最后一篇:面试遇到 ZK 的问题,横趟!
作者:HelloGitHub-老荀
本文是 HelloZooKeeper 系列的最后一篇文章,接下來主要聊聊面試中如果被問到 ZooKeeper 的問題如何回答,也可以當作學完本系列的測試。
準備好了嗎?面試開始嘍~
一、模擬面試
終于來到重頭戲了,本小節(jié)我會從網(wǎng)上找到一些關于 ZK 的面試題進行剖析講解,并且站在面試官的基礎上分析考點,相信看完這一節(jié),出去面試再碰到 ZK 相關的問題你便能披荊斬棘、所向披靡!
我先給大家模擬一個面試的場景:
面試官:我看你簡歷上用過 ZK,能給我介紹下嗎?你是怎么理解 ZK 的作用呢?
(如果你把百度百科中的定義背給他聽,我只能說 666,千萬別這樣,會被別人當成傻子。)
我:我的理解 ZK 是一個脫離于應用的第三方進程,類似的數(shù)據(jù)庫,消息隊列,Redis 等都是扮演這個角色,擁有一定的數(shù)據(jù)存儲和查詢能力,可以讓我們在現(xiàn)在都是分布式部署的應用之間“傳遞”數(shù)據(jù),其次 ZK 支持的回調(diào)通知,讓應用可以在一些業(yè)務場景中感知到數(shù)據(jù)的變化并及時作出相應的反應。最后,ZK 本身也支持集群部署具有高可用的特點,是一個可靠的第三方中間件。
面試官:嗯,你剛剛提到了回調(diào)通知,能仔細跟我聊聊 ZK 是怎么去實現(xiàn)的嗎?
我:各種編程語言的客戶端都會對這個回調(diào)通知進行抽象,通常需要開發(fā)者聲明一個 callback 的對象,在 Java 的客戶端中這個接口是 Watcher,ZK 服務端提供了一些方法,比如 getData、exists 或者最新版本中的 addWatch 都可以用來向 ZK 注冊回調(diào)通知,而向服務端發(fā)送的回調(diào)通知,只會告訴服務端我當前的這個路徑需要被通知,服務端得知后,會在內(nèi)存中記錄下來,路徑和客戶端之間的關系,客戶端自己也需要記錄下來,路徑和具體回調(diào)的關系。當被訂閱的路徑發(fā)生事件的時候,各種增刪改吧,服務端就會從內(nèi)存中的記錄去查看有沒有需要通知的客戶端,有的話會發(fā)送一個通知的請求給客戶端,客戶端收到通知后,就會從本地的記錄中取出對應的回調(diào)對象去執(zhí)行 callback 方法!
(實際情況,我覺得面試官可能不會讓你一直說下去,應該是互相聊的一個狀態(tài))
面試官:嗯,說得挺詳細,那你剛剛提到的 getData、exists、 addWatch 三種注冊有什么區(qū)別嗎?
我:getData、exists 以及 getChildren 注冊的通知都是一次性的,當服務端通知過一次后,就會刪除內(nèi)存中的記錄,之后如果仍然需要通知的話,客戶端就要去繼續(xù)注冊,而 addWatch 注冊的回調(diào)通知是永久性的,只需要注冊一次可以一直被通知。
面試官:嗯好,你剛剛還提到了 ZK 有一定的數(shù)據(jù)存儲能力,你能說說 ZK 是怎么保存和整理數(shù)據(jù)的嗎?
我:ZK 的數(shù)據(jù)體現(xiàn)在兩部分。
面試官:哦?哪兩部分?
我:內(nèi)存中和磁盤上。
面試官:那你先說說內(nèi)存里 ZK 是怎么存儲數(shù)據(jù)
我:從邏輯上來講,ZK 內(nèi)存中的數(shù)據(jù)其實是一個樹形結構,從 / 根節(jié)點開始,逐級向下用 / 分割,每一個節(jié)點下面還可以有多個子節(jié)點,就類似于 Unix 中的目錄結構,但在實際中,ZK 是使用一個 HashMap 去存儲整個樹形結構的數(shù)據(jù)的,key 是對應的全路徑字符串,value 則是一個節(jié)點對象,包含了節(jié)點的各種信息。
面試官:能說說你覺得為什么要這么設計嗎?
(其實我覺得一般面試官不會這么問,以下回答也是我個人的猜想)
我:首先 HashMap 查詢速度很快,是 Java 標準庫中一個非常重要的數(shù)據(jù)結構,在許多地方都有用到。ZK 本身并不需要排序或者是范圍求值的操作,所以 HashMap 完全可以滿足查詢的需求。至于為什么邏輯上要設計成樹形結構,父子節(jié)點,這個可能是因為這個結構和 Unix 文件系統(tǒng)很像,非常便于理解以及基于路徑進行數(shù)據(jù)的分類,而且最新的 ZK 中有一些功能是依賴了父子遞歸這個特性的(比如 addWatch),如果是普通的 key-value 是無法滿足的。
面試官:嗯好,那你再說說磁盤上 ZK 是怎么存儲數(shù)據(jù)的呢?
我:ZK 在磁盤上規(guī)定了兩種文件類型,一種是 log 文件,一種是 snapshot。log 文件是增量記錄,負責對每一個寫請求進行保存,snapshot 文件是全量記錄,是對內(nèi)存的快照。
面試官:ZK 是怎么保證內(nèi)存中的數(shù)據(jù)和磁盤中的數(shù)據(jù)的一致性呢?
我:真正的強一致性,ZK 無法保證。對于每一次的寫請求,ZK 是采取先記錄磁盤再修改內(nèi)存的,所以保證了如果出現(xiàn)意外的話,優(yōu)先記錄磁盤可以盡可能的保證數(shù)據(jù)的完整。如果 ZK 是正常退出的話,也會強制刷磁盤文件和生成 snapshot,保證了一致性,但如果是非正常退出的話,極端情況下的一部分數(shù)據(jù)是會丟失的。
面試官:你剛剛也提到了 ZK 本身也可以集群部署的?能多聊一點嗎?
我:ZK 的配置文件 zoo.cfg 中可以配置其他節(jié)點的信息,各個節(jié)點通過 dataDir 目錄下的 myid 文件進行區(qū)分,不同節(jié)點之間可以相互通信,客戶端連上集群中的任意一個節(jié)點都可以進行通信。
面試官:ZK 集群中有幾種不同的角色?你知道嗎?
我:有 Leader、Follower、Observer 三種角色。
面試官:說說他們之間的區(qū)別吧
我:集群中有且只能有一個 Leader,Leader 負責對整個集群的寫請求事務進行提交,在一個集群選出 Leader 之前是無法對外提供服務的。Follower 和 Observer 都只能處理讀請求,區(qū)別是 Follower 有投票權可以參與 Leader 的競選,Observer 無法參與 Leader 的競選。
面試官:那你可以跟我講講,選舉 Leader 依靠哪些信息嗎?
我:每一個節(jié)點都會維護三個最重要的信息:epoch、zxid、myid。epoch 代表選舉的輪次,優(yōu)先比較,如果相同則繼續(xù)比較下一級。zxid 代表本節(jié)點處理過的最大事務 ID,越大代表當前節(jié)點經(jīng)手的寫請求越多,知道的也就越多,第二優(yōu)先級比較,如果還相同則比較 myid,myid 整個集群中不能重復,所以最終一定能分出勝負。勝利的節(jié)點當選 Leader。
(準確的說,epoch 和 zxid 是一個字段,一個記錄在高 32 位,一個記錄在低 32 位)
面試官:不同節(jié)點之間怎么通信呢?怎么去進行選舉?
我:每一個 ZK 節(jié)點在啟動的時候,會通過讀取配置文件中的集群信息,與其他節(jié)點建立 Socket 連接,集群間的通信就是通過這個 Socket。每個節(jié)點選舉的時候都把自己認為的候選人信息廣播出去,同時也接收來自其他節(jié)點的候選人信息,通過比較后,失敗的一方會更改自己的候選人信息并重新進行廣播,反復直到某一個節(jié)點得到半數(shù)以上投票,選舉就完成了。
面試官:不同的節(jié)點角色,在處理讀寫請求上有什么不同嗎?你先聊聊 Leader 吧
我:好滴,Leader 作為集群中的老大,負責對收到的寫請求發(fā)起提案 PROPOSAL,告訴其他節(jié)點當前收到一個寫請求,其他節(jié)點收到后,會在本地進行歸檔,其實就是寫入文件輸出流,完畢后會發(fā)送一個 ACK 給 Leader,Leader 統(tǒng)計到半數(shù)以上的 ACK 之后會再次發(fā)送給其他節(jié)點一個 COMMIT,其他節(jié)點收到 COMMIT 之后就可以修改內(nèi)存數(shù)據(jù)了。讀請求的話不需要提案直接查詢內(nèi)存中的數(shù)據(jù)返回即可。
面試官:那 Follower 或 Observer 呢?
我:他們收到讀請求是一樣的,直接返回本地的內(nèi)存數(shù)據(jù)即可。但是寫請求的話,會將當前請求轉發(fā)給 Leader,然后由 Leader 去處理,就和之前的流程是一樣的。
面試官:不同的請求 ZK 是如何保證順序呢?
我:這個順序的保證最終是落實在一個先進先出的隊列,優(yōu)先進該隊列的請求會被先處理,所以能保證順序。
面試官:不同的客戶端的請求怎么保證順序呢?A 先發(fā)送了一個創(chuàng)建節(jié)點,在該請求返回之前,B 發(fā)送了一個查詢該節(jié)點,B 會阻塞到 A 執(zhí)行完畢再查詢嗎?還是直接返回查詢不到節(jié)點?
我:B 會直接返回查不到。不同的客戶端之間的順序 ZK 不保證,原因是在底層 ZK 是通過一個 Map 去分別放置不同的客戶端的請求的,不同的客戶端的 key 是不一樣的,而這個 Map 的 value 則是我剛剛提到的先進先出的隊列。所以只有同一個客戶端的請求能被順序執(zhí)行,不同的客戶端是無法保證的。
面試官:能說說不同的客戶端的 key 是什么嗎?怎么保證不同。
我:每一個客戶端在連接至 ZK 后會被分配一個 sessionId,這個 sessionId 是通過當前時間戳、節(jié)點的 myid 和一個遞增特性生成的一個 long 類型字段,可以保證不會重復。
面試官:說到 session,你知道 ZK 的會話是怎么維持的嗎?
我:你問的是客戶端和服務端之間的會話嗎?
面試官:是的,你能跟我說說嗎?
我:每一個客戶端在連接 ZK 的時候會同時上報自己的超時時間,加上剛剛的 sessionId,ZK 的服務端會在本地維護一個映射關系,通過計算可以計算出該 sessionId 的超時時間,并且 ZK 自己也有一個 tickTime 的配置,通過一個算法可以將不同客戶端不同超時間都映射到相同間隔的時間點上,再將這個超時時間和 sessionId 關系存起來。
面試官:映射到相同的時間點上有什么好處嗎?
我:這樣服務端在啟動后,后臺會有一個線程,通過這個統(tǒng)一的時間間隔,取出 session 過期的客戶端,向他們發(fā)送會話過期的消息,極大的節(jié)約了性能。
面試官:客戶端是怎么去更新會話的超時時間呢?
我:首先客戶端的每次操作都會刷新這個超時時間,其次客戶端必須設計一個 PING 的操作,用于在客戶端空閑的時候主動去刷新會話超時時間,防止過期。
面試官:除了客戶端和服務端之間的會話,還有別的嗎?
我:服務端和服務端之間也有心跳,而且服務端的心跳是由 Leader 主動發(fā)起的,向其他節(jié)點發(fā)送 PING 請求,而其他節(jié)點收到 PING 后,需要把本地的會話信息一并發(fā)送給 Leader。
編不下去了,上面一些題具有我強烈的主觀偏好性,我覺得如果面試官是個菜雞的話,這些問題大部分都問不出來,所以重點是不在于我怎么回答,而是當你對背后的原理了然于胸時,自然是神擋殺神,佛擋殺佛。
我說說我認為比較重要的幾個特性:
回調(diào)通知,ZK 其他原理可以不懂,但是怎么用回調(diào)是肯定要知道的。
選舉,ZK 最具特色的一個屬性,基本都會問一下。
持久化,說清楚兩種文件的區(qū)別。
會話,會話的概念,以及怎么維持。
最后通過一個模擬面試回答了一下我認為 ZK 中比較有特點的面試問題,如果大家對面試問題還有什么疑問記得留言給我噢~必須給你們安排上!
二、網(wǎng)上真題
我大部分題目是網(wǎng)上直接搜的 ZooKeeper面試題(2020最新版)但是過濾了一些太 low 的題目。真題保留如下:
4. ZooKeeper 怎么保證主從節(jié)點的狀態(tài)同步?
我上面說了 Leader 在接受到寫請求后,會發(fā)起提案,然后等待其他節(jié)點的 ACK,這個 ACK 是要求半數(shù)以上通過才能繼續(xù)下去的,所以能收到半數(shù)以上的 ACK 說明集群中的一半以上都已經(jīng)完成了本地磁盤的歸檔,自然是保證了主從之間的數(shù)據(jù)同步。
5. 四種類型的數(shù)據(jù)節(jié)點 Znode
我之前的文章中有介紹現(xiàn)在 ZK 中有 7 種節(jié)點類型,關于新節(jié)點的原理我還沒來得及講,所以他如果這么問了你可以很官方的回答他:
持久節(jié)點
持久順序節(jié)點
臨時節(jié)點
臨時順序節(jié)點
他一般后面會接著問兩者的區(qū)別,臨時節(jié)點會隨著客戶端的會話斷開而自動刪除,原理就是在創(chuàng)建臨時節(jié)點的時候,服務端會維護一個 sessionId 和它對應的臨時節(jié)點路徑列表,當關閉會話時,把這個列表里的路徑都拿出來一一刪除即可。而順序節(jié)點的區(qū)別就在于 ZK 會自動為路徑加上數(shù)字的后綴,僅此而已。
并發(fā)創(chuàng)建時,順序節(jié)點怎么保證后綴數(shù)字唯一呢?
ZK 的請求是放入隊列里一個個處理的,所以其實并沒有所謂的并發(fā),前一個請求處理完再處理下一個請求,自然就能保證后綴數(shù)字的唯一性了。
10. ACL 權限控制機制
ZK 將權限分為兩大類,兩大類又能繼續(xù)細分:
客戶端的角色權限
IP
用戶名密碼
world,最寬泛的權限,也就是沒有權限
super,特殊的用戶名密碼,相當于管理員權限
節(jié)點的數(shù)據(jù)權限
Create,創(chuàng)建
Delete,刪除
Read,讀
Write,寫
ACL,讀寫權限
11. Chroot 特性
chroot 是 ZK 設計給客戶端的命名空間隔離,作為不同客戶端的根節(jié)點,由客戶端去維護,總的來說就是發(fā)送請求之前把 chroot 的路徑拼接上,再去請求服務端。chroot 對于服務端是透明的,完全不知道的。
15. 數(shù)據(jù)同步
Learner 和 Leader 之間同步數(shù)據(jù)是一個比較漫長和復雜的過程,總的來說可以大致分為以下步驟:
Learner 上報自己的信息給 Leader
Leader 根據(jù) Learner 信息決定使用何種同步方法
DIFF,直接從最近的 500 個提案中恢復數(shù)據(jù),直接發(fā)送提案即可
TRUNC,通常出現(xiàn)于 Learner 是前 Leader,需要降級自己的數(shù)據(jù)達到和 Leader 一致
SNAP,Leader 直接發(fā)送整個內(nèi)存快照給 Follower
Leader 和 Learner 開始同步
同步完成后開始對外提供服務
三、配置大全
托大家的福,我把 ZK 的源碼全部(爆肝)瀏覽了一遍,找到了至少 99% 的配置選項,ZK 的配置大致可以分為 3 種:
啟動命令行傳入的參數(shù)
zoo.cfg 配置文件中的參數(shù)
當前環(huán)境變量中的參數(shù)
3.1 命令行參數(shù)
命令行參數(shù)很少,而且沒有對應的配置名稱,這里我簡單介紹下:
單機版只支持兩種形式的命令行傳參
客戶端監(jiān)聽端口加 data 目錄,上一節(jié)源碼調(diào)試中用的就是這一個形式,例如: 2181 /your/zk/data/path
或者只傳一個參數(shù),zoo.cfg 的路徑,例如:/your/zoocfg/path
集群版更簡單只支持 zoo.cfg 的路徑一個參數(shù)
3.2 zoo.cfg 文件中的配置
我仔細查看源碼的時候發(fā)現(xiàn)有些配置實際作用時需要計算又或者是一魚兩吃,被多個地方使用,所以很難一步到位的講清楚,所以下面的介紹僅供參考,配置項加星號(*)的是我未來打算開篇講解的。
| dataDir | /tmp/zookeeper | 存放 snapshot、myid 文件路徑 |
| clientPort | 2181 | 監(jiān)聽客戶端請求端口 |
| 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 要求,不配置的話可以接受任意發(fā)向 2181 的請求 |
| secureClientPort | - | SSL 安全端口號 |
| secureClientPortAddress | - | SSL 安全 host |
| observerMasterPort* | - | 使 Observer 通過 Follower 去了解集群中的選舉情況 |
| clientPortListenBacklog | 50 | TCP 服務端用于臨時存放已完成三次握手的請求的隊列的最大長度 |
| maxClientCnxns | 60 | 客戶端最大連接數(shù) |
| connectToLearnerMasterLimit | 0 | 決定了 Follower 連接 Leader 的超時時間 |
| quorumListenOnAllIPs | false | 服務端是否接受來自任意 IP 地址的請求 |
| peerType | - | 選項 observer / participant,決定節(jié)點角色 |
| syncEnabled | true | Learner 是否需要本地持久化文件 |
| dynamicConfigFile* | - | 動態(tài)配置路徑 |
| autopurge.snapRetainCount | 3 | 保留多少個最新的 snapshot 文件 |
| autopurge.purgeInterval | 0(小時) | 間隔多久進行一次 snapshot 的清理 |
| standaloneEnabled | true | 是否允許單機模式啟動 |
| reconfigEnabled* | false | 是否允許動態(tài)配置 |
| 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 | 集群間異步建立連接線程池最大線程數(shù) |
| jvm.pause.info-threshold.ms | 1000(毫秒) | INFO 輸出暫停統(tǒng)計閾值 |
| jvm.pause.warn-threshold.ms | 10000(毫秒) | WARN 輸出暫停統(tǒng)計閾值 |
| jvm.pause.sleep.time.ms | 500(毫秒) | JVM 暫停統(tǒng)計線程 sleep 間隔 |
| jvm.pause.monitor* | false | 是否啟用 JVM 暫停統(tǒng)計 |
| metricsProvider.className* | DefaultMetricsProvider(全路徑) | 統(tǒng)計實現(xiàn)類路徑 |
| multiAddress.enabled | false | |
| multiAddress.reachabilityCheckTimeoutMs | 1000(毫秒) | |
| multiAddress.reachabilityCheckEnabled | true | |
| (以開頭)server.* | 集群配置 | |
| (以開頭)group* | 分組配置 | |
| (以開頭)weight* | 權重 | |
| (以開頭)metricsProvider.* | 自定義的統(tǒng)計配置 |
以上就是 3.6.2 中 zoo.cfg 所有的官方配置選項了
3.3 環(huán)境變量配置
Java 程序想要指定環(huán)境變量有兩種方法:
只需要在啟動的時候在后面加上 -DpropertyKey=propertyValue 即可
ZK 還支持一種簡單的方式就是在 zoo.cfg 中直接指定(指定時不需要寫 zookeeper. 的前綴)。只要不是在上面 2.2 中 ZK 自己定義的配置項里,ZK 啟動的時候讀取這些配置會自動幫他們添加 zookeeper. 前綴并加入當前環(huán)境變量中
如果該配置是 follower.nodelay,就只能用第一種方式添加環(huán)境變量了。
讓我們也來看看 ZK 自己定義了哪些環(huán)境變量配置吧
| zookeeper.server.realm* | - | 客戶端配置 |
| zookeeper.clientCnxnSocket | ClientCnxnSocketNIO(全路徑) | 客戶端配置,通信的實現(xiàn)類 |
| 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 實現(xiàn)類,加 quorum 的是服務端的配置,下同 |
| zookeeper.ssl(.quorum).protocol | TLSv1.2 | |
| zookeeper.ssl(.quorum).enabledProtocols | - | |
| zookeeper.ssl(.quorum).ciphersuites | 根據(jù)不同的 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 校驗規(guī)則 |
| 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 目錄自動創(chuàng)建 |
| zookeeper.db.autocreate | true | |
| zookeeper.snapshot.trust.empty | false | 不信任空的 snapshot 文件 |
| zookeeper.snapshot.compression.method | 空字符串 | snapshot 文件壓縮實現(xiàn) |
| zookeeper.commitProcessor.numWorkerThreads | CPU 核心數(shù) | |
| 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 | 選舉端口連接重試次數(shù) |
| 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 節(jié)點類型 |
| 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 核心數(shù) / 2 再開方 | |
| zookeeper.nio.numWorkerThreads | CPU 核心數(shù) * 2 | |
| zookeeper.nio.directBufferBytes | 64 * 1024(字節(jié)) | |
| 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(千字節(jié)) | |
| zookeeper.largeRequestMaxBytes | 100 * 1024 * 1024 | |
| zookeeper.largeRequestThreshold | -1 | |
| zookeeper.superUser | - | |
| zookeeper.audit.enable | false | 是否啟用 audit 日志 |
| zookeeper.audit.impl.class | Log4jAuditLogger(全路徑) | audit 日志功能實現(xiàn)類 |
ZK 的配置還是很多的,有些我這里 TODO 了,以后有機會和大家詳細介紹下~而且相當一部分的配置 ZK 官方的文檔中已經(jīng)給出了解釋,可以查看 ZK 3.6.2 配置文檔。
我這里還要吐槽下,ZK 中有些配置是用 true 或者 false,有些使用 yes 或者 no,明顯是兩個(波)人開發(fā)的,這種不應該做一個統(tǒng)一嗎?yes 或 no 真的很多余...
四、系列結語
感謝你們能看到這里,陪伴這個系列從開始到現(xiàn)在!這個項目從有想法立項到之后跟蛋蛋溝通,再到正式開始編寫,到最后我寫下這段結語,大概經(jīng)歷了三個多月(你們看到的時候應該是更晚),現(xiàn)在回頭再看之前寫的東西,感慨頗深。
(截圖來自-B 站何同學的視頻)
如果以我自己的自控能力,這玩意自己搞,搞著搞著可能就涼了,在此感謝蛋蛋給予我的幫助和鼓勵。關于 ZK 我的確之前有研究過一段時間,但是以現(xiàn)在的眼光看,當時的研究其實也就是皮毛而已(可能現(xiàn)在也還是),很多東西是我這次整理時現(xiàn)學的,收獲非常多,最直觀的感受就是,我以后出去面試不會再害怕 ZK 相關的問題了。
感謝大家這 3 個月的陪伴,本系列終結嘍!如果還有什么想學的開源框架和技術可以留言告訴我們,后續(xù)繼續(xù)為大家安排免費的干貨教程。
最最后,來個大大的贊吧!
????「點擊關注」更多驚喜等待你!
閱讀原文點亮 Star 吧
總結
以上是生活随笔為你收集整理的最后一篇:面试遇到 ZK 的问题,横趟!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 100页PPT,带你了解数字化、智能化车
- 下一篇: android 连笔记本无线上网,[转载