背景
在整個大環境的降本增效的薰陶下,我們也不得不做好應對方案。
根據對線上流量、儲存以及系統資源的佔用,發現我們的 Pulsar 叢集有許多的冗餘,所以考慮進行縮容從而減少資源浪費,最終也能省一些費用。
不過在縮容之前很有必要先聊聊擴容,Pulsar 一開始就是存算分離的架構(更多關於 Pulsar 架構的內容本文不做過多介紹,感興趣的可以自行搜尋),天然就非常適合 kubernetes 環境,也可以利用 kubernetes
的能力進行快速擴容。
擴容
Pulsar 的擴容相對比較簡單,在 kubernetes 環境下只需要修改副本即可。
Broker
當我們的 broker 層出現瓶頸時(比如 CPU、記憶體負載較高、GC 頻繁時)可以考慮擴容。
計算層都擴容了,也需要根據流量計算下儲存層是否夠用。
如果我們使用的是 helm 安裝的 Pulsar 叢集,那隻需要修改對於的副本數即可。
broker:
configuration
component: broker
replicaCount: 3->5
當我們將副本數從 3 增加到 5 之後 kubernetes 會自動拉起新增的兩個 Pod,之後我們啥也不需要做了。
Pulsar 的負載均衡器會自動感知到新增兩個 broker 的加入,從而幫我們將一些負載高的節點的流量遷移到新增的節點中。
Bookkeeper
在介紹 bookkeeper 擴容前先簡單介紹些 Bookkeeper 的一些基本概念。
- Ensemble size (E):當前 Bookkeeper 叢集的節點數量
- Write quorum size (QW):一條訊息需要寫入到幾個 Bookkeeper 節點中
- ACK quorum size (QA):有多少個 Bookkeeper 節點 ACK 之後表示寫入成功
對應到我們在 broker.conf
中的配置如下:
managedLedgerDefaultEnsembleSize: "2"
managedLedgerDefaultWriteQuorum: "2"
managedLedgerDefaultAckQuorum: "2"
這個三個參數列示一條訊息需要同時寫入兩個 Bookkeeper 節點,同時都返回 ACK 之後才能表示當前訊息寫入成功。
從這個配置也可以看出,Bookkeeper 是多副本寫入模型,適當的降低 QW 和 QA 的數量可以提高寫入吞吐率。
大部分場景下 Bookkeeper 有三個節點然後 E/QW/QA 都配置為 2 就可以滿足訊息多副本寫入了。
多副本可以保證當某個節點當機後,這個節點的訊息在其他節點依然有存放,訊息讀取不會出現問題。
那什麼情況下需要擴容 Bookkeeper 了,當然如果單個 Bookkeeper 的負載較高也是可以擴容的。
但我們當時擴容 Bookkeeper 的場景是想利用 Pulsar 的資源隔離功能。
因為有部分業務的訊息量明顯比高於其他的 topic,這樣會導致某個 Broker 的負載較高,同時也可能影響到其他正常的 topic。
最好的方式就將這部分資料用單獨的 broker 和 Bookkeeper 來承載,從而實現硬體資源的隔離。
這樣的需求如果使用其他訊息佇列往往不太好實現,到後來可能就會部署多個叢集來實現隔離,但這樣也會增加運維的複雜度。
好在 Pulsar 天然就支援資源隔離,只需要一個叢集就可以實現不同 namespace 的流量隔離。
此時就可以額外擴容幾個 Bookkeeper 節點用於特定的 namespace 使用。
從上圖可以看到:我們可以將 broker 和 Bookkeeper 分別進行分組,然後再配置對應的 namespace,這樣就能實現資源隔離了。
更多關於資源隔離的細節本文就不過多贅述了。
鋪墊了這麼多,其實 Bookkeeper 的擴容也蠻簡單的:
bookkeeper:
component: bookie
metadata:
resources:
# requests:
# memory: 4Gi
# cpu: 2
replicaCount: 3->5
和 broker 擴容類似,提高副本數量後,Pulsar 的後設資料中心會感知到新的 Bookkeeper 節點加入,從而更新 broker 中的節點資料,這樣就會根據我們配置的隔離策略分配流量。
縮容
其實本文的重點在於縮容,特別是 Bookkeeper 的縮容,這部分內容我在網際網路上很少看到有人提及。
Broker
Broker 的縮容相對簡單,因為存算分離的特點:broker 作為計算層是無狀態的,並不承載任何的資料。
其實是承載資料的,只是 Pulsar 會自動遷移資料,從而體感上覺得是無狀態的。
只是當一個 broker 下線後,它上面所繫結的 topic 會自動轉移到其他線上的 broker 中。
這個過程會導致連線了這個 broker 的 client 觸發重連,從而短暫的影響業務。
正因為 broker 的下線會導致 topic 的歸屬發生轉移,所以在下線前最好是先透過監控皮膚觀察需要下線的 broker topic 是否過多,如果過多則可以先手動 unload 一些資料,儘量避免一次性大批次的資料轉移。
觀察各個broker 的 topic 數量
Bookkeeper
而 Bookkeeper 的縮容則沒那麼容易了,由於它是作為儲存層,本身是有狀態的,下線後節點上儲存的資料是需要遷移到其他的 Bookkeeper 節點中的。
不然就無法滿足之前提到的 Write quorum size (QW) 要求;因此縮容還有一個潛在條件需要滿足:
縮容後的 Bookkeeper 節點數量需要大於broker 中的配置:
managedLedgerDefaultEnsembleSize: "2"
managedLedgerDefaultWriteQuorum: "2"
managedLedgerDefaultAckQuorum: "2"
不然寫入會失敗,整個叢集將變得不可用。
Pulsar 提供了兩種 Bookkeeper 的下線方案:
不需要遷移資料
其實兩種方案主要區別在於是否需要遷移資料,第一種比較簡單,就是不遷移資料的方案。
首先需要將 Bookkeeper 設定為 read-only 狀態,此時該節點將不會接受寫請求,直到這個 Bookkeeper 上的資料全部過期被回收後,我們就可以手動下線該節點。
使用 forceReadOnlyBookie=true
可以強制將 Bookkeeper 設定為只讀。
但這個方案存在幾個問題:
- 下線時間不確定,如果該
Bookkeeper
上儲存的資料生命週期較長,則無法預估什麼時候可以下線該節點。 - 該配置修改後需要重啟才能生效,在 kubernetes 環境中這些配置都是寫在了 configmap 中,一旦重新整理後所有節點都會讀取到該配置,無法針對某一個節點生效;所以可能會出現將不該下線的節點設定為了只讀狀態。
但該方案的好處是不需要遷移資料,人工介入的流程少,同樣也就減少了出錯的可能。
比較適合於用虛擬機器部署的叢集。
遷移資料
第二種就是需要遷移資料的方案,更適用於 kubernetes 環境。
遷移原理
先來看看遷移的原理:
- 當 bookkeeper 停機後,AutoRecovery Auditor 會檢測到 zookeeper 節點
/ledger/available
發生變化,將下線節點的 ledger 資訊寫入到 zookeeper 的/ledgers/underreplicated
節點中。 - AutoRecovery ReplicationWorker 會檢測
/ledgers/underreplicated
節點資訊,然後輪訓這些 ledger 資訊從其他線上的 BK 中複製資料到沒有該資料的節點,保證 QW 數量不變。- 每複製一條資料後都會刪除
/ledgers/underreplicated
節點資訊。 - 所有
/ledgers/underreplicated
被刪除後說明遷移任務完成。
- 每複製一條資料後都會刪除
- 執行
bin/bookkeeper shell decommissionbookie
下線命令:- 會等待
/ledgers/underreplicated
全部刪除 - 然後刪除 zookeeper 中的後設資料
- 後設資料刪除後 bookkeeper 才是真正下線成功,此時 broker 才會感知到 Bookkeeper 下線。
- 會等待
AutoRecovery
是 Bookkeeper 提供的一個自動恢復程式,他會在後臺檢測是否有資料需要遷移。
簡單來說就是當某個Bookkeeper 停機後,它上面所儲存的 ledgerID 會被寫入到後設資料中心,此時會有一個單獨的執行緒來掃描這些需要遷移的資料,最終將這些資料寫入到其他線上的 Bookkeeper 節點。
Bookkeeper 中的一些關鍵程式碼:
下線步驟
下面來看具體的下線流程:
- 副本數-1
bin/bookkeeper shell listunderreplicated
檢測有多少 ledger 需要被遷移
- 執行遠端下線後設資料
nohup bin/bookkeeper shell decommissionbookie -bookieid bkid:3181 > bk.log 2>&1 &
- 這個命令會一直後臺執行等待資料遷移完成,比較耗時
- 檢視下線節點是否已被剔除
bin/bookkeeper shell listbookies -a
- 迴圈第一步
第一步是檢測一些現在有多少資料需要遷移:
bin/bookkeeper shell listunderreplicated
命令檢視需要被遷移的 ledger 資料也是來自於 /ledgers/underreplicated
節點
正常情況下是 0
第二步的命令會等待資料遷移完成後從 zookeeper 中刪除節點資訊,這個程序退出後表示下線成功。
這個命令最好是後臺執行,並輸出日誌到專門的檔案,因為週期較長,很有可能終端會話已經超時了。
我們登入 zookeeper 可以看到需要遷移的 ledger 資料:
bin/pulsar zookeeper-shell -server pulsar-zookeeper:2181
get /ledgers/underreplication/ledgers/0000/0000/0000/0002/urL0000000002
replica: "pulsar-test-2-bookie-0.pulsar-test-2-bookie.pulsar-test-2.svc.cluster.local:3181"
ctime: 1708507296519
underreplication 的節點路徑中存放了 ledgerId,透過 ledgerId 計算路徑:
注意事項
下線過程中我們可以檢視 nohup bin/bookkeeper shell decommissionbookie -bookieid bkid:3181 > bk.log 2>&1 &
這個命令寫入的日誌來確認遷移的進度,日誌中會列印當前還有多少數量的 ledger 沒有遷移。
同時需要觀察 zookeeper、Bookkeeper 的資源佔用情況。
因為遷移過程中寫入大量資料到 zookeeper 節點,同時遷移數時也會有大量流量寫入 Bookkeeper。
不要讓遷移過程影響到了正常的業務使用。
根據我的遷移經驗來看,通常 2w 的ledger 資料需要 2~3 小時不等的時間,具體情況還得根據你的叢集來確認。
回滾方案
當然萬一遷移比較耗時,或者影響了業務使用,所以還是要有一個回滾方案:
這裡有一個大的前提:
只要 BK 節點後設資料、PVC(也就是磁碟中的資料) 沒有被刪除就可以進行回滾。
所以只要上述的 decommissionbookie 命令沒有完全執行完畢,我們就可以手動 kill 該程序,然後恢復副本資料。
這樣恢復的 Bookkeeper 節點依然可以提供服務,同時資料也還存在;只是浪費了一些 autorecovery 的資源。
最後當 bookkeeper 成功下線後,我們需要刪除 PVC,不然如果今後需要擴容的時候是無法啟動 bookkeeper 的,因為在啟動過程中會判斷掛載的磁碟是否有資料。
總結
總的來說 Pulsar 的擴縮容還是非常簡單的,只是對於有狀態節點的資料遷移稍微複雜一些,但只要跟著流程走就不會有什麼問題。
參考連結:
- https://pulsar.apache.org/docs/next/administration-isolation/
- https://bookkeeper.apache.org/docs/4.13.0/admin/decomission
- https://bookkeeper.apache.org/docs/4.13.0/admin/autorecovery