基础概念
集群角色
zookeeper没有使用主备模式。
在zookeeper中有Leader,Follower和Observer三个角色。
Leader为客户端提供读写服务,而Follwer和Observer只提供读服务,Observer不参加选举过程。
会话Session
客户端和zookeeper的一个tcp长连接就是一个会话。
会话可以通知watcher事件的触发。
因为故障导致断开tcp,在一定时间内重新连接后还是沿用之前的会话。
数据节点Znode
数据节点称为Znode
zookeeper将所有数据存储在内存中,数据模型是一棵树,由/进行分割的路径就是一个znode,例如/foo/path1。
每个节点都会记录自己的版本,子节点的版本,ACL版本(权限控制)。
每个znode上面都会保存自己的数据内容,同时还会保存一系列的属性信息。
临时节点和持久节点:临时节点和会话绑定,当会话结束,那么临时节点也会消失。
zookeeper的应用场景
数据发布/订阅:响应式数据的集中管理
zookeeper采用的是推拉相结合的方式:客户端向服务端注册监视节点,当节点数据发生变动,服务端向客户端发送watcher事件通知,客户端收到通知后,主动向服务端拉取最新数据。
负载均衡
zookeeper实现负载均衡的动态dns(DDNS)。
实现方式:
- 在zookeeper上创建节点/DDNS/app/server.app.com 域名节点
- 在节点数据中存储这个域名的ip地址:
create /DDNS/app/server.app.com 192.168.0.1:8000,192.168.0.2:8080
使用ddns服务的从这个节点获取ip地址,同时订阅这个节点,能够收到域名变更通知。
命名服务
通过命名服务,客户端应用能够通过需求服务的服务名来获得资源的地址和信息等。
发布式协调/通知
zookeeper中独有的watcher注册和异步通知机制,能实现很好地分布式环境下的不同系统之间的协调和通知。
在mysql的数据复制过程中承担mysql的主备集群协调
每台主机都需要注册入主备集群中:
craete -e -q /mysql_replicator/tasks/copy_hot_item/insatnces/host-
通过让zookeeper生成的id最小的主机为主机器,其他为备份机器。
当主机器退出后(被订阅),会通知其他节点进行重新选举。
- 从服务器(Slave)连接到主服务器:
从服务器通过配置连接到主服务器,并请求复制主服务器上的二进制日志。 - 从服务器获取主服务器的快照:
初次启动时,从服务器可能会请求主服务器上的快照数据,以确保从服务器处于与主服务器相同的初始状态。这个过程称为初始化数据快照。 - 主服务器将二进制日志传输到从服务器:
一旦从服务器与主服务器建立连接,主服务器开始将二进制日志传输给从服务器。从服务器会持续获取并应用这些日志,以保持与主服务器数据的一致性。 - 从服务器应用二进制日志:
从服务器将接收到的二进制日志应用到自身的数据库中,以反映主服务器上的所有更改。这确保了主从服务器的数据保持同步。
通用的分布式系统机器间通信方式
系统间通信的目的无法三个:心跳检测,工作进度汇报,系统调度。
心跳检测:通过订阅临时节点来实现
工作进度汇报:临时节点上记录实时的工作进度
系统调度:控制台/客户端系统架构,将一个节点作为控制台存储指令,客户端订阅节点,从而实现调用
集群管理:对集群中的机器运行状态收集,对集群中的机器进行上下线
zookeeper通过节点数据和watcher可以实现。
机器监控
通过监听父节点的状态,当有机器通过创建临时节点的方式加入集群时,父节点发出“子节点状态改变”的通知。
实现分布式日志收集系统
- 创建收集日志的机器:create /logs/collector 192.168.0.1:8080
- 将需要提交日志的机器注册到收集日志的机器上 create -e /logs/collector/host1 192.168.0.2:8080
- 通过收集日志的机器的定时遍历从而实现分布式的机器的日志收集
Master选举
zookeeper实现:
多个机器在相同时间,同时create一个相同的临时时间节点,成功的成为主节点,失败的监听主节点,当主节点挂掉,重选。
分布式锁
排他锁(写锁)
给使用资源注册临时节点,使用完资源后删除锁。
共享锁(读锁)
- 创建资源节点 create /lock/resourece
- 读机器在资源节点下创建临时顺序锁,同时获取/lock/resourece下的所有子节点,并且对/lock/resource注册watcher。
- 确认自己的节点序号在所有/lock/resourece节点下的顺序
- 如果比自己序号小的节点都是读请求,则开始读,比自己序号小的节点中有写锁,则进入等待。
- 收到watcher子节点变更后重新进行检测自己的序号排位。
缺点:子节点变更会通知所有节点,消耗资源
改进:新注册的节点只监听比自己小一位的节点。
分布式队列
- create /queue_fifo
- 入队创建临时节点 create -e -q /queue_fifo/host1-00000001
- 新节点加入后如果自己不是最小的进入等待,并且监听比自己序号小的最后一个节点
- 收到watcher信号后执行。
kafka中的zookeeper
Broker的注册
每个broker启动时,都会在zookeeper上注册“broker”节点:create -e /broker/ids/1
Topic的注册
“topic”节点:create /brokers/topics/login
在kafka中,会将一个topic分区,并且发布到多个broker上面,这些分区信息也是由zookeeper维持的。
create -e /brokers/topics/login/3 2
表明brokerid为3的broker存储了login topic的俩个分区的数据。
消息分区和消费者的关系
一个消息分区有一个消费者消费,需要将消费者的consumer id写入到对应消费分区的临时节点上。
create -e /consumers/consumergourpid/owner/topic/broker_id-paritition_id
记录分区的offset消费进度
/consumers/group_id/offsets/topic/broker_id-paritition_id 其内容就是offset值。
消费者的注册
- 注册到消费者分组
create /consumers/group_id/ids/consumer_id - 对消费者分组的变化注册监听,一旦发生事件,就会修改同组的消费者的消费的分区(负载均衡)
watcher /consumers/group_id/ids - 对broker服务器的变化注册监听
- 进行消费者组的topic的负载均衡
基于mysql binlog的增量订阅和消费组件:Canal
canal将自己伪装成一个mysql的slave机器,向mysq主服务器进行binlog的同步。
zookeeper实现canal的主备设计