简介
zookeeper是分布式协调服务
可以在分布式系统中共享配置
可以用来实现分布式锁
zookeeper很像文件系统的目录,目录中的文件称为Znode
比如定义一个Znode
: /canal/cluster
cluster里面可以定义
- data:存储的数据
- ACL:访问权限,即哪些用户/IP可以访问
- stat:包含各种元数据,事务ID、版本号、时间戳、大小等
- child:子节点
安装
这里使用docker安装zookeeper集群
新建文件stack.yml,这里定义了三个zookeeper节点,端口号分别是2181,2182,2183
version: '3.1'
services:
zoo1:
image: zookeeper
restart: always
hostname: zoo1
ports:
- 2181:2181
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
zoo2:
image: zookeeper
restart: always
hostname: zoo2
ports:
- 2182:2181
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181
zoo3:
image: zookeeper
restart: always
hostname: zoo3
ports:
- 2183:2181
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181
执行命令docker-compose -f stack.yml up
可以发现已正常启动,并自动创建里一个zookeeper_default的network
docker-hub地址:https://hub.docker.com/_/zook...
ZK-Web
使用docker安装一个简单版的web
docker run -d \
-p 8080:8080 \
-e ZK_DEFAULT_NODE=192.168.0.100:2181/ \
--name zk-web \
-t tobilg/zookeeper-webui
访问localhost:80,即可看到znode节点信息
ZkCli
安装docker-cli执行环境,注意要设置network
,可以使用docker network list
等命令查看network信息
在docker安装ZkClidocker run --network zookeeper_default -it --rm --link zookeeper_zoo1_1:zookeeper zookeeper zkCli.sh -server zookeeper
- help:帮助命令
- conect:连接zookeeper,host:port
- ls:查看目录下znode列表
- get:查看znode信息
- set:设置znode值
- create:创建znode -s代表创建顺序节点
- delete:删除znode
- stat:返回znode的详情信息
[zk: 192.168.101.92:2181,192.168.101.92:2182,192.168.101.92:2183(CONNECTED) 47] ls /
[otter, test, zookeeper]
[zk: 192.168.101.92:2181,192.168.101.92:2182,192.168.101.92:2183(CONNECTED) 48] create -s /test/req
Created /test/req0000000000
[zk: 192.168.101.92:2181,192.168.101.92:2182,192.168.101.92:2183(CONNECTED) 49] create -s /test/req
Created /test/req0000000001
[zk: 192.168.101.92:2181,192.168.101.92:2182,192.168.101.92:2183(CONNECTED) 50] create -s /test/req
Created /test/req0000000002
[zk: 192.168.101.92:2181,192.168.101.92:2182,192.168.101.92:2183(CONNECTED) 51] create -s /test/req
Created /test/req0000000003
zookeeper官方命令介绍:https://zookeeper.apache.org/...
原理
zookeeper是一主多从的架构,只有主可以写,从只能读
如果主挂掉了,则会自动选举出主节点,使用ZAB(Zookeeper Atomic Broadcast)协议保证数据的一致性
ZAB协议的状态
- Looking:选举状态
- Follwing:Follower节点的状态
- Leading:Leader节点的状态
写Leader
- 客户端发送写请求到
Follower
节点 -
Follower
节点将写入请求转发到Leader
节点 -
Leader
节点采用二阶段提交方法,先发送Propose
广播给从节点 - 从节点接收到
Propose
消息,写入日志成功后,返回ACK
消息给Leader
- 主节点接收到过半以上的
ACK
,则广播Commit
请求给从节点
读Leader/Follower
leader/follower都可以直接处理读请求,follower越多能处理的读请求量越大
基于TCP的FastLeaderElection选举算法
- myid:集群中每台服务器的唯一id
- zxid:类似事务ID,高32位是Leader的epoch,从1开始,每次选出新Leader,epoch+1,低32位是该epoch内的序号,每当epoch变化,会重置低32位
每个服务器在进行领导选举时,会发送如下关键信息:
- logicClock 每个服务器会维护一个自增的整数,名为logicClock,它表示这是该服务器发起的第多少轮投票
- state 当前服务器的状态
-
self_id 当前服务器的
myid
-
self_zxid 当前服务器上所保存的数据的最大
zxid
-
vote_id 被推举的服务器的
myid
-
vote_zxid 被推举的服务器上所保存的数据的最大
zxid
选举过程
- 自增选举轮次,对自己维护的logicClock 加 1
- 每个服务器最开始都是将票通过广播投给自己
- 接收外部投票,计入自己的投票箱,[2, 3]代表服务器2投票给了服务器3
- 先对比
logicClock
,若外部投票的LogicClock
小于当前自己LogicClock
,则忽略该投票, - 若
LogicClock
一样,则对比zxid
,投票给zxid
大的服务器,并广播 - 若
zxid
一样,则对比myid
,投票给myid
大的,并广播 - 统计选票,如果过半服务器认可了自己的投票,则终止投票,更新自身状态为
LEADING/FOLLOWING
查看服务器sid=3的选举日志
收到日志:n.sid:2, n.state:LOOKING, n.leader:2
state=LOOKING 代表正在选举,2投票给了2
收到日志:n.sid:2, n.state:LOOKING, n.leader:3
state=LOOKING 代表正在选举,2投票给了3 (因为初始情况下,LogicClock和zxid都一样,投给了sid最的3)
服务器2、服务器1都投票给了服务器3,所以服务器3成为LEADER
`2020-06-02 05:48:28,207 [myid:3] - INFO [ListenerHandler-/0.0.0.0:3888:QuorumCnxManager$Listener$ListenerHandler@1070] - Received connection request from /172.18.0.4:49944
2020-06-02 05:48:28,220 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:2, n.state:LOOKING, n.leader:2, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-06-02 05:48:28,225 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:2, n.state:LOOKING, n.leader:3, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-06-02 05:48:28,255 [myid:3] - INFO [ListenerHandler-/0.0.0.0:3888:QuorumCnxManager$Listener$ListenerHandler@1070] - Received connection request from /172.18.0.3:45270
2020-06-02 05:48:28,266 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:1, n.state:LOOKING, n.leader:1, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-06-02 05:48:28,272 [myid:3] - INFO [WorkerReceiver[myid=3]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:1, n.state:LOOKING, n.leader:3, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-06-02 05:48:28,474 [myid:3] - INFO QuorumPeer[myid=3(secure=disabled):QuorumPeer@857] - Peer state changed: leading
2020-06-02 05:48:28,475 [myid:3] - INFO QuorumPeer[myid=3(secure=disabled):QuorumPeer@1465] - LEADING`
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。