本文作者:HelloGitHub-老荀
本文是 HelloZooKeeper 系列的最后一篇文章,接下來主要聊聊面試中如果被問到 ZooKeeper 的問題如何回答,也可以當作學完本系列的測試。
准備好了嗎?面試開始嘍~「首發於 HelloGitHub 公眾號」
一、模擬面試
終於來到重頭戲了,本小節我會從網上找到一些關於 ZK 的面試題進行剖析講解,並且站在面試官的基礎上分析考點,相信看完這一節,出去面試再碰到 ZK 相關的問題你便能披荊斬棘、所向披靡!
我先給大家模擬一個面試的場景:
面試官:我看你簡歷上用過 ZK,能給我介紹下嗎?你是怎么理解 ZK 的作用呢?
(如果你把百度百科中的定義背給他聽,我只能說 666,千萬別這樣,會被別人當成傻子。)
我:我的理解 ZK 是一個脫離於應用的第三方進程,類似的數據庫,消息隊列,Redis 等都是扮演這個角色,擁有一定的數據存儲和查詢能力,可以讓我們在現在都是分布式部署的應用之間“傳遞”數據,其次 ZK 支持的回調通知,讓應用可以在一些業務場景中感知到數據的變化並及時作出相應的反應。最后,ZK 本身也支持集群部署具有高可用的特點,是一個可靠的第三方中間件。
面試官:嗯,你剛剛提到了回調通知,能仔細跟我聊聊 ZK 是怎么去實現的嗎?
我:各種編程語言的客戶端都會對這個回調通知進行抽象,通常需要開發者聲明一個 callback 的對象,在 Java 的客戶端中這個接口是 Watcher
,ZK 服務端提供了一些方法,比如 getData
、exists
或者最新版本中的 addWatch
都可以用來向 ZK 注冊回調通知,而向服務端發送的回調通知,只會告訴服務端我當前的這個路徑需要被通知,服務端得知后,會在內存中記錄下來,路徑和客戶端之間的關系,客戶端自己也需要記錄下來,路徑和具體回調的關系。當被訂閱的路徑發生事件的時候,各種增刪改吧,服務端就會從內存中的記錄去查看有沒有需要通知的客戶端,有的話會發送一個通知的請求給客戶端,客戶端收到通知后,就會從本地的記錄中取出對應的回調對象去執行 callback 方法!
(實際情況,我覺得面試官可能不會讓你一直說下去,應該是互相聊的一個狀態)
面試官:嗯,說得挺詳細,那你剛剛提到的 getData
、exists
、 addWatch
三種注冊有什么區別嗎?
我:getData
、exists
以及 getChildren
注冊的通知都是一次性的,當服務端通知過一次后,就會刪除內存中的記錄,之后如果仍然需要通知的話,客戶端就要去繼續注冊,而 addWatch
注冊的回調通知是永久性的,只需要注冊一次可以一直被通知。
面試官:嗯好,你剛剛還提到了 ZK 有一定的數據存儲能力,你能說說 ZK 是怎么保存和整理數據的嗎?
我:ZK 的數據體現在兩部分。
面試官:哦?哪兩部分?
我:內存中和磁盤上。
面試官:那你先說說內存里 ZK 是怎么存儲數據
我:從邏輯上來講,ZK 內存中的數據其實是一個樹形結構,從 /
根節點開始,逐級向下用 /
分割,每一個節點下面還可以有多個子節點,就類似於 Unix 中的目錄結構,但在實際中,ZK 是使用一個 HashMap 去存儲整個樹形結構的數據的,key 是對應的全路徑字符串,value 則是一個節點對象,包含了節點的各種信息。
面試官:能說說你覺得為什么要這么設計嗎?
(其實我覺得一般面試官不會這么問,以下回答也是我個人的猜想)
我:首先 HashMap 查詢速度很快,是 Java 標准庫中一個非常重要的數據結構,在許多地方都有用到。ZK 本身並不需要排序或者是范圍求值的操作,所以 HashMap 完全可以滿足查詢的需求。至於為什么邏輯上要設計成樹形結構,父子節點,這個可能是因為這個結構和 Unix 文件系統很像,非常便於理解以及基於路徑進行數據的分類,而且最新的 ZK 中有一些功能是依賴了父子遞歸這個特性的(比如 addWatch
),如果是普通的 key-value 是無法滿足的。
面試官:嗯好,那你再說說磁盤上 ZK 是怎么存儲數據的呢?
我:ZK 在磁盤上規定了兩種文件類型,一種是 log 文件,一種是 snapshot。log 文件是增量記錄,負責對每一個寫請求進行保存,snapshot 文件是全量記錄,是對內存的快照。
面試官:ZK 是怎么保證內存中的數據和磁盤中的數據的一致性呢?
我:真正的強一致性,ZK 無法保證。對於每一次的寫請求,ZK 是采取先記錄磁盤再修改內存的,所以保證了如果出現意外的話,優先記錄磁盤可以盡可能的保證數據的完整。如果 ZK 是正常退出的話,也會強制刷磁盤文件和生成 snapshot,保證了一致性,但如果是非正常退出的話,極端情況下的一部分數據是會丟失的。
面試官:你剛剛也提到了 ZK 本身也可以集群部署的?能多聊一點嗎?
我:ZK 的配置文件 zoo.cfg
中可以配置其他節點的信息,各個節點通過 dataDir
目錄下的 myid
文件進行區分,不同節點之間可以相互通信,客戶端連上集群中的任意一個節點都可以進行通信。
面試官:ZK 集群中有幾種不同的角色?你知道嗎?
我:有 Leader、Follower、Observer 三種角色。
面試官:說說他們之間的區別吧
我:集群中有且只能有一個 Leader,Leader 負責對整個集群的寫請求事務進行提交,在一個集群選出 Leader 之前是無法對外提供服務的。Follower 和 Observer 都只能處理讀請求,區別是 Follower 有投票權可以參與 Leader 的競選,Observer 無法參與 Leader 的競選。
面試官:那你可以跟我講講,選舉 Leader 依靠哪些信息嗎?
我:每一個節點都會維護三個最重要的信息:epoch、zxid、myid。epoch 代表選舉的輪次,優先比較,如果相同則繼續比較下一級。zxid 代表本節點處理過的最大事務 ID,越大代表當前節點經手的寫請求越多,知道的也就越多,第二優先級比較,如果還相同則比較 myid,myid 整個集群中不能重復,所以最終一定能分出勝負。勝利的節點當選 Leader。
(准確的說,epoch 和 zxid 是一個字段,一個記錄在高 32 位,一個記錄在低 32 位)
面試官:不同節點之間怎么通信呢?怎么去進行選舉?
我:每一個 ZK 節點在啟動的時候,會通過讀取配置文件中的集群信息,與其他節點建立 Socket 連接,集群間的通信就是通過這個 Socket。每個節點選舉的時候都把自己認為的候選人信息廣播出去,同時也接收來自其他節點的候選人信息,通過比較后,失敗的一方會更改自己的候選人信息並重新進行廣播,反復直到某一個節點得到半數以上投票,選舉就完成了。
面試官:不同的節點角色,在處理讀寫請求上有什么不同嗎?你先聊聊 Leader 吧
我:好滴,Leader 作為集群中的老大,負責對收到的寫請求發起提案 PROPOSAL,告訴其他節點當前收到一個寫請求,其他節點收到后,會在本地進行歸檔,其實就是寫入文件輸出流,完畢后會發送一個 ACK 給 Leader,Leader 統計到半數以上的 ACK 之后會再次發送給其他節點一個 COMMIT,其他節點收到 COMMIT 之后就可以修改內存數據了。讀請求的話不需要提案直接查詢內存中的數據返回即可。
面試官:那 Follower 或 Observer 呢?
我:他們收到讀請求是一樣的,直接返回本地的內存數據即可。但是寫請求的話,會將當前請求轉發給 Leader,然后由 Leader 去處理,就和之前的流程是一樣的。
面試官:不同的請求 ZK 是如何保證順序呢?
我:這個順序的保證最終是落實在一個先進先出的隊列,優先進該隊列的請求會被先處理,所以能保證順序。
面試官:不同的客戶端的請求怎么保證順序呢?A 先發送了一個創建節點,在該請求返回之前,B 發送了一個查詢該節點,B 會阻塞到 A 執行完畢再查詢嗎?還是直接返回查詢不到節點?
我:B 會直接返回查不到。不同的客戶端之間的順序 ZK 不保證,原因是在底層 ZK 是通過一個 Map 去分別放置不同的客戶端的請求的,不同的客戶端的 key 是不一樣的,而這個 Map 的 value 則是我剛剛提到的先進先出的隊列。所以只有同一個客戶端的請求能被順序執行,不同的客戶端是無法保證的。
面試官:能說說不同的客戶端的 key 是什么嗎?怎么保證不同。
我:每一個客戶端在連接至 ZK 后會被分配一個 sessionId,這個 sessionId 是通過當前時間戳、節點的 myid 和一個遞增特性生成的一個 long 類型字段,可以保證不會重復。
面試官:說到 session,你知道 ZK 的會話是怎么維持的嗎?
我:你問的是客戶端和服務端之間的會話嗎?
面試官:是的,你能跟我說說嗎?
我:每一個客戶端在連接 ZK 的時候會同時上報自己的超時時間,加上剛剛的 sessionId,ZK 的服務端會在本地維護一個映射關系,通過計算可以計算出該 sessionId 的超時時間,並且 ZK 自己也有一個 tickTime
的配置,通過一個算法可以將不同客戶端不同超時間都映射到相同間隔的時間點上,再將這個超時時間和 sessionId 關系存起來。
面試官:映射到相同的時間點上有什么好處嗎?
我:這樣服務端在啟動后,后台會有一個線程,通過這個統一的時間間隔,取出 session 過期的客戶端,向他們發送會話過期的消息,極大的節約了性能。
面試官:客戶端是怎么去更新會話的超時時間呢?
我:首先客戶端的每次操作都會刷新這個超時時間,其次客戶端必須設計一個 PING 的操作,用於在客戶端空閑的時候主動去刷新會話超時時間,防止過期。
面試官:除了客戶端和服務端之間的會話,還有別的嗎?
我:服務端和服務端之間也有心跳,而且服務端的心跳是由 Leader 主動發起的,向其他節點發送 PING 請求,而其他節點收到 PING 后,需要把本地的會話信息一並發送給 Leader。
編不下去了,上面一些題具有我強烈的主觀偏好性,我覺得如果面試官是個菜雞的話,這些問題大部分都問不出來,所以重點是不在於我怎么回答,而是當你對背后的原理了然於胸時,自然是神擋殺神,佛擋殺佛。
我說說我認為比較重要的幾個特性:
- 回調通知,ZK 其他原理可以不懂,但是怎么用回調是肯定要知道的。
- 選舉,ZK 最具特色的一個屬性,基本都會問一下。
- 持久化,說清楚兩種文件的區別。
- 會話,會話的概念,以及怎么維持。
最后通過一個模擬面試回答了一下我認為 ZK 中比較有特點的面試問題,如果大家對面試問題還有什么疑問記得留言給我噢~必須給你們安排上!
二、網上真題
我大部分題目是網上直接搜的,網址在這里 ZooKeeper面試題(2020最新版)但是過濾了一些太 low 的題目。
我上面說了 Leader 在接受到寫請求后,會發起提案,然后等待其他節點的 ACK,這個 ACK 是要求半數以上通過才能繼續下去的,所以能收到半數以上的 ACK 說明集群中的一半以上都已經完成了本地磁盤的歸檔,自然是保證了主從之間的數據同步。
我之前的文章中有介紹現在 ZK 中有 7 種節點類型,關於新節點的原理我還沒來得及講,所以他如果這么問了你可以很官方的回答他:
- 持久節點
- 持久順序節點
- 臨時節點
- 臨時順序節點
他一般后面會接着問兩者的區別,臨時節點會隨着客戶端的會話斷開而自動刪除,原理就是在創建臨時節點的時候,服務端會維護一個 sessionId 和它對應的臨時節點路徑列表,當關閉會話時,把這個列表里的路徑都拿出來一一刪除即可。而順序節點的區別就在於 ZK 會自動為路徑加上數字的后綴,僅此而已。
並發創建時,順序節點怎么保證后綴數字唯一呢?
ZK 的請求是放入隊列里一個個處理的,所以其實並沒有所謂的並發,前一個請求處理完再處理下一個請求,自然就能保證后綴數字的唯一性了。
ZK 將權限分為兩大類,兩大類又能繼續細分:
- 客戶端的角色權限
- IP
- 用戶名密碼
- world,最寬泛的權限,也就是沒有權限
- super,特殊的用戶名密碼,相當於管理員權限
- 節點的數據權限
- Create,創建
- Delete,刪除
- Read,讀
- Write,寫
- ACL,讀寫權限
chroot 是 ZK 設計給客戶端的命名空間隔離,作為不同客戶端的根節點,由客戶端去維護,總的來說就是發送請求之前把 chroot 的路徑拼接上,再去請求服務端。chroot 對於服務端是透明的,完全不知道的。
Learner 和 Leader 之間同步數據是一個比較漫長和復雜的過程,總的來說可以大致分為以下步驟:
- Learner 上報自己的信息給 Leader
- Leader 根據 Learner 信息決定使用何種同步方法
- DIFF,直接從最近的 500 個提案中恢復數據,直接發送提案即可
- TRUNC,通常出現於 Learner 是前 Leader,需要降級自己的數據達到和 Leader 一致
- SNAP,Leader 直接發送整個內存快照給 Follower
- Leader 和 Learner 開始同步
- 同步完成后開始對外提供服務
三、配置大全
托大家的福,我把 ZK 的源碼全部(爆肝)瀏覽了一遍,找到了至少 99% 的配置選項,ZK 的配置大致可以分為 3 種:
- 啟動命令行傳入的參數
zoo.cfg
配置文件中的參數- 當前環境變量中的參數
3.1 命令行參數
命令行參數很少,而且沒有對應的配置名稱,這里我簡單介紹下:
單機版只支持兩種形式的命令行傳參
- 客戶端監聽端口加 data 目錄,上一節源碼調試中用的就是這一個形式,例如:
2181 /your/zk/data/path
- 或者只傳一個參數,
zoo.cfg
的路徑,例如:/your/zoocfg/path
集群版更簡單只支持 zoo.cfg
的路徑一個參數
3.2 zoo.cfg 文件中的配置
我仔細查看源碼的時候發現有些配置實際作用時需要計算又或者是一魚兩吃,被多個地方使用,所以很難一步到位的講清楚,所以下面的介紹僅供參考,配置項加星號(*)的是我未來打算開篇講解的。
配置項 | 默認值(單位) | 介紹 |
---|---|---|
dataDir | /tmp/zookeeper | 存放 snapshot、myid 文件路徑 |
clientPort | 2181 | 監聽客戶端請求端口 |
tickTime | 2000(毫秒) | 影響客戶端會話檢查間隔、服務端之間心跳間隔 |
syncLimit | 5 | tickTime * syncLimit 決定了服務端心跳超時時間 |
initLimit | 10 | tickTime * initLimit 決定了 ACK 的超時時間 |
dataLogDir | 和 dataDir 一致 | 存放 log 文件路徑 |
minSessionTimeout | tickTime * 2 | 客戶端的超時時間最小值 |
maxSessionTimeout | tickTime * 20 | 客戶端的超時時間最大值 |
electionAlg | 3 | 選舉算法(1,2 已被廢棄) |
localSessionsEnabled* | false | 啟用本地會話 |
localSessionsUpgradingEnabled* | false | 本地會話可以升級成全局會話 |
clientPortAddress | - | 客戶端的 host 要求,不配置的話可以接受任意發向 2181 的請求 |
secureClientPort | - | SSL 安全端口號 |
secureClientPortAddress | - | SSL 安全 host |
observerMasterPort* | - | 使 Observer 通過 Follower 去了解集群中的選舉情況 |
clientPortListenBacklog | 50 | TCP 服務端用於臨時存放已完成三次握手的請求的隊列的最大長度 |
maxClientCnxns | 60 | 客戶端最大連接數 |
connectToLearnerMasterLimit | 0 | 決定了 Follower 連接 Leader 的超時時間 |
quorumListenOnAllIPs | false | 服務端是否接受來自任意 IP 地址的請求 |
peerType | - | 選項 observer / participant,決定節點角色 |
syncEnabled | true | Learner 是否需要本地持久化文件 |
dynamicConfigFile* | - | 動態配置路徑 |
autopurge.snapRetainCount | 3 | 保留多少個最新的 snapshot 文件 |
autopurge.purgeInterval | 0(小時) | 間隔多久進行一次 snapshot 的清理 |
standaloneEnabled | true | 是否允許單機模式啟動 |
reconfigEnabled* | false | 是否允許動態配置 |
sslQuorum | false | 集群間是否使用 SSL 通信 |
portUnification | false | 是否允許不安全連接 |
sslQuorumReloadCertFiles | false | 啟用密鑰更新時自動加載 |
quorum.auth.enableSasl | false | 啟用集群間 SASL 鑒權 |
quorum.auth.serverRequireSasl | false | |
quorum.auth.learnerRequireSasl | false | |
quorum.auth.learner.saslLoginContext | QuorumLearner | |
quorum.auth.server.saslLoginContext | QuorumServer | |
quorum.auth.kerberos.servicePrincipal | zkquorum/localhost | |
quorum.cnxn.threads.size | 20 | 集群間異步建立連接線程池最大線程數 |
jvm.pause.info-threshold.ms | 1000(毫秒) | INFO 輸出暫停統計閾值 |
jvm.pause.warn-threshold.ms | 10000(毫秒) | WARN 輸出暫停統計閾值 |
jvm.pause.sleep.time.ms | 500(毫秒) | JVM 暫停統計線程 sleep 間隔 |
jvm.pause.monitor* | false | 是否啟用 JVM 暫停統計 |
metricsProvider.className* | DefaultMetricsProvider(全路徑) | 統計實現類路徑 |
multiAddress.enabled | false | |
multiAddress.reachabilityCheckTimeoutMs | 1000(毫秒) | |
multiAddress.reachabilityCheckEnabled | true | |
(以開頭)server.* | 集群配置 | |
(以開頭)group* | 分組配置 | |
(以開頭)weight* | 權重 | |
(以開頭)metricsProvider.* | 自定義的統計配置 |
以上就是 3.6.2 中 zoo.cfg
所有的官方配置選項了
3.3 環境變量配置
Java 程序想要指定環境變量有兩種方法:
- 只需要在啟動的時候在后面加上
-DpropertyKey=propertyValue
即可 - ZK 還支持一種簡單的方式就是在
zoo.cfg
中直接指定(指定時不需要寫zookeeper.
的前綴)。只要不是在上面 2.2 中 ZK 自己定義的配置項里,ZK 啟動的時候讀取這些配置會自動幫他們添加zookeeper.
前綴並加入當前環境變量中
如果該配置是 follower.nodelay
,就只能用第一種方式添加環境變量了。
讓我們也來看看 ZK 自己定義了哪些環境變量配置吧
配置項 | 默認值 | 配置 |
---|---|---|
zookeeper.server.realm* | - | 客戶端配置 |
zookeeper.clientCnxnSocket | ClientCnxnSocketNIO(全路徑) | 客戶端配置,通信的實現類 |
zookeeper.client.secure | true | 客戶端配置 |
zookeeper.request.timeout | 0 | 客戶端配置,異步 API 超時時間 |
zookeeper.server.principal | - | 客戶端配置 |
zookeeper.sasl.client.username | zookeeper | 客戶端配置 |
zookeeper.sasl.client.canonicalize.hostname | true | 客戶端配置 |
zookeeper.disableAutoWatchReset | false | 客戶端配置,會話超時自動清空 watcher |
zookeeper.sasl.clientconfig | - | |
zookeeper.sasl.client | true | 啟用 SASL |
zookeeper.ssl(.quorum).authProvider | x509 | SSL 實現類,加 quorum 的是服務端的配置,下同 |
zookeeper.ssl(.quorum).protocol | TLSv1.2 | |
zookeeper.ssl(.quorum).enabledProtocols | - | |
zookeeper.ssl(.quorum).ciphersuites | 根據不同的 jvm 版本 | |
zookeeper.ssl(.quorum).keyStore.location | - | |
zookeeper.ssl(.quorum).keyStore.password | - | |
zookeeper.ssl(.quorum).keyStore.type | - | |
zookeeper.ssl(.quorum).trustStore.location | - | |
zookeeper.ssl(.quorum).trustStore.password | - | |
zookeeper.ssl(.quorum).trustStore.type | - | |
zookeeper.ssl(.quorum).context.supplier.class | - | |
zookeeper.ssl(.quorum).hostnameVerification | true | |
zookeeper.ssl(.quorum).crl | false | |
zookeeper.ssl(.quorum).ocsp | false | |
zookeeper.ssl(.quorum).clientAuth | - | |
zookeeper.ssl(.quorum).handshakeDetectionTimeoutMillis | 5000(毫秒) | |
zookeeper.kinit | /usr/bin/kinit | |
zookeeper.jmx.log4j.disable | false | 禁用 jmx log4j |
zookeeper.admin.enableServer* | true | 是否啟用 Admin Server |
zookeeper.admin.serverAddress* | 0.0.0.0 | |
zookeeper.admin.serverPort* | 8080 | |
zookeeper.admin.idleTimeout* | 30000 | |
zookeeper.admin.commandURL* | /commands | |
zookeeper.admin.httpVersion* | 11 | |
zookeeper.admin.portUnification | false | |
zookeeper.DigestAuthenticationProvider.superDigest | - | 管理員賬號密碼 |
zookeeper.ensembleAuthName | - | |
zookeeper.requireKerberosConfig | - | |
zookeeper.security.auth_to_local | DEFAULT | |
(以開頭)zookeeper.authProvider.* | - | 自定義 scheme 校驗規則 |
zookeeper.letAnySaslUserDoX | - | |
zookeeper.SASLAuthenticationProvider.superPassword | - | |
zookeeper.kerberos.removeHostFromPrincipal | - | |
zookeeper.kerberos.removeRealmFromPrincipal | - | |
zookeeper.X509AuthenticationProvider.superUser | - | |
zookeeper.4lw.commands.whitelist* | - | 四字命令白名單 |
zookeeper.preAllocSize | 65536 * 1024 | |
zookeeper.forceSync | yes | |
zookeeper.fsync.warningthresholdms | 1000(毫秒) | fsync 告警閾值 |
zookeeper.txnLogSizeLimitInKb | -1(KB) | log 文件大小 |
zookeeper.datadir.autocreate | true | data 目錄自動創建 |
zookeeper.db.autocreate | true | |
zookeeper.snapshot.trust.empty | false | 不信任空的 snapshot 文件 |
zookeeper.snapshot.compression.method | 空字符串 | snapshot 文件壓縮實現 |
zookeeper.commitProcessor.numWorkerThreads | CPU 核心數 | |
zookeeper.commitProcessor.shutdownTimeout | 5000(毫秒) | |
zookeeper.commitProcessor.maxReadBatchSize | -1 | |
zookeeper.commitProcessor.maxCommitBatchSize | 1 | |
zookeeper.fastleader.minNotificationInterval | 200(毫秒) | 收集選票超時時間(初始) |
zookeeper.fastleader.maxNotificationInterval | 60000(毫秒) | 收集選票超時時間(最大) |
zookeeper.leader.maxTimeToWaitForEpoch | -1 | |
zookeeper.leader.ackLoggingFrequency | 1000 | |
zookeeper.testingonly.initialZxid | - | 初始化 zxid,僅供測試! |
zookeeper.leaderConnectDelayDuringRetryMs | 100 | Leaner 連接 Leader 超時時間 |
follower.nodelay | true | 設置 TCP no delay |
zookeeper.forceSnapshotSync | false | Learner 強制使用 snapshot 和 Leader 進行同步 |
zookeeper.leader.maxConcurrentSnapSyncs | 10 | |
zookeeper.leader.maxConcurrentDiffSyncs | 100 | |
zookeeper.observer.reconnectDelayMs | 0(毫秒) | Observer 延遲重連至 Leader |
zookeeper.observer.election.DelayMs | 200(毫秒) | Observer 延遲開始選舉 |
zookeeper.observerMaster.sizeLimit | 32 * 1024 * 1024 | |
zookeeper.electionPortBindRetry | 3 | 選舉端口連接重試次數 |
zookeeper.tcpKeepAlive | false | Socket keep alive 設置 |
zookeeper.cnxTimeout | 5000(毫秒) | Socket 超時時間 |
zookeeper.multiAddress.enabled | false | |
zookeeper.multiAddress.reachabilityCheckTimeoutMs | 1000(毫秒) | |
zookeeper.multiAddress.reachabilityCheckEnabled | true | |
zookeeper.quorumCnxnTimeoutMs | -1 | |
zookeeper.observer.syncEnabled | true | Observer 是否需要本地歸檔 |
zookeeper.bitHashCacheSize | 10 | 位圖初始緩存大小 |
zookeeper.messageTracker.BufferSize | 10 | |
zookeeper.messageTracker.Enabled | false | |
zookeeper.pathStats.slotCapacity | 60 | |
zookeeper.pathStats.slotDuration | 15 | |
zookeeper.pathStats.maxDepth | 6 | |
zookeeper.pathStats.sampleRate | 0.1 | |
zookeeper.pathStats.initialDelay | 5 | |
zookeeper.pathStats.delay | 5 | |
zookeeper.pathStats.topPathMax | 20 | |
zookeeper.pathStats.enabled | false | |
zookeeper.watcherCleanThreshold | 1000 | |
zookeeper.watcherCleanIntervalInSeconds | 600 | |
zookeeper.watcherCleanThreadsNum | 2 | |
zookeeper.maxInProcessingDeadWatchers | -1 | |
zookeeper.watchManagerName | WatchManager(全路徑) | |
zookeeper.connection_throttle_tokens | 0 | |
zookeeper.connection_throttle_fill_time | 1 | |
zookeeper.connection_throttle_fill_count | 1 | |
zookeeper.connection_throttle_freeze_time | -1 | |
zookeeper.connection_throttle_drop_increase | 0.02 | |
zookeeper.connection_throttle_drop_decrease | 0.002 | |
zookeeper.connection_throttle_decrease_ratio | 0 | |
zookeeper.connection_throttle_weight_enabled | false | |
zookeeper.connection_throttle_global_session_weight | 3 | |
zookeeper.connection_throttle_local_session_weight | 1 | |
zookeeper.connection_throttle_renew_session_weight | 2 | |
zookeeper.extendedTypesEnabled* | false | 是否啟用 TTL 節點類型 |
zookeeper.emulate353TTLNodes* | false | 是否兼容 3.5.3 的 TTL |
zookeeper.client.portUnification | false | |
zookeeper.netty.server.outstandingHandshake.limit | -1 | |
zookeeper.netty.advancedFlowControl.enabled | false | |
zookeeper.nio.sessionlessCnxnTimeout | 10000(毫秒) | |
zookeeper.nio.numSelectorThreads | CPU 核心數 / 2 再開方 | |
zookeeper.nio.numWorkerThreads | CPU 核心數 * 2 | |
zookeeper.nio.directBufferBytes | 64 * 1024(字節) | |
zookeeper.nio.shutdownTimeout | 5000(毫秒) | |
zookeeper.request_stale_connection_check | true | |
zookeeper.request_stale_latency_check | false | |
zookeeper.request_throttler.shutdownTimeout | 10000(毫秒) | |
zookeeper.request_throttle_max_requests | 0 | |
zookeeper.request_throttle_stall_time | 100 | |
zookeeper.request_throttle_drop_stale | true | |
zookeeper.serverCnxnFactory | NIOServerCnxnFactory(全路徑) | |
zookeeper.maxCnxns | 0 | |
zookeeper.snapshotSizeFactor | 0.33 | |
zookeeper.commitLogCount | 500 | |
zookeeper.sasl.serverconfig | Server | |
zookeeper.globalOutstandingLimit | 1000 | |
zookeeper.enableEagerACLCheck | false | |
zookeeper.skipACL | no | |
zookeeper.allowSaslFailedClients | false | |
zookeeper.sessionRequireClientSASLAuth | false | |
zookeeper.digest.enabled | true | |
zookeeper.closeSessionTxn.enabled | true | |
zookeeper.flushDelay | 0 | |
zookeeper.maxWriteQueuePollTime | zookeeper.flushDelay / 3 | |
zookeeper.maxBatchSize | 1000 | |
zookeeper.intBufferStartingSizeBytes | 1024 | |
zookeeper.maxResponseCacheSize | 400 | |
zookeeper.maxGetChildrenResponseCacheSize | 400 | |
zookeeper.snapCount | 100000 | |
zookeeper.snapSizeLimitInKb | 4194304(千字節) | |
zookeeper.largeRequestMaxBytes | 100 * 1024 * 1024 | |
zookeeper.largeRequestThreshold | -1 | |
zookeeper.superUser | - | |
zookeeper.audit.enable | false | 是否啟用 audit 日志 |
zookeeper.audit.impl.class | Log4jAuditLogger(全路徑) | audit 日志功能實現類 |
ZK 的配置還是很多的,有些我這里 TODO 了,以后有機會和大家詳細介紹下~而且相當一部分的配置 ZK 官方的文檔中已經給出了解釋,可以查看 ZK 3.6.2 配置文檔。
我這里還要吐槽下,ZK 中有些配置是用 true 或者 false,有些使用 yes 或者 no,明顯是兩個(波)人開發的,這種不應該做一個統一嗎?yes 或 no 真的很多余...
四、系列結語
感謝你們能看到這里,陪伴這個系列從開始到現在!這個項目從有想法立項到之后跟蛋蛋溝通,再到正式開始編寫,到最后我寫下這段結語,大概經歷了三個多月(你們看到的時候應該是更晚),現在回頭再看之前寫的東西,感慨頗深。
(截圖來自-B 站何同學的視頻)
如果以我自己的自控能力,這玩意自己搞,搞着搞着可能就涼了,在此感謝蛋蛋給予我的幫助和鼓勵。關於 ZK 我的確之前有研究過一段時間,但是以現在的眼光看,當時的研究其實也就是皮毛而已(可能現在也還是),很多東西是我這次整理時現學的,收獲非常多,最直觀的感受就是,我以后出去面試不會再害怕 ZK 相關的問題了。
感謝大家這 3 個月的陪伴,本系列終結嘍!如果還有什么想學的開源框架和技術可以留言告訴我們,后續繼續為大家安排免費的干貨教程。
最最后,來個大大的贊吧!
關注 HelloGitHub 公眾號 收到第一時間的更新。
還有更多開源項目的介紹和寶藏項目等待你的發掘。