Zookeeper 跨區高可用方案

最近因爲業務需求,測試各類組件的高可用性。因爲咱們的環境在AWS 北京部署。只有兩個Aviable Zone(可用區)。php

註釋:有兩個數據中心,相互須要作容災的需求,和本文測試的狀況是相同的。html

而Zookeeper須要3個以上的單數節點同時工做,而且,必須保證半數以上的節點存活,還能正常提供服務。java

那麼,針對只有兩個AZ的狀況,無論怎麼規劃,都有機率遇到存在半數以上的AZ掛掉,致使整個Zookeeper不可用的狀況。node

clipboard.png

因此,咱們能作的就是,在這個AZ掛掉以後,咱們怎麼儘快處理,並恢復環境。apache

咱們準備兩個軟件安裝好,參數配置好的機器。在可用區1徹底掛掉以後,能夠手動啓動兩個備用節點。將可用區2的Zookeeper數量增長過半數。就能夠在可用區2恢復Zookeeper的服務。api

參考下圖:服務器

2.png

以上的設想,是否能實現呢?session

那咱們今天就來測試一下。socket

1. 一共準備了5臺機器,做爲測試ide

3.png

2. Zookeeper的下載與安裝。

2.1 Zookeeper官方下載地址

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/


2.2 下載軟件

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz

2.3 詳細Zookeeper安裝步驟,請參考:

https://blog.51cto.com/hsbxxl/1971241

2.4 zoo.cfg的配置 #cat zoo.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

2.5  根據zoo.cfg建立data和log兩個文件夾

mkdir -p /data/zookeeper/data 
mkdir -p /data/zookeeper/log

2.6 根據節點號碼,修改文件

echo 1 > /data/zookeeper/data/myid

3. 一共準備了5臺EC2進行測試,而且都已經安裝好Zookeeper

可是隻啓動三臺,另兩個機器做爲standby

下圖能夠看到,已經有三臺啓動zookeeper,

注意,在Zookeeper啓動的過程當中,必須保證三臺及以上,zookeeper集羣才能正常工做

5.png

4. 接下來,我開始逐個機器關機,看zookeeper的狀態

當前leader在zk3上,咱們先關閉zk1,再關閉zk3,看Leader會不會飄到zk2上

4.1 在zk1上執行kill,殺掉進程

[root@ip-172-31-9-73 ~]# jps
12438 Jps
7545 QuorumPeerMain
[root@ip-172-31-9-73 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: follower
[root@ip-172-31-9-73 ~]# kill -9 7545

4.2 在zk5上經過zkCli連接zk3,並能夠查詢數據。

在zk1上kill掉進程以後,理論上,還有zk2和zk3存活,可是zkCli的鏈接顯示已經報錯。

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.26.111:2181
Connecting to 172.31.26.111:2181
......
[zk: 172.31.26.111:2181(CONNECTED) 0] ls /
[zk-permanent, zookeeper, test]
[zk: 172.31.26.111:2181(CONNECTED) 1] 2019-06-23 07:28:06,581 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x30000c504530000, likely server has closed socket, closing socket connection and attempting reconnect
......
2019-06-23 07:28:09,822 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
2019-06-23 07:28:09,824 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@879] - Socket connection established to ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181, initiating session
2019-06-23 07:28:09,825 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x30000c504530000, likely server has closed socket, closing socket connection and attempting reconnect

4.3 咱們繼續 kill掉zk3上的進程,只保留zk2上的進程。可是咱們已經沒法確認zk2是Leader仍是Follow,或者說,他是否還保留有數據。

[root@ip-172-31-26-111 bin]# jps
4183 QuorumPeerMain
4648 Jps
[root@ip-172-31-26-111 bin]# kill -9 4183
[root@ip-172-31-26-111 bin]# jps
4658 Jps

4.4 zk3上進程kill掉以後,連接就不僅是上面的報錯了,而是直接鏈接拒絕

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.26.111:2181
Connecting to 172.31.26.111:2181
......
Welcome to ZooKeeper!
2019-06-23 07:35:18,411 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2019-06-23 07:35:18,533 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1162] - Socket error occurred: ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181: Connection refused
[zk: 172.31.26.111:2181(CONNECTING) 0] 2019-06-23 07:35:19,639 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
2019-06-23 07:35:19,640 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1162] - Socket error occurred: ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181: Connection refused

4.5 能夠看到zk2上的進程還在,

# jps
5155 QuorumPeerMain
5211 Jps

4.6 而且經過下面命令,能夠檢查到zk2 的2181端口還在提供服務

# echo ruok | nc localhost 2181
imok

4.7 可是其餘命令是沒有正常輸出的,只有echo ruok | nc localhost 2181輸出ok。

# echo ruok | nc 172.31.16.33 2181
imok[root@ip-172-31-16-33 bin]# echo conf | nc 172.31.16.33 2181
This ZooKeeper instance is not currently serving requests
# echo dump | nc 172.31.16.33 2181
This ZooKeeper instance is not currently serving requests

4.8  ZooKeeper 四字命令

ZooKeeper 四字命令

功能描述

conf

輸出相關服務配置的詳細信息。

cons

列出全部鏈接到服務器的客戶端的徹底的鏈接 / 會話的詳細信息。包括「接受 / 發送」的包數量、會話 id 、操做延遲、最後的操做執行等等信息。

dump

列出未經處理的會話和臨時節點。

envi

輸出關於服務環境的詳細信息(區別於 conf 命令)。

reqs

列出未經處理的請求

ruok

測試服務是否處於正確狀態。若是確實如此,那麼服務返回「imok 」,不然不作任何相應。

stat

輸出關於性能和鏈接的客戶端的列表。

wchs

列出服務器 watch 的詳細信息。

wchc

經過 session 列出服務器 watch 的詳細信息,它的輸出是一個與watch 相關的會話的列表。

wchp

經過路徑列出服務器 watch 的詳細信息。它輸出一個與 session相關的路徑。

4.9 正常狀況下,以上命令能夠輸出:

# echo dump | nc 172.31.20.233 2181

SessionTracker dump:
org.apache.zookeeper.server.quorum.LearnerSessionTracker@77714302
ephemeral nodes dump:
Sessions with Ephemerals (0):

# echo conf | nc 172.31.20.233 2181

clientPort=2181
dataDir=/data/zookeeper/data/version-2
dataLogDir=/data/zookeeper/log/version-2
tickTime=2000
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=2
initLimit=10
syncLimit=5
electionAlg=3
electionPort=3888
quorumPort=2888
peerType=0

# echo envi| nc 172.31.20.233 2181

Environment:
zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
host.name=ip-172-31-20-233.cn-north-1.compute.internal
java.version=1.8.0_212
java.vendor=Oracle Corporation
java.home=/usr/java/jdk1.8.0_212-amd64/jre
java.class.path=/root/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/root/zookeeper-3.4.14/bin/../build/classes:/root/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/root/zookeeper-3.4.14/bin/../build/lib/*.jar:/root/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/root/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/root/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/root/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/root/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/root/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/root/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/root/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/root/zookeeper-3.4.14/bin/../conf:
java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.io.tmpdir=/tmp
java.compiler=<NA>
os.name=Linux
os.arch=amd64
os.version=4.14.123-86.109.amzn1.x86_64
user.name=root
user.home=/root
user.dir=/root/zookeeper-3.4.14/bin

5. 這個時候,我去啓動另外兩個備用節點,zk4,zk5.這個兩個節點都是第一次啓動。

6.png

6. 再次鏈接到zookeeper上,能夠看到,至少數據仍是沒有丟失的

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.16.33:2181
Connecting to 172.31.16.33:2181
......
[zk: 172.31.16.33:2181(CONNECTED) 0] ls /
[zk-permanent, zookeeper, test]

7. 經過以上測試,彷佛是達到咱們預期的結果。惟一的一點小問題,就是:咱們有3個節點,爲何關閉1個,剩餘兩個,就不能正常運行了呢?

其實,這裏是有個「想固然」的小問題。

咱們覺得,只啓動三個. 其實,Zookeeper集羣,識別的是5個, 爲何呢?

Zookeeper靠什麼去識別集羣中有幾個節點呢?固然不是靠「想固然」。必定是有配置文件告訴它。Zookeeper,只有兩個配置文件zoo.cfg和myid。

那就只有zoo.cfg會影響到它了。

8. 我將zoo.cfg作以下修改以後。只開啓3個節點,在關閉一個節點以後,仍是能夠正常運行的。

註釋掉server2和server5

# cat zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
#server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
#server.5=172.31.16.33:2888:3888

9. 關閉server4以後,還有server2和server3活着。

[root@ip-172-31-26-111 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: leader
[root@ip-172-31-9-73 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: follower

10. 總結,若是考慮兩個AZ的狀況下,zookeeper節點數多的AZ出現災難狀況,咱們如何快速恢復?

(假設Server1/Server2在1AZ,Server3/Server4/Server5在2AZ)

10.1. 在Zookeeper節點少的AZ,多準備2臺配置好zookeeper的EC2,並關機待使用。Server4/Server5具體zoo.cfg配置以下

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

10.2.  Server1/Server2/Server3,是正常運行的節點,配置以下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888

10.3.  災難發生,Server1/Server2所在的1AZ掛掉的狀況下,須要人工介入,將Server3的配置更改成以下配置,並重啓Server3的zookeeper服務,而後啓動Server4/Server5,必定要先啓動Server3,注意順序。

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

10.4 平常運行狀態

7.png

10.5 檢查已經建立的znode信息

./zkCli.sh -server 172.31.16.33:2181 ls /
Connecting to 172.31.16.33:2181
[zk-permanent, zookeeper, test]

10.6 關閉Server1/Server2,注意順序,先關閉follow,若是先關閉leader,會發生切換。咱們指望的是Server3最後以follow的身份存活。


11. 最終能夠看到測試結果,一切都是按照咱們「想固然」的方向發展。

8.png

12. 最後驗證zookeeper中的znode數據,仍是都存在的。

./zkCli.sh  -server 172.31.16.33:2181 ls /
Connecting to 172.31.16.33:2181
[zk-permanent, zookeeper, test]

13. 其實數據一直是在這個路徑下,只要有一個節點還保留,就會保存下去。

# ls /data/zookeeper/data/
myid  version-2  zookeeper_server.pid

注意:必定要保證Server4/Server5的下面兩個路徑是空的,否則會出現,Server4/Server5識別的是以前的陳舊信息。

/data/zookeeper/data/version-2
/data/zookeeper/log/version-2

14. 說到這裏,咱們能夠理解到,Zookeeper的所有數據,都是存放在下面兩個路徑中。若是須要作備份,能夠直接在OS層面,作cp備份便可。

dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log

衍生一個想法,就是若是想作跨Region,北京(主環境)到寧夏(容災環境)的zookeeper的高可用怎麼作呢?

咱們能夠考慮將北京的zookeeper的數據文件按期備份,並導入到寧夏的環境。

具體步驟:

<1. 在寧夏啓動一個Zookeeper集羣,並配置好,而後關閉zookeeper服務,清空掉數據文件夾。

<2. 在北京,經過腳本按期檢查zookeeper各個節點狀態,從一個運行健康的節點,按期備份數據到S3的一個bucket,爲每一個文件加上時間戳。

<3. 經過S3的Cross Region Replication,同步到寧夏。

<4. 而後在寧夏,從S3讀取備份文件,並還原到災備的zookeeper中。

相關文章
相關標籤/搜索