分为两大类
RuntimeException: I/O导致的IOException、SQLException
CheckedException: try/catch 可捕获的
根据 Spring Cloud 的官方网站, Spring Cloud 为开发人员提供了快速构建分布 式系统中一些常见模式的工具( 例如配置管理, 服务发现, 断路器, 智能路由, 领导选举, 分布式会话, 集群状态)。
在使用 Spring Boot 开发分布式微服务时,我们面临的问题很少由 Spring Cloud 解决。
在使用 Spring Boot 开发分布式微服务时,我们面临的问题很少由 Spring Cloud 解决。
与分布式系统相关的复杂性 – 包括网络问题,延迟开销,带宽问题,安 全问题。
处理服务发现的能力 – 服务发现允许集群中的进程和服务找到彼此并进 行通信。
解决冗余问题 – 冗余问题经常发生在分布式系统中。
负载平衡 – 改进跨多个计算资源(例如计算机集群,网络链接,中央处 理单元)的工作负载分布。
减少性能问题 – 减少因各种操作开销导致的性能问题。
回答思路:访问者模式是一种分离对象数据结构与行为的方法,通过这种分离,可以为一个已存在的类增加新的操作而无须为它们进行修改,在spring中就有对这个设计模式的实现案例,在java中我们会通过注解@Value通过占位符对类中的属性赋值,而且是解析的Properties 文件中的值映射到类的成员变量上,只需要修改Properties文件。在spring中每个对象都会被解析成BeanDefinition ,然后访问者模式中,会用Spring 的 BeanDefinitionVisitor 用来访问 BeanDefinition,访问的具体调用就是BeanDefinitionVisitor.visitBeanDefinition(bd);封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。于要更新的表有状态字段,并且刚好要更新状态字段的这种特殊情况,并非所有场景都适用。
高手回答:
java根据其生命周期的长短又将引用类型分为强引用、软引用、弱引用、虚引用;
强引用:new一个对象就是强引用,例如 Object obj = new Object();当JVM的内存空间不足时,宁愿抛出OutOfMemoryError使得程序异常终止也不愿意回收具有强引用的存活着的对象;
软引用的生命周期比强引用短一些。软引用是通过SoftReference类实现的。当JVM认为内存空间不足时,就会去试图回收软引用指向的对象;软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收! 这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
弱引用是通过WeakReference类实现的,它的生命周期比软引用还要短。在GC的时候,不管内存空间足不足都会回收这个对象,也同样适用于内存敏感的缓存。如果一个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么应该用 Weak Reference 来记住此对象。或者想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候就应该用弱引用,这个引用不会在对象的垃圾回收判断中产生任何附加的影响。
虚引用,是通过PhantomReference类实现的。任何时候可能被GC回收,就像没有引用一样;无法通过虚引用访问对象的任何属性或者函数。虚引用仅仅只是提供了一种确保对象被finalize以后来做某些事情的机制
高手回答:
对象在内存中的存储的布局可以分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding);对象头由 Markword + 类指针kclass(该指针指向该类型在方法区的元类型) 组成;普通对象头在32位系统上占用8bytes,64位系统上占用16bytes。64位机器上,数组对象的对象头占用24个字节,启用压缩之后占用16个字节。
MarkWord用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。在64位的虚拟机(未开启压缩指针)为64bit。
kclass存储的是该对象所属的类在方法区的地址,所以是一个指针,默认Jvm对指针进行了压缩,用4个字节存储,如果不压缩就是8个字节。 关于Compressed Oops的知识,大家可以自行查阅相关资料来加深理解。
实例数据部分就是成员变量的值,其中包含父类的成员变量和本类的成员变量。也就是说,除去静态变量和常量值放在方法区,非静态变量的值是随着对象存储在堆中的。
用于确保对象的总长度为8字节的整数倍。HotSpot要求对象的总长度必须是8字节的整数倍。由于对象头一定是8字节的整数倍,但实例数据部分的长度是任意的。因此需要对齐补充字段确保整个对象的总长度为8的整数倍。
高手回答:
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。采用的是"标记-清除算法",整个过程分为4步;
(1)初始标记,标记GC Roots能直接关联到的对象 Stop The World-- ->速度很快
(2)并发标记,就是从GC Roots开始找到它能引用的所有其它对象的过程
(3)重新标记,Stop The World 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间要短。
(4)并发清除,在整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,因此,从总体上看,CMS收集器的内存回收过程是与用户线程一起并发执行的。
G1收集器的工作过程也可以分为四步:
初始标记、并发标记、最终标记跟CMS的前三步基本一致;
筛选回收,对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划
参考思路:过scop注解来控制,在scop注解中包含4个选项,分别为:
@Scope(“prototype”):多实例,IOC容器启动创建的时候,并不会创建对象放在容器在容器当中,当你需要的时候,需要从容器当中取该对象的时候,就会创建
@Scope(“singleton”):单实例 IOC容器启动的时候就会调用方法创建对象,以后每次获取都是从容器当中拿同一个对象
@Scope(“request”):同一个请求创建一个实例
@Scope(“session”):同一个session创建一个实例
参考思路:限流算法常用的几种实现方式有如下四种:计数器、滑动窗口、漏桶和令牌桶;
● 计数器:
○ 思想:在固定时间窗口内对请求进行计数,与阀值进行比较判断是否需要限流,一旦到了时间临界点,将计数器清零。
○ 问题:计数器算法存在“时间临界点”缺陷。比如每一分钟限制100个请求,可以在00:00:00-00:00:58秒里面都没有请求,在00:00:59瞬间发送100个请求,这个对于计数器算法来是允许的,然后在00:01:00再次发送100个请求,意味着在短短1s内发送了200个请求,如果量更大呢,系统可能会承受不住瞬间流量,导致系统崩溃
● 滑动窗口:
○ 思想:滑动窗口算法将一个大的时间窗口分成多个小窗口,每次大窗口向后滑动一个小窗口,并保证大的窗口内流量不会超出最大值,这种实现比固定窗口的流量曲线更加平滑。
○ 问题:没有根本解决固定窗口算法的临界突发流量问题
● 漏桶:
○ 思想:漏桶算法是首先想象有一个木桶,桶的容量是固定的。当有请求到来时先放到木桶中,处理请求的worker以固定的速度从木桶中取出请求进行相应。如果木桶已经满了,直接返回请求频率超限的错误码或者页面
○ 适用场景:漏桶算法是流量最均匀的限流实现方式,一般用于流量“整形”。例如保护数据库的限流,先把对数据库的访问加入到木桶中,worker再以db能够承受的qps从木桶中取出请求,去访问数据库。
○ 问题:木桶流入请求的速率是不固定的,但是流出的速率是恒定的。这样的话能保护系统资源不被打满,但是面对突发流量时会有大量请求失败,不适合电商抢购和微博出现热点事件等场景的限流。
● 令牌桶:
○ 思想:令牌桶是反向的"漏桶",它是以恒定的速度往木桶里加入令牌,木桶满了则不再加入令牌。服务收到请求时尝试从木桶中取出一个令牌,如果能够得到令牌则继续执行后续的业务逻辑。如果没有得到令牌,直接返回访问频率超限的错误码或页面等,不继续执行后续的业务逻辑。
○ 适用场景:适合电商抢购或者微博出现热点事件这种场景,因为在限流的同时可以应对一定的突发流量。如果采用漏桶那样的均匀速度处理请求的算法,在发生热点时间的时候,会造成大量的用户无法访问,对用户体验的损害比较大
回答思路:SpringBoot启动时通过执行main方法中的SpringApplication.run方法去启动的,在run方法中调用了SpringApplication的构造方法,在该构造方法中加载了META-INFA\spring.factories文件配置的ApplicationContextInitializer的实现类和ApplicationListenerr的实现类,ApplicationContextInitializer 这个类当springboot上下文Context初始化完成后会调用。ApplicationListener当springboot启动时事件change后都会触发。
SpringApplication实例构造完之后会调用它的run方法,在run方法中作了以下几步重要操作:
高手回答:
synchronized是Java中的关键字,底层是JVM实现的一种同步锁,synchronized能同时保证可见性,原子性,有序性;
synchronized有三种方式来加锁,不同的修饰类型,代表锁的控制粒度:
● 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
● 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
● 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁
在 JDK 1.6之前,synchronized 还是一个重量级锁,是一个效率比较低下的锁,但是在JDK 1.6后,Jvm为了提高锁的获取与释放效率对(synchronized )进行了优化,引入了偏向锁和轻量级锁,从此以后锁的状态就有了四种(无锁、偏向锁、轻量级锁、重量级锁),并且四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,也就是说只能进行锁升级(从低级别到高级别),不能锁降级(高级别到低级别),意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
偏向锁:
当一个线程访问加了同步锁的代码块时,会在对象头中存储当前线程的ID,后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。而是直接比较对象头里面是否存储了指向当前线程的偏向锁。如果相等表示偏向锁是偏向于当前线程的,就不需要再尝试获得锁了,引入偏向锁是为了不存在线程竞争的情况下尽量减少不必要的加解锁。
轻量级锁:
当一个线程获取到该锁后,另一个线程也来获取该锁,这个线程并不会被直接阻塞,而是通过自旋来等待该锁被释放。自旋就是让线程执行一段无意义的循环。分为自适应自旋锁和固定次数自旋锁,前者是自旋次数位动态的,JVM通过之前这把锁的获得情况来自动的选择增加或者减少自旋次数直至阻塞。后者即固定次数自旋,超过则阻塞。
自旋锁设计的原因:Java的线程是映射到操作系统原生线程之上的,阻塞或唤醒线程要操作系统从用户态和核心态之间切换, 线程刚刚进入阻塞状态,这个锁就被其他线程释放了,则需要操作系统来唤醒,浪费资源。
重量级锁:由对象内置锁ObjectMonitor实现:
objectMonitor流程:
● 所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了对象锁的entry set区域(监控区)。
● 所有曾经获得过锁,但是由于其它必要条件不满足而需要wait的时候,线程就进入了对象锁的wait set区域(待授权区) 。
● 在wait set区域的线程获得Notify/notifyAll通知的时候,随机的一个Thread(Notify)或者是全部的Thread(NotifyALL)从对象锁的wait set区域进入了entry set中。
● 在当前拥有锁的线程释放掉锁的时候,处于该对象锁的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行。
高手回答:
AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.util.concurrent)下locks包内的一个类。它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列。底层实现的数据结构是一个双向链表。
AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。
答:●session在服务器端Cookie在客户端(浏览器)
●session 的运行依赖session id,而session id是存在cookie中的,也就是说,如果浏览器禁用了cookie , 同时session也会失效(但是可以通过其它方式实现,比如在url中传递session _id )
●session 可以放在文件.数据库、或内存中都可以。
●用户验证这种场合一般会用 session
●cookie不是很安全,别人可以分析存放在本地的COOKI E并进行COOKIE欺骗考虑到安全应当使用session.
●session会在一 定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE.
●单个cookie保存的数据不能超过4K ,很多浏览器都限制个站点最多保存20个cookie。
答:●sleep和wait
sleep是Thread类的方法
C wait是Object类的方法
●有什么区别
( sleep0方法(休眠)是线程类( Thread )的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会
( CPU )让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态)。
( wait()是Object类的方法,调用对象的wait0方法导致当前线程放弃对象的锁(线程皆停执行) ,进入对象的等待池
( wait pool) ,只有调用对象的notify(0方法(或ntifll()方法)时才能唤翟等待池中的线程进入等锁池( lockpool ) 如果线程重新获得对象的锁就可以进入就绪状态
答:volatile关键字的作用
保证内存的可见性
防止指令重排
注意:volatile并不保证原子性
内存可见性
ovolatile保证可见性的原理是在每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本。所以volatile关键字的作用之一就是保证变量修改的实时可见性。
当且仅当满足以下所有条件时,才应该使用volatile变量
对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
该变量没有包含在具有其他变量的不变式中。
volatile使用建议
在两个或者更多的线程需要访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,没必要使用volatile。
由于使用volatile用蔽掉了JMM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
volatile和synchronized区别
volatile不会进行加锁操作:
volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制。
volatile变量作用类似于同步变量读写操作:
从内存可见性的角度看,写入volatile变量相当于退出同步代码块,而读取volatile变量相当于进入同步代码块。
volatile不如synchronized安全:
在代码中如果过度依赖volatile变量来控制状态的可见性,通常会比使用锁的代码更脆弱,也更难以理解。仅当volatile变量能简化代码的实现以及对同步策路的验证时,才应该使用它。一般来说,用同步机制会更安全些。
volatile无法同时保证内存可见性和原则性:
加锁机制{即同步机制)既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性,原因是声明为volatile的简单变量如果当前值与该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:“count+ +"、 "count = count+1”。
答:1.使用top 定位到占用CPU高的进程PIDtop 指令通过ps aux | grep PID命令
2.获取线程信息,并找到占用CPU高的线程ps -mp 进程ID -o THREAD,tid,time | sort -rn
3.将需要的线程ID转换为16进制格式printf “%x\n” tid
4.打印线程的堆栈信息jstack pid |grep tid -A 30
MVCC:效果是建立一个快照,同一个事务无论查询多少次都是相同的数据
规则:
一个事务能看到的版本
第一次查询之前,已经提交的数据;
本事务的修改
一个事务不能看到的数据版本
在本事务第一次查询之后建立的事务
活跃的未提交事务的修改
| m_ids:列表当前活跃的事务 |min_trx_id 活跃事务中最小的m_id |max_trx_id 系统分配的下一个事务ID|create_trx_id生成视图的事务ID
判断规则:
连接层面
架构层面
优化查询
表结构和存储引擎的优化
B+树的特点
优势:
高手回答:
InnoDB索弓|的数据结构用的是B+树。为什么要用B+?
InnoDB索引肯定会有1个聚集索引,聚集索引默认是主键,、然后是非空的唯一索引, 最后是隐藏列rowid。
聚集索引的存储方式为叶子节点有完整的数据,而非叶子节点,只存有索引值。
那么每页存的数据也就更多,内存跟磁盘交互的单位为页。每页的数据越多,那么就能减少跟磁盘的交互次数,整体上提升速度。
同时,因为真实数据都在叶子节点,所以sq|语句的查询路径都是一样长。 查询稳定。
为什么不用二叉查找树?因为二叉树会有斜树的情况出现,会退化成链表,不够平衡。
为什么不用红黑树?同样的,路数比较少,深度会随着数据量的提升而提升。速度会越来越慢。同时也不够平衡。
B树跟B+最大的一个区别,B树每个节点都有真实数据,那么每页存的数据就越少,查询数
据跟磁盘的交互也就越多,同时,索弓|树的高度也就越高,查询的链路也会越长,整体查询会慢。还有每个节
点都有真实数据。查询数据就不稳定,有些在索引第-层就能查到,有些要查到
索引最后一层
答:主要区别:
MylSAM是非事务安全 型的,而InnoDB是 事务安全型的。
MylSAM锁的粒度是表级 ,而InnoDB支持行级锁定。
MylSAM支持全文类型索引,而InnoDB不支持全文索弓|。
MylSAM相对简单,所以在效率上要优于InnoDB ,小型应用可以考虑使用MyI5AM。
MylSAM表是保存成文件的形式,在跨平台的数据转移中使用My|5AM存储会省去不少的嘛烦。
0 InnoDB表比MyI5AM表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表( alter table tablenametype=innodb )。
●应用场景:
MylSAM管理非事务表。它提供高連存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MylSAM是更好的选择。
InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB ,这样可以提高多用户并发操作的性能。
答:●索引的特点
(可以加快数据库的检索連度
(降低数据库插入、修改删除等维护的連度
(只能创建在表上,不能创建到视图上
( 既可以直接创建又可以间接创建
(可以在优化隐藏中使用索弓|
(使用查询处理器执行5QL语句 ,在一个表上,- -次只能使用一个索引
●索引的优点
(创建唯一-性索引,保证数据库表中每一-行数据的唯- -性
( 大大加快数据的检索連度,这是创建索引的最主要的原因
(加連数据库表之 间的连接,特别是在实现数据的参考完整性方面特别有意义
(在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
(通过使用索引,可以在查询中使用优化隐藏器, 提高系统的性能
●索引的缺点
(创建索引和维护索引|要耗费时间,这种时间随着数据量的增而增加)
(索引需要占用物理空间,除了数据表占用数据空间之外,每-个索引还要占-定的物理空间,如果建立聚簇索引,那么需要的空间就会更大)
(当对表中的数据进行增加口、 删除和修改的时候,索引也需要维护,降低数据维护的連度)
●索引分类
(直接创建索弓|和间接创建索引)
(昔通索弓|和唯一-性索引)
(单个索引和复合索弓|)
( 聚簇索弓|和非聚簇索引)
●索引失效
(如果条件中有or ,即使其中有条件带索引也不会使用(这就是问什么尽量少使用or的原因)
(对于多列索引,不是使用的第一 部分,则不会使用索引
(like查询是以 %开头)
(如果列类型是字符串 , 那一定要在条件中使用引号弓起来,否则不会使用索弓|)
(如果mysq|估计使用全表扫秒比使用索弓|快,则不适用索引)
DAO接口即Mapper接口,接口的全限名就是映射文件中的namespace的值,接口的方法就是映射文件中statement的id值,接口中的参数就是传递给sql的参数
Mapper的工作原理:
JDK动态代理,MyBatis的运行时使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,将sql结果返回
在mybtis中对外提供了4大对象供开发者拦截,分别是
Excutor:查看mybatis的sql执行过程;
ParameterHandler修改他的参数;
ResultSetHandler拦截返回值;
StatementHandler进行分页
开发者自己定义一个类,实现Interceptor接口,实现intercept方法,在类上通过@Intercepts注解和@Signature选择拦截哪个类中的哪个方法,比如:@Intercepts(@Signature(type = ResultSetHandler.class, method = “handleResultSets”, args = Statement.class)),然后那自定义拦截器的类配置到mybatis的配置文件中。在加载mybatis的时候会去在执行到ResultSetHandler的时候生成拦截器器的链,后面去调用会走拦截器
数据脱敏我们就需要去拦截ResultSetHandler对象修改返回值,在这个里面可以去做数据脱敏处理,可以通过反射获取对象的属性,判断哪些字段需要进行脱敏处理,如果需要脱敏处理,直接通过filed.setAccessibe(true)暴力反问,修改属性值
参考思路:mybatis是通过对dao接口进行代理,在启动mybatis的时候,会去加载在mybtais配置文件中配置的mapper文件,mapper文件中的每个sql语句都封装成一个statement,然后通过mapper文件中的namespace去得到到接口然后给他生成代理的工厂类放入到map中,注入mapper接口类时从该map中拿出对接口代理的对象,在代理对象中的invoke方法中除了object的方法,其他的所有方法都直接去找到相应的statment,然后去执行sql语句;
Jdk动态代理的类必须要实现接口,并且不能是final修饰的类,方法不能是非public的方法,在生成代理类时快,只生成一个代理文件,生成的代理类回去实现目标类实现的接口,运行时通过反射调用目标类的方法,调用时慢,cglib是使用asm框架来生成代理类,目标类无须实现接口,生成的代理类会继承目标类,不能是final修饰的类,方法不能是非public,由于生成了几个类文件,所以生成时慢,之所以有几个类文件,因为cglib在生成代理类的同时,会为目标类的每个方法都生成一个相应的index,通过index直接定位到方法,直接调用,所以调用时快,在spring中会判断如果有接口就使用jdk代理,如果没有接口就使用cglib代理
三种编码方式?
key 可以分层
缓存穿透:一般的缓存系统都是按照key去查询,如果不存在对应的value,就会去数据库查找,一些恶意的请求会故意查询不存在的key,请求量很大,就会造成数据库压力
缓存雪崩:当缓存服务器重启,或者大量缓存在某一个时间段同时失效,会给后端数据库带来压力,导致崩溃
一般是出现在主从分离、读写分离的数据库
在从库有数据更新之后,将缓存中的数据也同步更新,当主库发生了数据更新之后,向缓存发出删除、淘汰这段时间写入的旧数据
答:Jedis 是 Redis 的 Java 实现的客户端, 其 API 提供了比较全面的 Redis 命令的支 持;Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单, 不支持字符串操作, 不支持排序、事务、管道、分区等 Redis 特性。Redisson 的宗旨是 促进使用者对 Redis 的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑 上
推荐使用Zookeeper作为注册中心,还可以使用redis等,但不推荐
基于zookeeper的临时节点原理
默认也是推荐使用netty框架,还有mina
推荐使用Hessian序列化,还有Dubbo、FastJson、java自带序列化
可以通过 dubbo:reference 中设置 mock=“return null”。mock 的值也可以修改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 “ 接口名称 +Mock” 后缀。然后在 Mock 类里实现自己的降级逻辑
配置层(Config):对外配置接口,以ServiceConfig和 ReferenceConfig 为中心。
服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub 和服务器端 Skeleton。
服务注册层(Registry):封装服务地址的注册与发现,以服务URL 为中心。
集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册 中心,以 Invoker 为中心。
监控层(Monitor):RPC调用次数和调用时间监控。
远程调用层(Protocol):封将RPC调用,以Invocation和Result
为中心,扩展接口为 Protocol、Invoker 和 Exporter。
信息交换层(Exchange):封装请求响应模式,同步转异步,以
Request 和 Response 为中心。
网络传输层(Transport):抽象mina和netty为统一接口,以
Message 为中心。
dubbo: 单一长连接和 NIO 异步通讯,适合大并发小数据量的服务 调用,以及消费者远大于提供者。传输协议 TCP,异步,Hessian 序 列化;
rmi:采用JDK标准的rmi协议实现,传输参数和返回参数对象需要 实现 Serializable 接口,使用 java 标准序列化机制,使用阻塞式短连 接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,
传输协议 TCP。 多个短连接,TCP 协议传输,同步传输,适用常规的 远程服务调用和 rmi 互操作。在依赖低版本的 Common-Collections 包,java 序列化存在安全漏洞;
webservice:基于WebService的远程调用协议,集成CXF实现, 提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输, 同步传输,适用系统集成和跨语言调用;
http:基于Http表单提交的远程调用协议,使用Spring的 HttpInvoke 实现。多个短连接,传输协议 HTTP,传入参数大小混 合,提供者个数多于消费者,需要给应用程序和浏览器 JS 调用;
hessian:集成Hessian服务,基于HTTP通讯,采用Servlet暴露 服务,Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服 务互操作。多个短连接,同步 HTTP 传输,Hessian 序列化,传入参 数较大,提供者大于消费者,提供者压力较大,可传文件;
memcache:基于memcached实现的RPC协议
redis:基于redis实现的RPC协议
主要就是如下 3 个核心功能:
Remoting:网络通信框架,提供对多种NIO框架抽象封装,包括 “同步转异步”和“请求-响应”模式的信息交换方式。
Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多 协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群 支持。
Registry:服务注册,基于注册中心目录服务,使服务消费方能动态 的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少 机器
ZAB协议是分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议
ZAB协议包含两种基本的模式:崩溃恢复和消息广播
当整个zookeeper集群刚刚启动或者Leader服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步后,退出恢复模式进入消息广播模式,Leader服务器开始接收客户端的事务请求生成事务提案来进行事务请求处理