上一篇文章,咱们讲解了 ZooKeeper 入门知识,这篇文章主要讲解下 ZooKeeper 的架构,理解 ZooKeeper 的架构能够帮助咱们更好地设计协同服务。java
首先咱们来看下 ZooKeeper 的整体架构图。node
应用使用 ZooKeeper 客户端库来使用 ZooKeeper 服务,ZooKeeper 客户端会和集群中某一个节点创建 session, ZooKeeper 客户端负责和 ZooKeeper 集群的交互。 ZooKeeper 集群能够有两种模式:standalone 模式和 quorum 模式。处于 standalone 模式的 ZooKeeper 集群还有一个独立运行的 ZooKeeper 节点,standalone 模式通常用来开发。实际生产环境 ZooKeeper 通常处于 quorum 模式,在 quorum 模式下 ZooKeeper 集群包换多个 ZooKeeper 节点。数据库
Session 是 ZooKeeper 客户端的一个重要概念,ZooKeeper 客户端库和 ZooKeeper 集群中的节点建立一个 session。客户端能够主动关闭 session。另外若是 ZooKeeper 节点没有在 session 关联的 timeout 时间内收到客户端的数据的话,ZooKeeper 节点也会关闭 session。另外 ZooKeeper 客户端库若是发现链接的 ZooKeeper 出错,会自动的和其余 ZooKeeper 节点创建链接。apache
下图展现了 ZooKeeper 客户端是如何进行重连的?segmentfault
刚开始 ZooKeeper 客户端和 ZooKeeper 集群中的节点 1 创建的 session,在过了一段时间后,ZooKeeper 节点 1 失败了,ZooKeeper 客户端就自动和 ZooKeeper 集群中的节点 3 从新创建了 session 链接。服务器
处于 Quorum 模式的 ZooKeeper 集群包含多个 ZooKeeper 节点。 下图的 ZooKeeper 集群有 3 个节点,其中节点 1 是 leader 节点,节点 2 和节点 3 是 follower 节点。集群中只能有一个 leader 节点,能够有多个 follower 节点,leader 节点能够处理读写请求,follower 只能够处理读请求。follower 在接到写请求时会把写请求转发给 leader 来处理。session
下面来讲下 ZooKeeper 保证的数据一致性:架构
数据一致性socket
为了让你们更好地理解 Quorum 模式,下面会配置一个 3 节点的 Quorum 模式的 ZooKeeper 集群。spa
首先须要准备 3 个配置文件,dataDir 和 clientPort 配置项要配置不一样的值。3 个配置文件的 server.n 部分都是同样的。在 server.1=127.0.0.1:3333:3334,其中 3333 是 quorum 之间的通讯的端口号,3334 是用于 leader 选举的端口号。
还须要在每一个节点的 dataDir 目录下建立 myid 文件,里面内容为一个数字,用来标识当前主机,配置文件中配置的 server.n 中 n 为何数字,则 myid 文件中就输入这个数字。
以下是第 1 个节点的配置文件,其中目录是 node1,端口号用的是 2181,另外两个节点的目录分别是 node2 和 node3,端口号分别为 2182 和 2183,最下面的三行都是同样的:
# 心跳检查的时间 2秒 tickTime=2000 # 初始化时 链接到服务器端的间隔次数,总时间10*2=20秒 initLimit=10 # ZK Leader 和follower 之间通信的次数,总时间5*2=10秒 syncLimit=5 # 存储内存中数据库快照的位置,若是不设置参数,更新事务日志将被存储到默认位置。 dataDir=/data/zk/quorum/node1 # ZK 服务器端的监听端口 clientPort=2181 server.1=127.0.0.1:3333:3334 server.2=127.0.0.1:4444:4445 server.3=127.0.0.1:5555:5556
下面来启动这个集群,首先启动第一个节点,启动命令以下:
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.5.6-bin/conf/zoo-quorum-node1.cfg
注:start-foreground 选项 zkServer.sh 在前台运行,把日志直接打到 console。若是把日志打到文件的话,这三个 zkServer.sh 会把日志打到同一个文件。
在启动第一个节点后日志中会出现以下:
2019-12-29 13:14:35,758 [myid:1] - WARN [WorkerSender[myid=1]:QuorumCnxManager@679] - Cannot open channel to 2 at election address /127.0.0.1:4445 java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:650) at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:707) at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:620) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:477) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:456) at java.lang.Thread.run(Thread.java:748)
缘由是配置文件中配置的为 3 个节点,可是只启动了 1 个节点,目前他和其余另外两个节点创建不了链接,因此报这个问题。
接下来启动第 2 个节点,执行命令以下:
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.5.6-bin/conf/zoo-quorum-node2.cfg
启动后,咱们能够在节点 2 的日志中发现这么一行:
2019-12-29 13:15:13,699 [myid:2] - INFO [QuorumPeer[myid=2](plain=/0.0.0.0:2182)(secure=disabled):Leader@464] - LEADING - LEADER ELECTION TOOK - 41 MS
这说明节点 2 成为了 leader 节点,一样能够在节点 1 的日志中发现以下一行日志,说明了节点 1 成为了 follower 节点。
2019-12-29 13:15:13,713 [myid:1] - INFO [QuorumPeer[myid=1](plain=/0.0.0.0:2181)(secure=disabled):Follower@69] - FOLLOWING - LEADER ELECTION TOOK - 61 MS
由于对于一个三节点集群来讲两个就表明了多数,就造成了 Quorum 模式,接下来启动第 3 个节点,执行命令以下:
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.5.6-bin/conf/zoo-quorum-node3.cfg
启动后在日志中也有以下一行,说明第 3 个节点也加入这个集群,而且是做为 follower 节点加入的。
2019-12-29 13:15:52,440 [myid:3] - INFO [QuorumPeer[myid=3](plain=/0.0.0.0:2183)(secure=disabled):Follower@69] - FOLLOWING - LEADER ELECTION TOOK - 15 MS
下面来启动客户端来使用这个三节点集群,在命令中加了 -server
选项,后面指定的是三个节点的主机名和端口号,命令以下:
zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
2019-12-29 13:45:44,982 [myid:127.0.0.1:2181] - INFO [main-SendThread(127.0.0.1:2181):ClientCnxn$SendThread@1394] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x101fff740830000, negotiated timeout = 30000
经过启动日志能够看到客户端和端口号为 2181 的节点创建了链接,也就是和第 1 个节点创建了链接。
咱们执行 ls -R /
命令看下这个集群中的 znode 数据。
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 1] ls -R / / /zookeeper /zookeeper/config /zookeeper/quota
下面咱们杀掉一个 ZooKeeper 节点,看客户端是否能进行重连。如今咱们连的节点 1,咱们来把节点 1 杀掉,能够在客户端的日志中发现客户端和端口号为 2183 的节点从新创建了链接,也就是和节点 3 创建了链接。
2019-12-29 14:03:31,392 [myid:127.0.0.1:2183] - INFO [main-SendThread(127.0.0.1:2183):ClientCnxn$SendThread@1394] - Session establishment complete on server localhost/127.0.0.1:2183, sessionid = 0x101fff740830000, negotiated timeout = 30000
而后咱们再看下客户端可否正常使用,执行 ls -R /
,能够发现可以正常返回数据,说明客户端是可以正常使用的。
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 4] ls -R / / /zookeeper /zookeeper/config /zookeeper/quota
这篇文章主要讲解了 ZooKeeper 架构,以及怎样配置一个三节点的 ZooKeeper 集群。