来个总结吧
集群模式部署
分支主题
一般奇数节点,因为你5台机器可以挂2台,6台机器也是挂2台,不能超过一半的机器挂掉,所以5台和6台效果一致,那奇数节点可以减少机器开销,小集群部署,读多写少
分支主题
主从架构:Leader、Follower、Observer(一般刚开始没必要用)
分支主题
内存数据模型:znode,多种节点类型
分支主题
客户端跟zk进行长连接,TCP,心跳,维持session
分支主题
zxid,高32位,低32位
分支主题
ZAB协议,2PC,过半ack + 磁盘日志写,commit + 写内存数据结构
分支主题
支持Watcher机制,监听回调通知
分支主题
顺序一致性:消息按顺序同步,但是最终才会一致,不是强一致
分支主题
高性能,2PC中的过半写机制,纯内存的数据结构,znode
分支主题
高可用,follower宕机没影响,leader宕机有数据不一致问题,新选举的leader会自动处理,正常运行,但是在恢复模式期间,可能有一小段时间是没法写入zk的
分支主题
高并发,单机leader写,Observer可以线性扩展读QPS
应用场景
元数据管理
Kafka、Canal,本身都是分布式架构,分布式集群在运行,本身他需要一个地方集中式的存储和管理分布式集群的核心元数据,所以他们都选择把核心元数据放在zookeeper中的
分布式协调
监听并作出响应,比如有一个数据,一个broker注册了一个数据,其他broker监听这个数据
总结:
分布式协调系统,封装了分布式架构中所有核心和主流的需求和功能,分布式锁、分布式集群的集中式元数据存储、Master选举、分布式协调和通知
特点
集群部署:3~5台机器组成一个集群
每台机器都在内存保存了zk的全部数据,机器之间互相通信同步数据,客户端连接任何一台机器都可以
树形结构的数据模型:znode,树形结构,数据模型简单,纯内存保存
顺序一致性:集群中只有一台机器可以写,所有机器都可以读,所有写请求都会分配一个zk集群全局的唯一递增编号
zxid,保证各种客户端发起的写请求都是有顺序的
原子性:要么全部机器都成功,要么全部机器都别成功
数据一致性:任何一台zk机器收到了写请求之后都会同步给其他机器,保证数据的强一致,你连接到任何一台zk机器看到的数据都是一致的
高可用:哪怕集群中挂掉不超过一半的机器,都能保证可用,数据不会丢失
3台机器可以挂1台,5台机器可以挂2台
高性能:每台zk机器都在内存维护数据,所以zk集群绝对是高并发高性能的
如果你让zk部署在高配置物理机上,一个3台机器的zk集群抗下每秒几万请求没有问题
高并发:高性能决定的,只要基于纯内存数据结构来处理,并发能力是很高的
只有一台机器进行写,但是高配置的物理机,比如16核32G,写入几万QPS
读,所有机器都可以读,3台机器的话,起码可以支撑十几万QPS
实时性:一旦数据发生变更,其他人要实时感知到
watcher监听机制
集群架构
角色划分
Observer
只读,写请求转发到Leader
不参与选举
也不参与ZAB返回ack那个环节,只接受数据,可能存在数据不一致的问题
客户端通信
通过TCP建立长连接,维护session
定时发送心跳
客户端宕机时,在sessionTimeout时间内重新发送心跳会继续维持长连接
Watcher监听机制
客户端对zookeeper znode节点进行监听,然后改变的时候通知客户端
监听数据变化,更新数据,反向通知
ZAB协议
Zookeeper Atomic Broadcast
即zookeeper原子广播协议
角色划分
划分集群角色,主从架构,分为Leader和Follower ,只有leader接受写入请求
2PC(两阶段提交)
Leader接收到写请求,先写入磁盘文件,并向Follower发送事务proposal的广播
Follower接到proposal写入磁盘文件,然后向Leader返回ACK
等待Leader发送commit写入znode
过半写
超过半数的Follower返回ACK消息,Leader将数据写入znode,并发送commit消息通知Follower写入
commit之后这个数据就能被读到了
顺序性保证
在发起一个事务proposal之前,会生成一个自增的全局zxid,通过这个保证顺序性
Leader会为没给Follower创建一个队列,里面放要发送的事务proposal,保证了同步的顺序性
启动与崩溃恢复
启动
恢复模式
选举出一个Leader (过半Follower认可即成为Leader)
跟Follower进行数据同步
完成后退出恢复模式,进入消息广播模式
对外提供服务
消息写入
消息广播机制 + Leader采用2PC模式的过半写机制,给Follower进行同步
崩溃恢复
恢复模式
Leader/Follower宕机
只要集群宕机的机器不超过一半
就可以重新进行选举出Leader,进行数据同步
强一致性or最终一致性?
强一致性:
只要写入一条消息,立马无论从那个zk节点都可以查到数据
写入操作卡主,知道所有的follower返回ack,leader执行commit之后,从所有节点都能读到数据
很明显,根据ZAB协议,zk不是强一致性
最终一致性:
写入一条消息,方法返回,告诉你写入成功了
短暂时间内从其他节点可能查不到数据,不过等一会同步完成,肯定能查到数据
研究过ZAB协议就能发现,follower半数以上返回ack,然后leader发送commit以后就能读到数据了
那么就有一种可能,有的follower接收到commit了,可以读到,有的没接到commit,读不到
不过最后还是能读到的
zk官方自己的定义是:顺序一致性
它比最终一致性好些,因为leader可以保证所有的follower事务proposal都是按照顺序执行的,能保证顺序性
但是全部follower的数据一致确实是最终才能实现一致的
出去说要说是顺序一致性
如果要求强一致性,可以手动调用zk的sync()操作
ZAB协议下的一种可能存在的数据一致性问题
Leader自己commit了,还没给其他Follower发送commit消息就挂了
Follower重新选举出Leader
挑选已经收到zxid最大的那个Follower作为新的Leader
zxid大说明最近跟leader进行了数据同步
新的Leader发现自己有一条proposal没有commit,其他follower也有这个proposal,并且数量过半
会重新发送commit给其他Follower进行数据同步
确保数据不会丢失
Leader接收到写入请求,写入磁盘日志文件了,还没来得及个其他Follower发送事务proposal就挂了
它重新启动后跟Leader进行数据同步时,发现自己有一条没有commit的事务proposal
zxid是64位的,高32位存放leader的版本号epoch,低32位主键自增
新的leader的epoch 自增
Leader没有,说明是它自己宕机前的脏数据
直接丢弃掉,从新Leader同步最新的数据
所谓commit就是把这条数据加到内存的znode树上去,然后就对外可见了,也会通知一些监听这个znode的人