zookeeper简介以及C客户端用法
zookeeper簡介以及C客戶端用法
- 前言
- 簡介
- zookeeper保證
- 理解zookeeper的順序一致性
- zookeeper 接口
- 安裝
- zoo.cfg參數(shù)詳解
- 常用命令
- C API
- zookeeper C API
- 如何在代碼中使用zk C API
- zookeeper引用計(jì)數(shù)
- zookeeper節(jié)點(diǎn)類型
- zookeeper集群
- ZooKeeper典型使用場景
- zk c client 連接流程
- zk 狀態(tài)轉(zhuǎn)換
- 連接中的異常
- 應(yīng)對(duì)
- 記一次線上事故
- 參考鏈接
前言
zookeeper用法有很多,但是針對(duì)C++的工具集和文檔卻很少,本文主要介紹zk的使用方法,特別是在C++上的一些用法。
簡介
Zookeepe維護(hù)一個(gè)類似文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu):每個(gè)子目錄項(xiàng)如 NameService 都被稱作為 znode(目錄節(jié)點(diǎn)),和文件系統(tǒng)一樣,我們能夠自由的增加、刪除znode,在一個(gè)znode下增加、刪除子znode,唯一的不同在于znode是可以存儲(chǔ)數(shù)據(jù)的。
有四種類型的znode:
- 客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)依舊存在
- 客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)依舊存在,只是Zookeeper給該節(jié)點(diǎn)名稱進(jìn)行順序編號(hào)
- 客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)被刪除
- 客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)被刪除,只是Zookeeper給該節(jié)點(diǎn)名稱進(jìn)行順序編號(hào)
zookeeper保證
根據(jù)zookeeper官方文檔,zookeeper提供了如下保證:
- Sequential Consistency - Updates from a client will be applied in the order that they were sent.
- Atomicity - Updates either succeed or fail. No partial results.
- Single System Image - A client will see the same view of the service regardless of the server that it connects to. i.e., a client will never see an older view of the system even if the client fails over to a different server with the same session. 如果client首先看到了新數(shù)據(jù),再嘗試重連到存有舊數(shù)據(jù)的follower,該follower會(huì)拒絕該連接(client的zxid高于follower)
- Reliability - Once an update has been applied, it will persist from that time forward until a client overwrites the update.
- Timeliness - The clients view of the system is guaranteed to be up-to-date within a certain time bound.
由此可見,zookeeper只提供順序一致性和分區(qū)容錯(cuò)性
理解zookeeper的順序一致性
ZooKeeper Programmer’s Guide提到:
Sometimes developers mistakenly assume one other guarantee that ZooKeeper does not in fact make. This is:
Simultaneously Conistent Cross-Client Views
ZooKeeper does not guarantee that at every instance in time, two different clients will have identical views of ZooKeeper data. Due to factors like network delays, one client may perform an update before another client gets notified of the change. Consider the scenario of two clients, A and B. If client A sets the value of a znode /a from 0 to 1, then tells client B to read /a, client B may read the old value of 0, depending on which server it is connected to. If it is important that Client A and Client B read the same value, Client B should should call the sync() method from the ZooKeeper API method before it performs its read.
So, ZooKeeper by itself doesn’t guarantee that changes occur synchronously across all servers, but ZooKeeper primitives can be used to construct higher level functions that provide useful client synchronization.
就是說zookeeper并不保證每次從其一個(gè)server讀到的值是最新的,它只保證這個(gè)server中的值是順序更新的,如果想要讀取最新的值,必須在get之前調(diào)用sync()
zookeeper 接口
zookeeper的接口十分簡單,只支持以下操作:
- create : creates a node at a location in the tree
- delete : deletes a node
- exists : tests if a node exists at a location
- get data : reads the data from a node
- set data : writes data to a node
- get children : retrieves a list of children of a node
- sync : waits for data to be propagated 對(duì)某個(gè)節(jié)點(diǎn)sync,保證拿到這個(gè)節(jié)點(diǎn)為最新的。(不確定是否是同步操作)
安裝
入門安裝指南
Step1:配置JAVA環(huán)境,檢驗(yàn)環(huán)境:java -version, 一般就用1.8
Step2:下載并解壓zookeeper
注:如果當(dāng)前的java版本和zk要求的不同,可以簡單的export臨時(shí)變量
JAVA_HOME=/home/test/jdk1.8.0_161/ export JAVA_HOME CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export CLASSPATH PATH=$JAVA_HOME/bin:$PATH export PATH cd /usr/local wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz tar -zxvf zookeeper-3.4.12.tar.gz cd zookeeper-3.4.12Step3:重命名配置文件zoo_sample.cfg
cp conf/zoo_sample.cfg conf/zoo.cfgStep4:啟動(dòng)zookeeper
bin/zkServer.sh startStep5:檢測是否成功啟動(dòng),用zookeeper客戶端連接下服務(wù)端
bin/zkCli.sh -timeout 5000 -r -server ip:portzoo.cfg參數(shù)詳解
| tickTime | zk中的時(shí)間單元,zk中所有時(shí)間都是以這個(gè)時(shí)間為基礎(chǔ),進(jìn)行整數(shù)倍配置的,如session的最小超時(shí)時(shí)間是2*tickTime, 每隔tickTime發(fā)送一個(gè)心跳 |
| clientPort | 客戶端連接zookeeper服務(wù)器的端口號(hào),默認(rèn)2181 |
| dataLogDir | 事務(wù)日志輸出目錄,盡量給事務(wù)日志的輸出配置單獨(dú)的磁盤或掛載點(diǎn),這將極大的提升zk性能,用于單獨(dú)設(shè)置transaction log的目錄,transaction log分離可以避免和普通log還有快照的競爭。 |
| dataDir | 存儲(chǔ)快照(snapshot)文件目錄,默認(rèn)事務(wù)日志也存儲(chǔ)在此路徑下,建議同時(shí)配置dataLogDir,會(huì)影響zk性能,zk會(huì)通過org.apache.zookeeper.server.ZKDatabase開加載 |
| globalOutstandingLimit | 系統(tǒng)屬性:zookeeper.globalOutstandingLimit 默認(rèn)1000,如果有大量的client,會(huì)造成zk server對(duì)請求的處理速度小于client的提交請求的速度,會(huì)造成server端大量請求queue滯留而導(dǎo)致OOM,此參數(shù)可以控制server最大持有為處理的請求個(gè)數(shù) |
| preAllocSize | 系統(tǒng)屬性:zookeeper.preAllocSize ,為了避免大量磁盤檢索,zk對(duì)txn log文件進(jìn)行空間的預(yù)分配,默認(rèn)為64M,當(dāng)剩余空間小于4k時(shí),會(huì)再次“預(yù)分配”。你可以嘗試減小此值,比如當(dāng)快照較為頻繁時(shí),可以適當(dāng)減小 |
| traceFile | 系統(tǒng)屬性:requestTraceFile 請求跟蹤文件,如果設(shè)置了此參數(shù),所有請求將會(huì)被記錄在traceFile.year.month.day,類似與nginx的request log,不過此參數(shù)會(huì)帶來性能問題 |
| maxClientCnxns | 默認(rèn):60, 一個(gè)client與server最大的socket連接數(shù),根據(jù)IP區(qū)分,設(shè)置為0,取消此限制。可以避免DOS攻擊 |
| clientPortAddress | ip或者h(yuǎn)ostName,指定監(jiān)聽clientPort的address,此參數(shù)可選,默認(rèn)是clientPort會(huì)綁定到所有ip上,在物理server具有多個(gè)網(wǎng)絡(luò)接口時(shí),可以設(shè)置特定的IP |
| minSessionTimeout | 默認(rèn) 2*tickTime,也是server允許的最小值,如果設(shè)置的值過小,將會(huì)采用默認(rèn)值 |
| maxSessionTimeout | 默認(rèn)20*tickTime,允許的最大值, 可以一句話概括,客戶端上報(bào)的期望timeout(zookeeper_init()函數(shù)的第三個(gè)參數(shù))一定要在服務(wù)端設(shè)置的上下界之間,如果越過邊界,則以邊界為準(zhǔn)。 |
| autopurge.snapRetainCount | zk server啟動(dòng)時(shí)會(huì)開啟一個(gè)org.apache.zookeeper.server.DatadirCleanupManager的線程,用于清理"過期"的snapshot文件和其相應(yīng)的txn log file,此參數(shù)用于設(shè)定需要被retain保留的文件個(gè)數(shù)(從QuorumPeerMain跟蹤代碼) |
| autopurge.purgeInterval | 和上述參數(shù)配合使用,清理任務(wù)的時(shí)間間隔,單位為hours, 可以查看org.apache.zookeeper.server.DatadirCleanupManager的105行 |
| snapCount | 系統(tǒng)屬性:zookeeper.snapCount 默認(rèn)為:100000,在新增Log條數(shù)達(dá)到snapCount/2 +Random.nextInt(snapCount/2)時(shí),將會(huì)對(duì)zkDatabase內(nèi)存數(shù)據(jù)庫進(jìn)行snapshot,將內(nèi)存中的DataTree反序列化到snapshot文件數(shù)據(jù),同時(shí)log計(jì)數(shù)重置為0,以此循環(huán), snapshot過程中,同時(shí)也伴隨txn log的新文件創(chuàng)建,snapshot時(shí)使用隨機(jī)數(shù)的原因:讓每個(gè)server snapshot的時(shí)機(jī)具有隨機(jī)且可控,避免所有的server同時(shí)snapshot可見:org.apache.zookeeper.server.SyncRequestProcessor.run()方法實(shí)現(xiàn) |
| electionAlg | 選舉算法,默認(rèn)為3,可以選擇(0,1,2,3), 0表示使用原生的UDP(LeaderElection), 1表示使用費(fèi)授權(quán)的UDP2表示使用授權(quán)的UDP(AuthFastLeaderElection) 3基于TCP的快速選舉(FastLeaderElection)具體可見:org.apache.zookeeper.server.quorum.QuorumPeer 159行createElectionAlgorithm(electionType);org.apache.zookeeper.server.quorum.LeaderElection (已被廢棄)org.apache.zookeeper.server.quorum.AuthFastLeaderElection(已被廢棄)org.apache.zookeeper.server.quorum.FastLeaderElection |
| initLimit | Leader與learner建立連接中 socket通訊read所阻塞的時(shí)間(initLimit * tickTime) 如果是Leaner數(shù)量較多或者leader的數(shù)量很大, 可以增加此值 ,代碼參考:org.apache.zookeeper.server.quorum.LearnerHandler第297行run()方法 |
| SyncLimit | learner與leader建立連接中,socket通訊read阻塞的時(shí)間.其中包括數(shù)據(jù)同步/數(shù)據(jù)提交等, 參考代碼:org.apache.zookeeper.server.quorum.Learner222行connectToLeader()316行syncWithLeader() |
| peerType | zkserver 類型 observer 觀察者, participant參與者 ,默認(rèn)為參與者 |
| leaderServes | 系統(tǒng)屬性 zookeeper.leaderServes leader是否接受client請求,默認(rèn)為yes即leader可以接受client的連接,在zk cluster 環(huán)境中,當(dāng)節(jié)點(diǎn)數(shù)為>3時(shí),建議關(guān)閉 |
| cnxTimeout | 系統(tǒng)屬性:zookeeper.cnxTimeout leader選舉時(shí)socket連接打開的時(shí)長,只有在electionAlg=3有效 |
| skipACL | 系統(tǒng)屬性:zookeeper.skipACL 默認(rèn)為no,是否跳過ACL檢查 |
| forceSync | 系統(tǒng)屬性:zookeeper.forceSync 默認(rèn)yes 在update執(zhí)行之前,是否強(qiáng)制對(duì)操作立即持久寫入txn log文件.關(guān)閉此選項(xiàng),會(huì)造成服務(wù)器失效后,尚未持久化的數(shù)據(jù)丟失 |
常用命令
bin/zkCli.sh ## 后面進(jìn)入命令行 ls / # 使用 ls 命令來查看當(dāng)前 ZooKeeper 中所包含的內(nèi)容 create /zkPro myData # 創(chuàng)建一個(gè)新的 znode get /zkPro # 查 set /zkPro myData123 # 改 delete /zkPro # 刪C API
- ZooKeeper Programmer’s Guide(官方C++例程)
zookeeper C API
zookeeper只有C API,沒有C++ API
CAPI的代碼已經(jīng)五六年沒更改過了,整體代碼并不難,這里只記一些碰到過的坑
https://github.com/apache/zookeeper.git
如何在代碼中使用zk C API
- 請?zhí)砑泳幾g選項(xiàng) -dthreaded,
- 同時(shí)鏈接時(shí)應(yīng)鏈接 zookeeper_mt 庫;
- 請不要添加編譯選項(xiàng) -dthreaded,
- 同時(shí)鏈接時(shí)應(yīng)鏈接 zookeeper_st 庫。
zookeeper引用計(jì)數(shù)
- 用zookeeper_init建立的zhandle包含成員ref_count,如果引用計(jì)數(shù)不為0,則無法關(guān)閉zookeeper(zookeeper_close)
- ref_count可以用api_prolog加1,常見的應(yīng)用場合:
- 發(fā)送隊(duì)列里有東西的時(shí)候
- 正在初始化thread的時(shí)候
- do_io和do_completion都會(huì)讓引用計(jì)數(shù)+1
zookeeper節(jié)點(diǎn)類型
是否持久
- persistent :持久節(jié)點(diǎn)。需要主動(dòng)刪除
- ephemeral : 瞬時(shí)節(jié)點(diǎn)。與客戶端session結(jié)束,自動(dòng)刪除; 不能有子節(jié)點(diǎn)
是否有序
- persistent_sequential : 持久有序節(jié)點(diǎn)。
- ephemeral_sequential : 瞬時(shí)有序節(jié)點(diǎn)。
zookeeper集群
ZooKeeper典型使用場景
- ZooKeeper典型使用場景一覽 - 阿里
- ZooKeeper的強(qiáng)一致性,能夠保證在分布式高并發(fā)情況下節(jié)點(diǎn)創(chuàng)建的全局唯一性,即:同時(shí)有多個(gè)客戶端請求創(chuàng)建 /currentMaster 節(jié)點(diǎn),最終一定只有一個(gè)客戶端請求能夠創(chuàng)建成功。
zk c client 連接流程
zk 狀態(tài)轉(zhuǎn)換
有一點(diǎn)很關(guān)鍵,zk的狀態(tài),有一些是由zkserver轉(zhuǎn)換,有一些是由zkclient轉(zhuǎn)換的。
C++客戶端中的connecting,這是客戶端的狀態(tài)(也就是curator中的SUSPENDED),如果客戶端準(zhǔn)備連接到server但是還沒連接成功,或者連接上之后發(fā)給zkserver的心跳沒有回應(yīng)(網(wǎng)絡(luò)異常),導(dǎo)致client斷開當(dāng)前session連接,并且換一個(gè)server地址重連。client就會(huì)把自己設(shè)為connecting狀態(tài)。
- 同理,client如果在沒有收到server的心跳回包,也會(huì)斷開當(dāng)前鏈接,并且用zoo_cycle_next_server(C++客戶端)找下一個(gè)可用的zkserver嘗試重連。
連接中的異常
應(yīng)對(duì)
記一次線上事故
- 我司使用zk做選主+服務(wù)發(fā)現(xiàn),在某天夜里,突然zk因?yàn)閴毫μ?#xff0c;被打爆了,從而引發(fā)了多個(gè)問題
- zk腦裂:
- 我們多個(gè)服務(wù)向zk同一個(gè)節(jié)點(diǎn)注冊,注冊的升級(jí)為master節(jié)點(diǎn),其他的為follower
- 但是事故發(fā)生時(shí),zk服務(wù)不可用,master節(jié)點(diǎn)沒有感知到expired事件,因此認(rèn)為自己仍是master
- 有一個(gè)follower服務(wù)感知到了master節(jié)點(diǎn)被刪除的事件,把自己提升為master,從此,集群有了兩個(gè)master,因此導(dǎo)致了整個(gè)集群的癱瘓。
- zk hang
- zk客戶端和服務(wù)端網(wǎng)絡(luò)不通暢的時(shí)候,服務(wù)端發(fā)出的expire事件并不能及時(shí)通知到客戶端,客戶端如果不能及時(shí)對(duì)connecting狀態(tài)做出反應(yīng),仍然向server拉節(jié)點(diǎn),如果用同步API,就會(huì)造成hang,如果用異步API,operation_timeout的通知也會(huì)過很久(C客戶端上拉取節(jié)點(diǎn)超時(shí)的時(shí)間是三分之二的zktimeout時(shí)間)才返回。
- zk雪崩
- zk客戶端的邏輯是:重連之后會(huì)對(duì)所有節(jié)點(diǎn)重新watch, 如果zk不可用導(dǎo)致所有的zk連接expire,那么會(huì)導(dǎo)致所有的節(jié)點(diǎn)去server watch節(jié)點(diǎn),驚群效應(yīng)會(huì)導(dǎo)致zk壓力過大–>服務(wù)處理延遲過大–>導(dǎo)致client認(rèn)為客戶端連接失敗–>zk客戶端重連–>連接失敗–>然后就會(huì)一直重連。無限循環(huán)
- Zookeeper中Session Timeout的那些事
參考鏈接
總結(jié)
以上是生活随笔為你收集整理的zookeeper简介以及C客户端用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈RDMA流控设计
- 下一篇: RDMA简介