一 Zookeeper
1. Zookeeper简介
Zookeeper是Hadoop下的一个子项目,它是一个针对大型分布式系统的可靠的协调系统,提供的功能包括
配置维护、名字服务、分布式同步、组服务等。
Zookeeper的设计初衷是作为分布式的协同服务,所以做注册中心其实是一个错误,它注重的是AP
2. Zab协议的两阶段选举
集群间通过Zab协议来保持数据的一致性。该协议包括两个阶段:leader election阶段和Atomic broadcas阶
段。leader election阶段,集群中将选举一个出一个leader,其它机器称为follower,所有写操作都被传送给
leader,并通过broadcas将所有更新告诉follower,当leader崩溃或是leader失去大多数follower时,需要重新选
取一个新的leader,让所有服务器都恢复到一个正确的状态。当leader被选举出来且大多数服务器完成了和
leader的状态同步(状态同步是指数据同步)后,leader election的过程就结束了,将进入Atomic broadcas的过
程。
有空看看不同的介绍,有的地方叫两种服务:
https://www.jianshu.com/p/5dce97c9ba85
3. Zookeeper的节点类型
持久节点、持久有序、临时节点、临时有序节点(重点,Zookeeper的分布式锁使用的该节点类型)持久和
临时的概念一目了然,就不介绍了。
有序节点
假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;zookeeper提供了一个可选的
有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前
的子节点数量自动添加整数序号,也就是说如果是第一个创建的子节点,那么生成的子节点为
/lock/node-0000000000,下一个节点则为/lock/node-0000000001,依次类推。
临时节点
客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会自动删除该节点。
Zookeeper的事件通知机制
在读取数据时,我们可以同时对节点设置事件监听(也叫订阅),当节点数据或结构变化时,
zookeeper会通知订阅它的客户端。当前zookeeper有如下四种事件:
-- 节点创建;
-- 节点删除;
-- 节点数据修改;
-- 子节点变更。
"增删改子节点",这么去记忆
4. Zookeeper实现分布式锁
核心思想是“心跳+临时节点+通知”。
假设锁空间的根节点为/lock,zookeeper实现分布式锁的算法流程:
(1)客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为
/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。
(2)客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,
如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得
锁。
(3)执行业务代码;
(4)完成业务流程后,删除对应的子节点释放锁
注意:应该使用的临时节点而不是持久节点
步骤1中创建的临时节点能够保证在故障的情况下锁也能被释放,考虑这么个场景:假如客户
端a当前创建的子节点为序号最小的节点,获得锁之后客户端所在机器宕机了,客户端没有主动删
除子节点;如果创建的是永久的节点,那么这个锁永远不会释放,导致死锁;由于创建的是临时节
点,客户端宕机后,过了一定时间zookeeper没有收到客户端的心跳包判断会话失效,将临时节点
删除从而释放锁;
扩展:zookeeper提供的API中设置监听器的操作(读子节点列表时同时设置监听器)与读操作是原子执行
的。
考虑这么个场景,客户端a对应子节点为/lock/lock-0000000000,客户端b对应子节点为
/lock/lock-0000000001,客户端b获取子节点列表时发现自己不是序号最小的,但是在设置监听器
前客户端a完成业务流程删除了子节点 /lock/lock-0000000000,客户端b设置的监听器岂不是丢失了
这个事件从而导致永远等待了?这个问题不存在的。因为zookeeper提供的API中设置监听器的操作
与读操作是原子执行的,也就是说在读子节点列表时同时设置监听器,保证不会丢失事件。
扩展:Zookeeper的临时节点和持久节点
持久节点(PERSISENT):一旦创建,除非主动调用删除操作,否则一直存储在zk上;
临时节点(EPHEMERAL):与客户端会话绑定,一旦客户端会话失效,这个客户端所创建的所有临
时节点都会被移除;
5. Zookeeper作为dubbo注册中心的原理
简单的说是(心跳+临时节点+通知)
在zookeeper中,进行服务注册,实际上就是在zookeeper中创建了一个znode节点,该节点存储了该服务
的IP、端口、调用方式(协议、序列化方式)等。该节点承担着最重要的职责,它由服务提供者(发布服务时)创建,
以供服务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及得知如何调用。RPC服务注
册、发现过程简述如下:
(1)服务提供者启动时,会将其服务名称,ip地址注册到配置中心。服务消费者在第一次调用服务时,会通过注
册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求
注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
注意:这里的客户端缓存根据Zookeeper的节点的更新而自动更新是应该是dubbo实现的。
(2)当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新
的服务IP地址列表发送给服务消费者机器,缓存在消费者本机,当某个服务的所有服务器都下线了,那么这
个服务也就下线了(服务提供方可以根据服务消费者的数量来作为服务下线的依据感知服务的);同样,
当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费
者本机。
下线&上线
zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket
长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除,比如100.19.20.02这
台机器如果宕机了,那么zookeeper上的路径就会只剩 /HelloWorldService/1.0.0/100.19.20.01:16888。服务消
费者会去监听相应路径(/HelloWorldService/1.0.0),一旦路径上的数据有任务变化(增加或减少),
zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。更为重要的是zookeeper
与生俱来的容错容灾能力(比如leader选举),可以确保服务注册表的高可用性。使用 zookeeper 作为注册中
心时,客户端订阅服务时会向 zookeeper 注册自身;主要是方便对调用方进行统计、管理。但订阅时是否注册
client 不是必要行为,和不同的注册中心实现有关,例如使用 consul 时便没有注册。
6. Zookeeper和Eureka比较
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直
接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当
master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间
太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,
因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导
致的注册长期不可用是不能容忍的;由于它不能很好的处理网络分区的问题,所以会导致一些客户端状态会丢失
(如果在同一个网络分区(partition)的节点数(nodes)数达不到ZooKeeper选取Leader节点的“法定人数”时,它
们就会从ZooKeeper中断开,当然同时也就不能提供Service发现服务了,导致连接到这些节点的客户端状态丢失)。
Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会
影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或如果
发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过
查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过
85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
(1)Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
(2)Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
(3)当网络稳定时,当前实例新的注册信息会被同步到其它节点中。
扩展1:Zookeeper做服务发现就是个错误
-- 因为相对于CP,更能接受的是AP
-- ZooKeeper本身并没有正确的处理网络分割的问题 在ZooKeeper中,如果在同一个网络分区(partition)
的节点数(nodes)数达不到ZooKeeper选取Leader节点的“法定人数”时,它们就会从ZooKeeper中断
开,当然同时也就不能提供Service发现服务了,导致连接到这些节点的客户端状态丢失。Pinterest与
Airbnb公司通过增加客户端缓存的方案来解决该问题,但是这种方式只是从表面上解决这个问题,因为
当部分或者所有节点跟ZooKeeper断开的情况下,每个节点还可以从本地缓存中获取到数据并不一定是
所有的服务注册信息,所引这导致我们并不能得到一个CP的系统也不能得到一个AP的系统。
扩展2:Zookeeper为什么实现CP
ZooKeeper是Hadoop的一个子项目,旨在解决大规模分布式应用场景下,服务协调同步
(Coordinate Service)的问题。ZooKeeper是分布式协调服务,它的职责是保证数据(注:配置数据,
状态数据)在其管辖下的所有服务之间保持同步、一致,所以就不难理解为什么ZooKeeper被设计成CP而
不是AP特性的了,如果是AP的,那么将会带来恐怖的后果。
https://my.oschina.net/thinwonton/blog/1622905
zookeeper使用场景:https://blog.csdn.net/he90227/article/details/70157046
7. ACL
Zkeeper本身提供了ACL机制,表示为scheme:id:permissions,第一个字段表示采用哪一种身份认证机制,第
二个id表示用户,permissions表示相关权限(如只读,读写,管理等)。
scheme有如下几种:
world:默认方式,相当于全世界都能访问。
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)。
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。
ip:使用Ip地址认证
permissions:代表ZK中的操作权限,有如5种:CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、
改、查、管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)
注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限。
设置访问控制:
方式一:(推荐)
* 增加一个认证用户
addauth digest 用户名:密码明文
eg. addauth digest user1:password1
* 设置权限
setAcl /path auth:用户名:密码明文:权限
eg. setAcl /test auth:user1:password1:cdrwa
* 查看Acl设置
getAcl /path
方式二:
* setAcl /path digest:用户名:密码密文:权限
注:这里的加密规则是SHA1加密,然后base64编码。
二 dubbo
1. Rpc介绍
一个完整的RPC架构里面包含了四个核心的组件,分别是Client、Server、Client Stub以及Server Stub。
客户端(Client):服务的调用方。
服务端(Server):真正的服务提供者。
客户端存根(Client Stub):存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过
网络远程发送给服务方。
服务端存根(Server Stub):接收客户端发送过来的消息,将消息解包,并调用本地的方法。
一次Rpc调用大约分10次
(1)服务消费方(client)调用以本地调用方式调用服务;
(2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
(3)client stub找到服务地址,并将消息发送到服务端;
(4)server stub收到消息后进行解码;
(5)server stub根据解码结果调用本地的服务;
(6)本地服务执行并将结果返回给server stub;
(7)server stub将返回结果打包成消息并发送至消费方;
(8)client stub接收到消息,并进行解码;
(9)服务消费方得到最终结果。
扩展知识:Rmi的嗲用过程(平时不用看,闲的蛋疼的时候在看)
(1)客户调用客户端辅助对象stub上的方法
(2)客户端辅助对象stub打包调用信息(变量,方法名),通过网络发送给服务端辅助对象skeleton
(3)服务端辅助对象skeleton将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所
在对象
(4)调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象skeleton
(5)服务端辅助对象将结果打包,发送给客户端辅助对象stub
(6)客户端辅助对象将返回值解包,返回给调用者
(7)客户获得返回值
2. Rpc和Rmi
看原文
3. Rpc和http看原文
4. Socket
看原文
5. 注册中心
(1)为什么要使用注册中心
分布式服务框架部署在多台不同的机器上,例如服务提供者在集群A,服务调用者在集群B,那么B在
调用A的服务的过程中,集群A的机器需要和集群B的机器进行通信。那么会出现如下问题:
-- 集群A的服务调用者如何发现集群B的服务提供者
-- 集群A的服务调用者如何选择集群B中的某一台服务提供者机器发起调用
-- 集群B的服务提供者机器上/下线之后,集群A中调用者如何感知到这台机器的上/下线,不在对已下线的
机器发起调用。
-- 集群B提供的某个服务如何获知集群A中那些机器正在消费该服务。
以上问题将通过服务注册中心来解决,采用服务注册中心来实时存储更新服务提供者信息及该服务的实时
调用者信息。
(2)注册中心的工作过程如下
-- 在服务启动的时候,将服务提供者信息主动上报到服务注册中心进行服务注册
-- 服务调用者启动的时候,将服务提供者信息从注册中心下拉到服务调用者机器本地缓存,服务调用者从
本地缓存的服务提供者列表中,基于某种负载均衡策略选择一台服务提供者发起远程调用。
-- 服务注册中心能够感知服务提供者集群中某一台机器下线,将该机器服务提供者信息从注册中心删除,
并且通知服务调用者集群中的每一台机器,是的服务调用者不在调用该机器。
(3)服务注册中心的功能,属于概念性东西,大概看看就行了,关键是能用自己的话说出来服务注册中心的
功能
注册中心其实充当是服务的协调者,一般包含如下几个功能:
-- 服务发现
* 服务注册/反注册:保存服务提供者和服务调用者的信息
* 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
* 服务路由(可选):具有筛选整合服务提供者的能力。
-- 服务配置(不包括其它无关配置):
* 配置订阅:服务提供者和服务调用者订阅微服务相关的配置
* 配置下发(可选):主动将配置推送给服务提供者和服务调用者
-- 服务健康检测
检测服务提供者的健康情况
(4)注册中心的优点,属于概念性东西,大概看看就行了,关键是能用自己的话说出来服务注册中心的功能
-- 服务发现:
* 服务注册/反注册:保存服务提供者和服务调用者的信息
* 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
* 服务路由(可选):具有筛选整合服务提供者的能力。
-- 服务配置(不包括其它无关配置):
* 配置订阅:服务提供者和服务调用者订阅微服务相关的配置
* 配置下发(可选):主动将配置推送给服务提供者和服务调用者
-- 服务健康检测
* 检测服务提供者的健康情况
5. dubbo和WebService
(1)WebService
-- 效率不高基于soap协议,其主要的特点是跨语言、跨平台的。项目中不推荐使用,可用于不同公司
间接口的调用。
-- 若使用restful形式的服务:http+json。很多项目中应用。如果服务太多,服务之间调用关系混乱,需
要治疗服务。
(2)使用dubbo。使用rpc协议进行远程调用,直接使用socket通信。传输效率高,并且可以统计出系统之间
的调用关系、调用次数。使用Java语言开发,只能用于Java语言开发的项目间的通信,不具备跨语言,
跨平台的特点。
(3)WebService是什么鬼
https://blog.csdn.net/u013168253/article/details/79695492
5. dubbo原理
(1)注册中心
注册中心和每个Server/Client之间会作一个实时的心跳检测(因为它们都是建立的Socket长连接,该功能
由Zookeeper实现),比如几秒钟检测一次。收集每个Server提供的服务的信息,每个Client的信息,整
理出一个服务列表,如:
serviceName | serverAddressList | clientAddressList |
UserService | 192.168.0.1,192.168.0.2,192.168.0.3,192.168.0.4 | 172.16.0.1,172.16.0.2 |
ProductService | 192.168.0.3,192.168.0.4,192.168.0.5,192.168.0.6 | 172.16.0.2,172.16.0.3 |
OrderService | 192.168.0.10,192.168.0.12,192.168.0.5,192.168.0.6 | 172.16.0.3,172.16.0.4 |
当某个Server不可用,那么就更新受影响的服务对应的serverAddressList,即把这个
Server从serverAddressList中剔除出去(从地址列表中删除),同时将推送serverAddressList给这些受
影响的服务的clientAddressList里面的所有Client。如:192.168.0.3挂了,那么UserService和
ProductService的serverAddressList都要把192.168.0.3删除掉,同时把新的列表告诉对应的Client:
172.16.0.1,172.16.0.2,172.16.0.3;当某个Client挂了,那么更新受影响的服务对应的clientAddressList
ConfigServer根据服务列表,就能提供一个web管理界面,来查看管理服务的提供者和使用者。新加一个
Server时,由于它会主动与ConfigServer取得联系,而ConfigServer又会将这个信息主动发送给Client,
所以新加一个Server时,只需要启动Server,然后几秒钟内,Client就会使用上它提供的服务。
dubbo与zookeeper的交互过程:https://blog.csdn.net/qq_27529917/article/details/80632078
(2)client
调用服务的机器,每个Client启动时,主动与ConfigServer建立Socket长连接,并将自己的IP等相
应信息发送给ConfigServer。Client在使用服务的时候根据服务名称去ConfigServer中获取服务提供者
信息(这样ConfigServer就知道某个服务是当前哪几个Client在使用),Client拿到这些服务提供者信息
后,与它们都建立连接,后面就可以直接调用服务了,当有多个服务提供者的时候,Client根据一定的
规则来进行负载均衡,如轮询,随机,按权重等。一旦Client使用的服务它对应的服务提供者有变化(
服务提供者有新增,删除的情况),ConfigServer就会把最新的服务提供者列表推送给Client,Client就
会依据最新的服务提供者列表重新建立连接,新增的提供者建立连接,删除的提供者丢弃连接。
(3)Server
真正提供服务的机器,每个Server启动时,主动与ConfigServer建立Scoket长连接,并将自己的IP,
提供的服务名称,端口等信息直接发送给ConfigServer, ConfigServer就会收集到每个Server提供的服
务的信息。
6. dubbo的功能讲解
(1)常规用法,Hello World例子
生产者
IDemoService.java
package com.baizhi.service; public interface IDemoService { /** * 求和 * @param x * @param y * @return */ public int sum(Integer x ,Integer y); /** * 计算连个数的乘积 * @param x * @param y * @return */ public int multi(Integer x ,Integer y); }
DemoService_v1.java
package com.baizhi.service.impl; import com.baizhi.service.IDemoService; public class DemoService_v1 implements IDemoService { public int sum(Integer x, Integer y) { // TODO Auto-generated method stub return x+y; } public int multi(Integer x, Integer y) { // TODO Auto-generated method stub return x*y; } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 配置Bean --> <bean id="demoService" class="com.baizhi.service.impl.DemoService_v1"/> <!-- 引入配置文件 --> <import resource="classpath:dubbo.xml"/> </beans>
dubbo.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 指定web服务名字。建议该名称和你的应用名保持一致,该名称可以用来搞路由--> <dubbo:application name="Dubbo_HelloWorld"/> <!-- 声明服务注册中心 --> <dubbo:registry protocol="zookeeper" address="192.168.1.122:2181"/> <!-- 指定传输层通信协议 --> <dubbo:protocol name="dubbo" port="20880"/> <!-- 暴露服务。把自己的接口注册到zookeeper; 通过ref自定服务的实现--> <dubbo:service interface="com.baizhi.service.IDemoService" protocol="dubbo" ref="demoService" /> </beans>
消费者
DubboUseage.java
import java.io.IOException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.expression.spel.ast.Identifier; import com.baizhi.service.IDemoService; public class DubboUseage { public static void main(String[] args) throws IOException { ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); IDemoService demoService=(IDemoService) ctx.getBean("demoService"); //此处可以发现打印的是代理类型 底层dubbo使用NIO的RCP做远程调度 System.out.println("打印引用类型:"+demoService.getClass()); //测试远程方法调度 int sum=demoService.sum(1, 3); System.out.println("和:"+sum); } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 引入配置文件 --> <import resource="classpath:dubbo.xml"/> </beans>
dubbo.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 指定web服务名字 --> <dubbo:application name="Dubbo_HelloWorld_ref"/> <!-- 声明服务注册中心 --> <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/> <!-- 指定传输层通信协议 因为在同一台机器测试,所以端口不一样--> <dubbo:protocol name="dubbo" port="20881"/> <!-- 引用服务,interface指定具体引用的服务,因为具体在zookeeper里暴露的服务就是com.baizhi.service.IDemoService--> <dubbo:reference id="demoService" interface="com.baizhi.service.IDemoService" protocol="dubbo" /> </beans>
到此为止,老师说dubbo已经讲完了
(2)启动时检查
启动时检查
check="true/false"
check=“true”:启动时检查它所依赖的服务是否可用,如果不可用会报错。报的是个spring的错,具体是
啥没看到。
check="false":启动时不检查它所依赖的服务是否可用,只管自己启动
(3)集群容错
集群容错是指我们在一个服务下暴露多个provider,任何一个provider宕机式,服务。依然正常工作。
不用配,默认就支持,dubbo天然就是一个集群模式。需要我们配置的是集群容错模式,集群容错模式
可以配在客户端也可以配在服务端(个人感觉配置在哪端都没有区别)。dubbo支持以下几种集群容错
模式:
-- Failover Cluster
失败自动切换,当出现失败,重试其它服务器(默认)。通过reetries参数用来设置重试次数(不含第
一次),设置reetries=0,表示不重试
* 通常用来读操作,但重试会带来更长延迟。
* 用于写操作的时候应该注意因为网络延时造成重复写的问题。如下图,当消费端访问服务A后,服务
A开始执行,但是因为网络故障消费端无法接到A的响应,消费端就认为是失败,所以消费端又尝试
请求服务B,这就造成重复写的问题。
示例:
<dubbo:service retries="2" /> 或 <dubbo:referenceretries="2" /> 或 <dubbo:reference><dubbo:methodname="findFoo" retries="2" /></dubbo:reference>
-- Failfast Cluster
快速失败(只发起一次调用),抛出异常。通常用于非幂等性的写操作,比如新增记录。
示例:
<dubbo:service cluster="failfast" /> 或 <dubbo:referencecluster="failfast" />
-- Failsafe Cluster
快速失败(只发起一次调用),不抛出异常 。通常用于写入审计日志等操作
示例:
<dubbo:service cluster="failsafe" /> 或 <dubbo:referencecluster="failsafe" />
-- Failback Cluster
失败后定时重试。通常用于新消息通知操作。
<dubbo:service cluster="failback" /> 或 <dubbo:referencecluster="failback" />
-- Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服
务器资源,可通过forks="2"来设置最大并行数。
-- Broadcast Cluster (2.10开始支持)
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所
有提供者更新缓存或日志等本地资源信息。
(2)负载均衡
dubbo的负载均衡机制可以写在代码里(服务端和客户端)也可以通过管控台配置,但是推荐通过管控台配
置,这样更改里规则不需要重启服务。dubbo支持如下几种负载均衡机制:
-- Random LoadBalance:随机,按权重设置随机概率,在一个截面上碰撞概率高,但调用量越大分布越均匀,
二期按概率使用,权重也比较均匀,有利于动态调整提供者权重。
-- RandomRobin LoadBalance:轮询,按公约后的权重设置轮询比率,存在小量提供者累计请求的问题,比如
第二台集器很慢但没挂,当请求调到第二台机器就卡在那,久而久之所有请求
都卡在调用第二台机器上。
-- LeastActive LoadBalance:最少活跃调用数,相同活跃随机,活跃数指调用前后计数差,使慢的提供者收到
更少的请求,因为越慢的提供者前后计数差越大。
-- ConsistentHash LoadBalancee:一致性Hash,相同参数的请求总是发到同一提供者。当某一台机器挂时,原
本发往该提供者的请求,基于下虚拟节点,平摊到其它提供者,不会引起剧烈
变动。剩下自己百度吧,很少用,因为管控台里没有。
示例(这里只写了一个,其它的差不多):
服务端服务级别
<!--服务端服务级别--> <dubbo:service interface="..." loadbalance="roundrobin" /> <!--服务端方法级别--> <dubbo:service interface="..."> <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:service> <!--客户端服务级别--> <dubbo:reference interface="..." loadbalance="roundrobin" /> <!--客户端端方法级别--> <dubbo:reference interface="..."> <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:reference>