赞
踩
问题一:数据同步问题
3台服务器都有数据库连接的配置文件,如果配置更改怎么保证每个节点的数据一致性?
问题二:任务执行顺序问题
三个服务都是相同的,怎么保证一个task任务只在一台服务器(一个节点)上执行?
问题三: master选举问题
如果其中一个服务器挂了,其他服务器如何发现并接替这个服务器正在执行的任务?
问题四:事务一致性问题
存在共享资源,对于这个集群每个节点的访问权限是公平的,那么如何保障互斥性、安全性(和多线程安全问题类似)?
CAP
由于分区容错是一定存在的,所以我们能够达到的状态只有两种 —> CP / AP
CAP理论仅适用于原子读写的Nosql场景,不适用于数据库系统
CAP理论并不适用于数据库事务 ,虽然XA事务可以保证数据库在分布式系统下的ACID特性,但是会带来性能方面的影响(用户能接受的请求响应时间大约5秒左右);
BASE
zookeeper是一个开源的分布式协调服务,也是分布式数据一致性的解决方案
数据的发布/订阅
配置中心 —> 集中式管理和数据的动态更新
负载均衡
dubbo利用了zookeeper机制实现负载均衡
命名服务
master选举
kafka、hadoop、hbase 等
分布式队列
分布式锁
角色解析
zookeeper集群, 包含三种角色: leader / follower /observer
Leader
Follower
Observer
集群角色关系图
集群配置
在zoo.cfg里面增加
peerType=observer
server.1=192.168.11.129:2181:3181:observer
server.2=192.168.11.131:2181:3181
server.3=192.168.11.135:2181:3181
server.id=host:port:port
id的取值范围: 1~255; 用id来标识该机器在集群中的机器序号
2181是zookeeper的端口; //3306
3181表示leader选举的端口
创建myid
在每一个服务器的dataDir目录下创建一个myid的文件,文件就一行数据,数据内容是每台机器对应的server ID的数字
启动zookeeper
sh zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
zookeeper客户端连接
sh zkCli.sh -server ip:port
zookeeper的数据模型和文件系统类似,每一个节点称为:znode,是zookeeper中的最小数据单元。
每一个znode上都可以保存数据和挂载子节点,从而构成一个层次化的属性结构。
节点特性:
同一节点下,子节点名称不能相同
NOT_CONNECTED —> CONNECTING —> CONNECTED —> CLOSED
zookeeper提供了分布式数据发布/订阅功能,zookeeper允许客户端向服务器注册一个watcher监听。当服务器端的节点触发指定事件的时候
会触发watcher。服务端会向客户端发送一个事件通知
watcher的通知是一次性,一旦触发一次通知后,该watcher就失效,如果需要永久监听,则需要反复注册(第三方框架封装了永久监听的功能)
如何注册事件机制 通过这三个操作来绑定事件 :getData、Exists、getChildren
zookeeper提供控制节点访问权限的功能,用于有效的保证zookeeper中数据的安全性
其特性如下:
ACL 权限控制,使用:schema:id :permission 来标识(权限方案、授权对象、授权什么),主要涵盖 3 个方面
Schema 是权限控制方案,分为四种:
授权对象ID是指,权限赋予的用户或者一个实体。它的值根据Schema的不同而不同
permission指具体权限,分为五种
命令举例
setAcl /node2 ip:192.168.100.1:cdrwa #设置IP:192.168.100.1 拥有所有权限
create /node10 data10 digest:hylexus:f4Myrgy6YlaWdo4lvv///2jgEDI=:crwad
```zookeeper的命令操作
创建节点
create [-s] [-e] path data acl
-s 表示节点是否有序
-e 表示是否为临时节点
默认情况下,是持久化节点
获得指定 path的信息
get path [watch]
修改节点 path对应的data
set path data [version] # version : 版本号,要么不写,要么和上一次查询出的版本号一致 (乐观锁的概念)
删除节点
delete path [version] # version : 版本号,要么不写,要么和上一次查询出的版本号一致 (乐观锁的概念)
cversion = 0 //子节点的版本号
aclVersion = 0 //表示acl的版本号,修改节点权限
dataVersion = 1 //表示的是当前节点数据的版本号
czxid=0x500000015 //节点被创建时的事务ID
mzxid=0x500000016 //节点最后一次被更新的事务ID
pzxid=0x500000015 //当前节点下的子节点最后一次被修改时的事务ID
ephemeralOwner = 0x0 //创建临时节点的时候,会有一个sessionId 。 该值存储的就是这个sessionid
dataLength = 3 //数据值长度
numChildren = 0 //子节点数
ctime = Sat Aug 05 20:48:26 CST 2017 //创建时间
mtime = Sat Aug 05 20:48:50 CST 2017 //修改时间
处理读请求
任意节点都可以去处理读请求不需要转发
写请求(事务请求)
会转发给Leader(改进版2pc,过半同意即可)
zkclient —>zookeeper原生api
jar包导入
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
API连接状态
事件类型
curator
是Netflix公司开源的zookeeper客户端,提供了各种应用场景的实现封装
curator中包含了两个重要模块
curator连接的重试策略
curator中有Leader选举、分布式锁、配置中心等各种实现
对于Leader选举提供了两套API
—> LeaderLatch //如果未抢先写入master节点则阻塞等待
—> LeaderSelector //通过写入临时有序节点后判定自己是否为最小节点的方式实现
另外一个zookeeper Java客户端
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.1.8</version>
</dependency>
原子消息广播协议,ZAB(Zookeeper AtomicBroadcast)协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性。
ZAB协议主要有两种模式
ZAB 协议的核心定义
消息广播的实现原理
消息广播存在于事务处理过程中(改良版本的2pc):
崩溃恢复
ZAB 协议的这个基于原子广播协议的消息广播过程,在正常情况下是没有任何问题的,但是一旦 Leader 节点崩溃,或者由于网络问题导致 Leader 服务器失去了过半的 Follower 节点的联系,那么就 会进入到崩溃恢复模式。
注: 网络问题可能是 leader 节点和 follower 节点之间产生了网络分区,那么此时的 leader 不再是合法的 leader 了
进入崩溃恢复模式后集群必须解决如下两个问题
已经被处理的消息不能丢失
正常情况: 当 leader 收到合法数量 follower 的 ACKs 后,就向各 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回成功。
异常情况: 如果在各个 follower 在收到 COMMIT 命令前Leader 就挂了,导致剩下的服务器并没有执行这条消息。
Leader 对事务消息发起 commit 操作,该消息在follower1 上执行了,但是 follower2 还没有收到 commit,Leader就已经挂了,而实际上客户端已经收到该事务消息处理成功的回执了。所以在 zab 协议下需要保证所有机器都要执行这个事务消息
。
被丢弃的消息不能再次出现
异常情况: 当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的。此时,之前挂了的 leader 重新启动并注册成了follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,需要将其删除。
如图:在集群正常运行过程中的某一个时刻,Leader节点先后广播P1,P2,C1,C2
其中当Leader服务器将消息P2提交后,就立即崩溃推出。这种情况下当崩溃的服务器再次连接的时候C1和C2事务将会被抛弃删除。
zookeeper 集群在处理事务性请求时是要发起follower投票的。
确保已经被leader 提交的事务 Proposal能够提交、同时丢弃已经被跳过的事务Proposal
重要概念
SID:服务器ID
用SID来唯一标识Zookeeper集群中的机器,每台机器都不能重复,和myid的值一致。
ZXID:事务ID
ZXID是一个事务ID,用来唯一标识一次服务器状态的变更。在某一个时刻,集群中每台机器的ZXID不一定都一致。ZXID由2部分组成总共 64 位,高 32 位是 epoch 编号 低 32 位是counter消息计数器;
epoch
可以理解为当前集群所处的年代或者周期,每个leader 就像皇帝,都有自己的年号,所以每次改朝换代,leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为follower 只听从当前年代的 leader 的命令。
counter
消息计数器,每接收到一条事务消息这个值就+1
示例
当处理事务请求时,会先生成一个事务ID(ZXID)如图,同一个Leader的统治下epoch是相同的,counter消息计数器随着事务的增加而递增,会按照请求顺序转发给Leader,并保存在一个FIFO队列中,这样就可以保证事务的顺序一致性。同时当这个Leader挂了,新选举出的Leader的epoch会+1,这样当这个节点再链接上来的时候,未处理的事务由于epoch过期了全部清除过期的事务。
zookeeper集群一般由2n+1台服务器组成(不包括observer)
选举算法
选举算法的关键参数
选举过程
服务器启动时的 leader 选举
每个节点启动的时候状态都是 LOOKING,处于观望状态,接下来就开始进行选主流程进行 Leader 选举,至少需要两台机器(具体原因前面已经讲过了),我们选取 3 台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器 Server1 启动时,它本身是无法进行和完成 Leader 选举,当第二台服务器 Server2 启动时,这个时候两台机器可以相互通信,每台机器都试图找到 Leader,于是进入 Leader 选举过程。选举过程如下:
运行过程中的 leader 选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。
Leader选举图例
zookeeper会定时把数据存储在磁盘上。
DataDir = 存储的是数据的快照,存储某一个时刻全量的内存数据内容
DataLogDir 存储事务日志 ( log.zxid )
查看事务日志的命令
java -cp :/zookeeper-3.4.10/lib/slf4j-api-1.6.1.jar:/zookeeper-3.4.10/zookeeper-3.4.10.jar org.apache.zookeeper.server.LogFormatter log.200000001
zookeeper.out //是Zookeeper的运行日志
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。