总结
集群模式部署
一般奇数节点,因为你5台机器可以挂2台,6台也是挂两台,不能超过一半的机器挂掉,所以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机器收到了写请求都会同步给其他机器,保证数据的强一致性,你连接到任何一台机器看到的数据都是一致的。
高可用:哪怕集群中挂掉不超过一半的机器,都能保证可用,数据不会丢失
3台机器可以挂掉一个,5台机器可以挂2台
高性能:每台zk机器都在内存维护数据,所以zk集群绝对是高并发高性能的
如果你让zk部署在高配置物理机上,一个3台机器的zk集群抗下每秒几万请求没问题
高并发:高性能决定的,只要基于纯内存数据结构来处理,并发能力是很高的
写:只有一台机器进行写,但是高配置的物理机,比如16C32G,写入几万QPS
读:所有机器都可以读,3台机器的话,起码可以支撑十几万QPS
实时性:一旦数据发生变更,其他人要实时感知到
watcher监听机制
集群架构
角色划分
Observer
只读,写请求转发到Leader
不可参与选举
也不参与zab返回ack那个环节,可能存在数据不一致的问题
客户端通信
通过tcp建立长连接,维护session
定时发送心跳
客户端宕机时,在sessionTimeout时间内重新发送心跳会继续维持长连接
内存数据模型
znode
Curator的锁用的就是临时顺序节点
ZAB协议
Zookeeper Atomic Broadcast
即Zookeeper原子广播协议
角色划分
划分集群角色,主从架构,分为Leader和Follower,只有Leader接受写入请求
ZPC两阶段提交
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,进行数据同步。
强一致性/最终一致性
强一致性
只要写入一条消息,立马无论从那个zk节点都能查到数据,写入操作卡住,直到所有的follower都返回ack,leader执行commit之后,所有从节点都能读到数据
很明显,根据zab协议,zk不是强一致性
最终一致性
研究过ZAB协议就能发现,follower半数以上返回ack,然后leader发送commit后就能读到数据了,那么就有一种可能,有的follower接收到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的人
读写性能分析
写请求
无论zookeeper集群多少台机器,只有leader能进行写入操作,单机写入最多每秒上万QPS,这是没办法拓展的
所以zk适用于写少的场景
读请求
一般2台,4台follower,可以支撑每秒几万的读QPS,还可以通过follower, observer进行拓展
但是一般不建议加太多的follower,写入的时候会向follower发送proposal,并且等待过半的follower返回ack, follower太多会影响性能,可以多加observer,因为它不参与选举以及proposal的ack返回