3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
作者| 梁俊傑 編輯| 小智 PhxQueue 是微信開源的一款基於 Paxos 協議實現的高可用、高吞吐和高可靠的分散式隊列,保證 At-Least-Once Delivery,在微信內部廣泛支持微信支付、公眾平台等多個重要業務。 開源地址消息隊列概述消息隊列作為成熟的非同步通信模式,對比常用的同步通信模式,有如下優勢:解耦:防止引入過多的 API 給系統的穩定性帶來風險;調用方使用不當會給被調用方系統造成壓力,被調用方處理不當會降低調用方系統的響應能力。削峰和流控:消息生產者不會堵塞,突發消息緩存在隊列中,消費者按照實際能力讀取消息。復用:一次發布多方訂閱。PhxQueue 誕生背景舊隊列微信初期使用的分散式隊列(稱為舊隊列)是微信後台自研的重要組件,廣泛應用在各種業務場景中,為業務提供解耦、緩存、非同步化等能力。舊隊列以 Quorum NRW 作為同步機制,其中 N=3、W=R=2,刷盤方式採用非同步刷盤,兼顧了性能和可用性。新需求隨著業務發展,接入業務種類日益增多,舊隊列逐漸顯得力不從心,主要不足如下:非同步刷盤,數據可靠性堪憂對於支付相關業務,保證數據可靠是首要需求。 目前大多數分散式隊列方案是以同步複製 + 非同步刷盤來保證數據可靠性的,但我們認為需要同步刷盤來進一步提高數據可靠性。亂序問題部分業務提出了絕對有序的需求,但 NRW 並不保證順序性,無法滿足需求。另外舊隊列還存在出隊去重、負載均衡等其他方面的問題亟需改善。上述種種促使了我們考慮新的方案。業界方案的不足Kafka 是大數據領域常用的消息隊列,最初由 LinkedIn 採用 Scala 語言開發,用作 LinkedIn 的活動流追蹤和運營系統數據處理管道的基礎。其高吞吐、自動容災、出入隊有序等特性,吸引了眾多公司使用,在數據採集、傳輸場景中發揮著重要作用,詳見 Powerd By Kafka。但我們充分調研了 Kafka,認為其在注重數據可靠性的場景下,有如下不足:Kafka 性能與同步刷盤的矛盾 Kafka 在開啟配置 log.flush.interval.messages=1,打開同步刷盤特性后,吞吐會急劇下降。該現象由如下因素導致:SSD 寫放大業務消息平均大小在數 1k 左右。 而 SSD 一次刷盤的最小單位為一個 page size,大小為 4k。 當 Kafka 對大小不足 4k 的消息進行刷盤時,實際寫入的物理數據量是消息大小的數倍。導致硬碟寫帶寬資源被浪費。業務場景下 Producer batch 效果不好Kafka Producer batch,簡單來說,就是把多個消息打包在一起發送到 Broker,廣泛用於大數據場景。按道理,batch 效果足夠,是能抵消寫放大的影響的。 但業務場景下的消息生產不同於大數據場景下的日誌生產,每個需要入隊的業務請求在業務系統中有獨立的上下文,batch 難度大。即使在業務和 Broker 之間加入代理層,將 Producer 轉移到代理層內進行 batch,也因代理層的節點數眾多,batch 效果難以提高,導致寫放大無法抵消。Kafka replica 同步設計上的不足 Kafka replica 同步設計概要:Kafka Broker leader 會跟蹤與其保持同步的 follower 列表,該列表稱為 ISR(即 in-sync Replica)。如果一個 follower 宕機,或者落後太多,leader 將把它從 ISR 中移除。該同步方式偏重於同步效率,但是在可用性方面表現略顯不足:Broker fail over 過程成功率下降嚴重在 3 replicas 的場景下,leader 均勻分佈在各 Broker 上,一個 Broker 出現故障,就意味著 1/3 的 leader、follower 離線,這時讀寫成功率下降:對於 leader 離線的 partition,暫時無法讀寫,需要等待 Controller 選舉出新的 leader 后才能恢復;對於 follower 離線的 partition,也暫時無法讀寫,需要等待一定時長(取決於 replica.lag.time.max.ms,默認 10s)后,leader 將故障 follower 從 ISR 中剔除才能恢復。也就是說,任意一個 Broker 故障時,讀寫成功率會在一段時間內降為 0。同步延遲取決於最慢節點在同步複製場景下,需要等待所有節點返回 ack。通過對比 Kafka replica 與 Paxos 的表現,我們認為在同步方式上 Paxos 是更好的選擇:所以,我們基於舊隊列,用 Paxos 協議改造了同步邏輯,並且進行了包括同步刷盤之內的多項優化,完成了 PhxQueue。PhxQueue 介紹PhxQueue 目前在微信內部廣泛支持微信支付、公眾平台等多個重要業務,日均入隊達千億,分鐘入隊峰值達一億。其設計出發點是高數據可靠性,且不失高可用和高吞吐,同時支持多種常見隊列特性。PhxQueue 支持的特性如下:同步刷盤,入隊數據絕對不丟,自帶內部實時對賬出入隊嚴格有序多訂閱出隊限速出隊重放所有模塊均可平行擴展存儲層批量刷盤、同步,保證高吞吐存儲層支持同城多中心部署存儲層自動容災 / 接入均衡消費者自動容災 / 負載均衡PhxQueue 設計整體架構PhxQueue 由下列 5 個模塊組成。Store - 隊列存儲 Store 作為隊列存儲,引入了 PhxPaxos 庫,以 Paxos 協議作副本同步。只要多數派節點正常工作及互聯,即可提供線性一致性讀寫服務。為了提高數據可靠性,同步刷盤作為默認開啟特性,且性能不亞於非同步刷盤。在可用性方面,Store 內有多個獨立的 paxos group,每個 paxos group 僅 master 提供讀寫服務,平時 master 動態均勻分佈在 Store 內各節點,均衡接入壓力,節點出災時自動切換 master 到其它可用節點。Producer - 生產者 Producer 作為消息生產者,根據 key 決定消息存儲路由。相同 key 的消息默認路由到同一個隊列中,保證出隊順序與入隊順序一致。Consumer - 消費者 Consumer 作為消費者,以批量拉取的方式從 Store 拉消息,支持多協程方式批量處理消息。Consumer 以服務框架的形式提供服務,使用者以實現回調的方式,根據不同主題(Topic),不同處理類型(Handler)定義具體的消息處理邏輯。Scheduler - 消費者管理器(可選擇部署) Scheduler 的作用是,收集 Consumer 全局負載信息, 對 Consumer 做容災和負載均衡。當使用者沒有這方面的需求時,可以省略部署 Scheduler,此時各 Consumer 根據配置權重決定與隊列的處理關係。部署 Scheduler 后,Scheduler leader 與所有 Conusmer 維持心跳,在收集 Consumer 的負載信息的同時,反向調整 Consumer 與隊列的處理關係。當 Scheduler leader 宕機了后,Scheduler 依賴下述分散式鎖服務選舉出新 leader,不可用期間僅影響 Consumer 的容災和負載均衡,不影響 Consumer 的正常消費。Lock - 分散式鎖(可選擇部署) Lock 是一個分散式鎖,其介面設計非常通用化,使用者可以選擇將 Lock 獨立部署,提供通用分散式鎖服務。Lock 在 PhxQueue 中的作用有如下兩點:為 Scheduler 選舉 leader;防止多個 Consumer 同時處理一條隊列。Lock 同樣也是可選擇部署的模塊:若部署了 Scheduler,就必須部署 Lock 為 Scheduler 選舉出 leader;否則,若業務對重複消費不敏感,可選擇不部署 Lock。這裡所指的重複消費場景是:若省略部署 Scheduler 的話,Consumer 需要通過讀取配置得知可處理的隊列集合;當隊列有變更(如隊列縮擴容)時,各 Consumer 機器上的配置改變有先有后,這時各 Consumer 在同一時間看到的配置狀態可能不一樣,導致一段時間內兩個 Consumer 都認為自己該消費同一個隊列,造成重複消費。Lock 的部署可以避免該場景下的重複消費。(注意,即使省略部署 Lock,該場景僅造成重複消費,而不會造成亂序消費)Store 複製流程PhxQueue Store 通過 PhxPaxos 協議進行副本複製。PhxPaxos 的工程實現方式分為三層:app 層負責處理業務請求,paxos 層執行 paxos 同步過程,狀態機層更新業務狀態。其中,app 層發起 paxos 提議,paxos 層各節點通過 paxos 協議共同完成一個 paxos log 的確認,之後狀態機以 paxos log 作為的輸入作狀態轉移,更新業務的狀態,最後返回狀態轉移結果給 app 層。一致的狀態機層,加上來自 paxos 層的一致輸入,就產生一致的狀態轉移,從而保證多個節點強一致。這裡我們要基於 PhxPaxos 在狀態機層實現一個隊列,就需要作如下概念映射:隊列這種模型不涉及數據修改,是有序的數據集合,和 paxos log 的定義很像,所以可以讓入隊的數據直接作為 paxos log,而狀態機只需要保存 paxos log 序列。instance id 的嚴格遞增特性,使得它可以方便地作為隊列偏移。隊列中讀偏移之前的數據,認為是可以刪除的數據,這點和 check point 的定義一致。整體上隊列狀態機和 paxos 能很好地切合。Store Group Commit - 高效刷盤及副本同步未經優化的 Paxos 協議並未解決同步刷盤的寫放大問題。而且,其副本同步效率不如 Kafka。原因是,Kafka 的副本同步是流式批量的,而 Paxos 協議是以 paxos log 為單位串列同步,每個 paxos log 的同步開銷是 1 個 RTT + 1 次刷盤。在多 DC 部署的場景下,ping 時延可達 4ms,這樣會導致單個 paxos group 的理論最高 TPS 僅 250。我們採用多 paxos group 部署 以及 Group Commit 的方式來同時解決同步刷盤的寫放大問題以及 Paxos 吞吐問題。如上圖, 我們部署多個 paxos group,以 paxos group 作為 Group Commit 的單位,一個 paxos group 內對應多個 queue,將多個 queue 在一段時間內入隊的數據合併在一起,當等待耗時或積累數據數目達到閥值,才會觸發一次 Paxos 同步和同步刷盤,等待期間前端阻塞。與 Kafka 的 Producer 批量邏輯相比,在存儲層以 Group Commit 進行批量合併的好處如下:業務層無需關注如何組織請求進行批量;在存儲層以 paxos group 為單位的聚合效果比上層聚合效果更好。PhxQueue 與 Kafka 對比下面分別從設計、性能、存儲層 failover 過程三方面對比 PhxQueue 與 Kafka。設計對比PhxQueue 架構雖然與 Kafka 等常見分散式隊列類似,但設計上仍有不少獨特之處。為了能讓對 Kafka 有一定了解的讀者更方便地了解 PhxQueue,下面列出了兩者的對比。註:以下對比基於相同的數據可靠性場景:少數派節點失效,不會造成數據丟失,且整體依舊可用。性能對比測試環境 測試基準及配置 測試結果 開啟 Producer Batch:關閉 Producer Batch:以上場景,PhxQueue 瓶頸在 cpu,使用率達 70% ~ 80%。小結 PhxQueue 性能與 Kafka 持平;相同 QPS 下,由於不用等最慢節點返回,PhxQueue 平均耗時比 Kafka 稍優;關閉 Producer Batch 后,在同步刷盤場景下,PhxQueue 性能可達 Kafka 的 2 倍,原因是,PhxQueue 存儲層在寫盤前做了 batch,而 Kafka 沒有,所以後者會有寫放大。存儲層 failover 過程對比主要對比殺死存儲層的一個節點后,對整體吞吐的影響。Kafka 表現:Failover 期間,在不同階段程度不同,入隊成功率在 0% ~ 33%;Failover 持續時間由租約決定,租約時長默認 10s。測試過程:將 replica.lag.time.max.ms 從 10s 調整為 60s(延長時間方便觀察),然後 kill Broker 0,挑選 3 個 partition,觀察 ISR 變化如下:其中,第二 / 三階段入隊成功率受損:第二階段期間,Partition 96/97/98 均無法寫入,入隊成功率成功率下降至 0%。第三階段期間,Partition 96 可繼續寫入,但 Partition 97/98 無法寫入,因為寫入要等 Broker 0 回 ack,但 Broker 0 已 kill,入隊成功率下降至 33%。而實際觀察,第二 / 三階段期間完全沒吞吐,原因是壓測工具不斷報連接失敗,停止了寫入。壓測工具輸出:壓測工具連接 Broker 失敗日誌:原因分析:Kafka Broker leader 是通過 Controller 選舉出來的,ISR 列表是 leader 維護的。前者的的租約是 Controller 定義的,後者的租約是 Broker 配置 replica.lag.time.max.ms 指定的。所以,第二階段持續時間較短,是 Controller 的租約時間決定的,第三階段持續時間較長,是 replica.lag.time.max.ms 決定的。當 Broker 0 被 kill 時,前者影響本來 Broker 0 是 leader 的 1/3 partitions 的入隊成功率,後者影響 Broker 0 作為 follower 的 2/3 partitions 的入隊成功率。PhxQueue 表現:Failover 期間,入隊成功率僅下降至 66%;Failover 持續時間由租約決定,租約時長默認 5s。開啟 換隊列重試特性(適合沒有絕對順序性要求的業務提高可用性)后,Failover 期間仍有 90+% 入隊成功率。測試過程:將 Store master 租約時長從 10s 調整為 60s(延長時間方便觀察),然後 kill store 0,觀察某 Producer 入隊成功率:關閉換隊列重試特性:開啟換隊列重試特性:小結 在存儲層 failover 過程中,PhxQueue 和 Kafka 的入隊成功率均有一定時長的下降,PhxQueue 的入隊成功率在 66% ~ 100%,Kafka 的入隊成功率在 0% ~ 33%;PhxQueue 開啟換隊列重試特性后,failover 過程中入隊成功率保持在 90+%;PhxQueue 和 Kafka 均能自動切換 master,最終入隊成功率完全恢復。寫在最後PhxQueue 在存儲層做了很多的努力:實現了 master 自動切換,且仍然保證線性一致,切換期間仍然高可用;保證了同步刷盤的吞吐,其性能不亞於非同步刷盤。另外實現了大部分隊列實用特性,例如出入隊順序一致、多訂閱、限速、消息重放等,適用於各種業務場景。目前 PhxQueue 已在微信內部大規模使用,也正式開源。我們將保持 PhxQueue 開源版本與內部版本的一致,歡迎讀者試用並反饋意見。開源地址:作者介紹梁俊傑,微信高級工程師,目前負責微信消息系統、消息中間件等開發及優化。2011 年華南師範大學大學部畢業,曾參與和主導微博私信、反垃圾系統,以及微信多個系統架構優化項目。在過去一年多,作為 PhxQueue 主創成員之一,對微信分散式隊列進行重大架構改造,致力於提供高可用、高吞吐和高可靠的消息中間件服務。 分散式系統事務一致性解決方案大對比

本文由yidianzixun提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦