zookeeper简介以及C客户端用法
zookeeper簡介以及C客戶端用法
- 前言
- 簡介
- zookeeper保證
- 理解zookeeper的順序一致性
- zookeeper 接口
- 安裝
- zoo.cfg參數詳解
- 常用命令
- C API
- zookeeper C API
- 如何在代碼中使用zk C API
- zookeeper引用計數
- zookeeper節點類型
- zookeeper集群
- ZooKeeper典型使用場景
- zk c client 連接流程
- zk 狀態轉換
- 連接中的異常
- 應對
- 記一次線上事故
- 參考鏈接
前言
zookeeper用法有很多,但是針對C++的工具集和文檔卻很少,本文主要介紹zk的使用方法,特別是在C++上的一些用法。
簡介
Zookeepe維護一個類似文件系統的數據結構:每個子目錄項如 NameService 都被稱作為 znode(目錄節點),和文件系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在于znode是可以存儲數據的。
有四種類型的znode:
- 客戶端與zookeeper斷開連接后,該節點依舊存在
- 客戶端與zookeeper斷開連接后,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號
- 客戶端與zookeeper斷開連接后,該節點被刪除
- 客戶端與zookeeper斷開連接后,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號
zookeeper保證
根據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首先看到了新數據,再嘗試重連到存有舊數據的follower,該follower會拒絕該連接(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只提供順序一致性和分區容錯性
理解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并不保證每次從其一個server讀到的值是最新的,它只保證這個server中的值是順序更新的,如果想要讀取最新的值,必須在get之前調用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 對某個節點sync,保證拿到這個節點為最新的。(不確定是否是同步操作)
安裝
入門安裝指南
Step1:配置JAVA環境,檢驗環境:java -version, 一般就用1.8
Step2:下載并解壓zookeeper
注:如果當前的java版本和zk要求的不同,可以簡單的export臨時變量
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:啟動zookeeper
bin/zkServer.sh startStep5:檢測是否成功啟動,用zookeeper客戶端連接下服務端
bin/zkCli.sh -timeout 5000 -r -server ip:portzoo.cfg參數詳解
| tickTime | zk中的時間單元,zk中所有時間都是以這個時間為基礎,進行整數倍配置的,如session的最小超時時間是2*tickTime, 每隔tickTime發送一個心跳 |
| clientPort | 客戶端連接zookeeper服務器的端口號,默認2181 |
| dataLogDir | 事務日志輸出目錄,盡量給事務日志的輸出配置單獨的磁盤或掛載點,這將極大的提升zk性能,用于單獨設置transaction log的目錄,transaction log分離可以避免和普通log還有快照的競爭。 |
| dataDir | 存儲快照(snapshot)文件目錄,默認事務日志也存儲在此路徑下,建議同時配置dataLogDir,會影響zk性能,zk會通過org.apache.zookeeper.server.ZKDatabase開加載 |
| globalOutstandingLimit | 系統屬性:zookeeper.globalOutstandingLimit 默認1000,如果有大量的client,會造成zk server對請求的處理速度小于client的提交請求的速度,會造成server端大量請求queue滯留而導致OOM,此參數可以控制server最大持有為處理的請求個數 |
| preAllocSize | 系統屬性:zookeeper.preAllocSize ,為了避免大量磁盤檢索,zk對txn log文件進行空間的預分配,默認為64M,當剩余空間小于4k時,會再次“預分配”。你可以嘗試減小此值,比如當快照較為頻繁時,可以適當減小 |
| traceFile | 系統屬性:requestTraceFile 請求跟蹤文件,如果設置了此參數,所有請求將會被記錄在traceFile.year.month.day,類似與nginx的request log,不過此參數會帶來性能問題 |
| maxClientCnxns | 默認:60, 一個client與server最大的socket連接數,根據IP區分,設置為0,取消此限制。可以避免DOS攻擊 |
| clientPortAddress | ip或者hostName,指定監聽clientPort的address,此參數可選,默認是clientPort會綁定到所有ip上,在物理server具有多個網絡接口時,可以設置特定的IP |
| minSessionTimeout | 默認 2*tickTime,也是server允許的最小值,如果設置的值過小,將會采用默認值 |
| maxSessionTimeout | 默認20*tickTime,允許的最大值, 可以一句話概括,客戶端上報的期望timeout(zookeeper_init()函數的第三個參數)一定要在服務端設置的上下界之間,如果越過邊界,則以邊界為準。 |
| autopurge.snapRetainCount | zk server啟動時會開啟一個org.apache.zookeeper.server.DatadirCleanupManager的線程,用于清理"過期"的snapshot文件和其相應的txn log file,此參數用于設定需要被retain保留的文件個數(從QuorumPeerMain跟蹤代碼) |
| autopurge.purgeInterval | 和上述參數配合使用,清理任務的時間間隔,單位為hours, 可以查看org.apache.zookeeper.server.DatadirCleanupManager的105行 |
| snapCount | 系統屬性:zookeeper.snapCount 默認為:100000,在新增Log條數達到snapCount/2 +Random.nextInt(snapCount/2)時,將會對zkDatabase內存數據庫進行snapshot,將內存中的DataTree反序列化到snapshot文件數據,同時log計數重置為0,以此循環, snapshot過程中,同時也伴隨txn log的新文件創建,snapshot時使用隨機數的原因:讓每個server snapshot的時機具有隨機且可控,避免所有的server同時snapshot可見:org.apache.zookeeper.server.SyncRequestProcessor.run()方法實現 |
| electionAlg | 選舉算法,默認為3,可以選擇(0,1,2,3), 0表示使用原生的UDP(LeaderElection), 1表示使用費授權的UDP2表示使用授權的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所阻塞的時間(initLimit * tickTime) 如果是Leaner數量較多或者leader的數量很大, 可以增加此值 ,代碼參考:org.apache.zookeeper.server.quorum.LearnerHandler第297行run()方法 |
| SyncLimit | learner與leader建立連接中,socket通訊read阻塞的時間.其中包括數據同步/數據提交等, 參考代碼:org.apache.zookeeper.server.quorum.Learner222行connectToLeader()316行syncWithLeader() |
| peerType | zkserver 類型 observer 觀察者, participant參與者 ,默認為參與者 |
| leaderServes | 系統屬性 zookeeper.leaderServes leader是否接受client請求,默認為yes即leader可以接受client的連接,在zk cluster 環境中,當節點數為>3時,建議關閉 |
| cnxTimeout | 系統屬性:zookeeper.cnxTimeout leader選舉時socket連接打開的時長,只有在electionAlg=3有效 |
| skipACL | 系統屬性:zookeeper.skipACL 默認為no,是否跳過ACL檢查 |
| forceSync | 系統屬性:zookeeper.forceSync 默認yes 在update執行之前,是否強制對操作立即持久寫入txn log文件.關閉此選項,會造成服務器失效后,尚未持久化的數據丟失 |
常用命令
bin/zkCli.sh ## 后面進入命令行 ls / # 使用 ls 命令來查看當前 ZooKeeper 中所包含的內容 create /zkPro myData # 創建一個新的 znode get /zkPro # 查 set /zkPro myData123 # 改 delete /zkPro # 刪C API
- ZooKeeper Programmer’s Guide(官方C++例程)
zookeeper C API
zookeeper只有C API,沒有C++ API
CAPI的代碼已經五六年沒更改過了,整體代碼并不難,這里只記一些碰到過的坑
https://github.com/apache/zookeeper.git
如何在代碼中使用zk C API
- 請添加編譯選項 -dthreaded,
- 同時鏈接時應鏈接 zookeeper_mt 庫;
- 請不要添加編譯選項 -dthreaded,
- 同時鏈接時應鏈接 zookeeper_st 庫。
zookeeper引用計數
- 用zookeeper_init建立的zhandle包含成員ref_count,如果引用計數不為0,則無法關閉zookeeper(zookeeper_close)
- ref_count可以用api_prolog加1,常見的應用場合:
- 發送隊列里有東西的時候
- 正在初始化thread的時候
- do_io和do_completion都會讓引用計數+1
zookeeper節點類型
是否持久
- persistent :持久節點。需要主動刪除
- ephemeral : 瞬時節點。與客戶端session結束,自動刪除; 不能有子節點
是否有序
- persistent_sequential : 持久有序節點。
- ephemeral_sequential : 瞬時有序節點。
zookeeper集群
ZooKeeper典型使用場景
- ZooKeeper典型使用場景一覽 - 阿里
- ZooKeeper的強一致性,能夠保證在分布式高并發情況下節點創建的全局唯一性,即:同時有多個客戶端請求創建 /currentMaster 節點,最終一定只有一個客戶端請求能夠創建成功。
zk c client 連接流程
zk 狀態轉換
有一點很關鍵,zk的狀態,有一些是由zkserver轉換,有一些是由zkclient轉換的。
C++客戶端中的connecting,這是客戶端的狀態(也就是curator中的SUSPENDED),如果客戶端準備連接到server但是還沒連接成功,或者連接上之后發給zkserver的心跳沒有回應(網絡異常),導致client斷開當前session連接,并且換一個server地址重連。client就會把自己設為connecting狀態。
- 同理,client如果在沒有收到server的心跳回包,也會斷開當前鏈接,并且用zoo_cycle_next_server(C++客戶端)找下一個可用的zkserver嘗試重連。
連接中的異常
應對
記一次線上事故
- 我司使用zk做選主+服務發現,在某天夜里,突然zk因為壓力太大,被打爆了,從而引發了多個問題
- zk腦裂:
- 我們多個服務向zk同一個節點注冊,注冊的升級為master節點,其他的為follower
- 但是事故發生時,zk服務不可用,master節點沒有感知到expired事件,因此認為自己仍是master
- 有一個follower服務感知到了master節點被刪除的事件,把自己提升為master,從此,集群有了兩個master,因此導致了整個集群的癱瘓。
- zk hang
- zk客戶端和服務端網絡不通暢的時候,服務端發出的expire事件并不能及時通知到客戶端,客戶端如果不能及時對connecting狀態做出反應,仍然向server拉節點,如果用同步API,就會造成hang,如果用異步API,operation_timeout的通知也會過很久(C客戶端上拉取節點超時的時間是三分之二的zktimeout時間)才返回。
- zk雪崩
- zk客戶端的邏輯是:重連之后會對所有節點重新watch, 如果zk不可用導致所有的zk連接expire,那么會導致所有的節點去server watch節點,驚群效應會導致zk壓力過大–>服務處理延遲過大–>導致client認為客戶端連接失敗–>zk客戶端重連–>連接失敗–>然后就會一直重連。無限循環
- Zookeeper中Session Timeout的那些事
參考鏈接
總結
以上是生活随笔為你收集整理的zookeeper简介以及C客户端用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈RDMA流控设计
- 下一篇: RDMA简介