
作者|梁勇
背景
哈啰已進化為包括兩輪出行(哈啰單車、哈啰助力車、哈啰電動車、小哈換電)、四輪出行(哈啰順風車、全網叫車、哈啰打車)等的綜合化移動出行平台,并向酒店、到店團購等衆多本地生活化生态探索。
随着公司業務的不斷發展,流量也在不斷增長。我們發現生産中的一些重大事故,往往是被突發的流量沖跨的,對流量的治理和防護,保障系統高可用就尤為重要。
本文就哈啰在消息流量和微服務調用的治理中踩過的坑、積累的經驗進行分享。
作者介紹
梁勇 ( 老梁 ) ,《 RocketMQ 實戰與進階》專欄聯合作者、參與了《 RocketMQ 技術内幕》審稿工作。ArchSummit 全球架構師大會講師、QCon 案例研習社講師。
目前主要在後端中間件方向,在公衆号【瓜農老梁】已陸續發表百餘篇源碼實戰類文章,涵蓋 RocketMQ 系列、Kafka 系列、GRPC 系列、Nacosl 系列、Sentinel 系列、Java NIO 系列。目前就職于哈啰出行,任職進階技術專家。
聊聊治理這件事
開始之前先聊聊治理這件事情,下面是老梁個人了解:
治理在幹一件什麼事?
- 讓我們的環境變得美好一些
需要知道哪些地方還不夠好?
- 以往經驗
- 使用者回報
- 業内對比
還需要知道是不是一直都是好的?
- 監控跟蹤
- 告警通知
不好的時候如何再讓其變好?
- 治理措施
- 應急方案
目錄
- 打造分布式消息治理平台
- RocketMQ 實戰踩坑和解決
- 打造微服務高可用治理平台
裸奔的 RabbitMQ
公司之前使用 RabbitMQ ,下面在使用 RabbitMQ 時的痛點,其中很多事故由于 RabbitMQ 叢集限流引起的。
- 積壓過多是清理還是不清理?這是個問題,我再想想。
- 積壓過多觸發叢集流控?那是真的影響業務了。
- 想消費前兩天的資料?請您重發一遍吧。
- 要統計哪些服務接入了?您要多等等了,我得去撈IP看看。
- 有沒有使用風險比如大消息?這個我猜猜。
裸奔的服務
曾經有這麼一個故障,多個業務共用一個資料庫。在一次晚高峰流量陡增,把資料庫打挂了。
- 資料庫單機更新到最高配依然無法解決
- 重新開機後緩一緩,不一會就又被打挂了
- 如此循環着、煎熬着、默默等待着高峰過去
思考:無論消息還是服務都需要完善的治理措施
設計指南
哪些是我們的關鍵名額,哪些是我們的次要名額,這是消息治理的首要問題。
設計目标
旨在屏蔽底層各個中間件( RocketMQ / Kafka )的複雜性,通過唯一辨別動态路由消息。同時打造集資源管控、檢索、監控、告警、巡檢、容災、可視化運維等一體化的消息治理平台,保障消息中間件平穩健康運作。
消息治理平台設計需要考慮的點
- 提供簡單易用 API
- 有哪些關鍵點能衡量用戶端的使用沒有安全隐患
- 有哪些關鍵名額能衡量叢集健康不健康
- 有哪些常用的使用者/運維操作将其可視化
- 有哪些措施應對這些不健康
盡可能簡單易用
把複雜的問題搞簡單,那是能耐。
極簡統一 API
提供統一的 SDK 封裝了( Kafka / RocketMQ )兩種消息中間件。
一次申請
主題消費組自動建立不适合生産環境,自動建立會導緻失控,不利于整個生命周期管理和叢集穩定。需要對申請流程進行控制,但是應盡可能簡單。例如:一次申請各個環境均生效、生成關聯告警規則等。
用戶端治理
監控用戶端使用是否規範,找到合适的措施治理
場景回放
場景一 瞬時流量與叢集的流控
假設現在叢集 Tps 有 1 萬,瞬時翻到 2 萬甚至更多,這種過度陡增的流量極有可能引發叢集流控。針對這類場景需監控用戶端的發送速度,在滿足速度和陡增幅度門檻值後将發送變的平緩一些。
場景二 大消息與叢集抖動
當用戶端發送大消息時,例如:發送幾百KB甚至幾兆的消息,可能造成 IO 時間過長與叢集抖動。針對這類場景治理需監控發送消息的大小,我們采取通過事後巡檢的方式識别出大消息的服務,推動使用同學壓縮或重構,消息控制在 10KB 以内。
場景三 過低用戶端版本
随着功能的疊代 SDK 的版本也會更新,變更除了功能外還有可能引入風險。當使用過低的版本時一個是功能不能得到支援,另外一個是也可能存在安全隐患。為了解 SDK 使用情況,可以采取将 SDK 版本上報,通過巡檢的方式推動使用同學更新。
場景四 消費流量摘除和恢複
消費流量摘除和恢複通常有以下使用場景,第一個是釋出應用時需要先摘流量,另外一個是問題定位時希望先把流量摘除掉再去排查。為了支援這種場景,需要在用戶端監聽摘除/恢複事件,将消費暫停和恢複。
場景五 發送/消費耗時檢測
發送/消費一條消息用了多久,通過監控耗時情況,巡檢摸排出性能過低的應用,針對性推動改造達到提升性能的目的。
場景六 提升排查定位效率
在排查問題時,往往需要檢索發了什麼消息、存在哪裡、什麼時候消費的等消息生命周期相關的内容。這部分可以通過 msgId 在消息内部将生命周期串聯起來。另外是通過在消息頭部埋入 rpcId / traceId 類似鍊路辨別,在一次請求中将消息串起來。
治理措施提煉
需要的監控資訊
- 發送/消費速度
- 發送/消費耗時
- 消息大小
- 節點資訊
- 鍊路辨別
- 版本資訊
常用治理措施
- 定期巡檢:有了埋點資訊可以通過巡檢将有風險的應用找出來。例如發送/消費耗時大于 800 ms、消息大小大于 10 KB、版本小于特定版本等。
- 發送平滑:例如檢測到瞬時流量滿足 1 萬而且陡增了 2 倍以上,可以通過預熱的方式将瞬時流量變的平滑一些。
- 消費限流:當第三方接口需要限流時,可以對消費的流量進行限流,這部分可以結合高可用架構實作。
- 消費摘除:通過監聽摘除事件将消費用戶端關閉和恢複。
主題/消費組治理
監控主題消費組資源使用情況
場景一 消費積壓對業務的影響
有些業務場景對消費堆積很敏感,有些業務對積壓不敏感,隻要後面追上來消費掉即可。例如單車開鎖是秒級的事情,而資訊彙總相關的批處理場景對積壓不敏感。通過采集消費積壓名額,對滿足門檻值的應用采取實時告警的方式通知到應用負責的同學,讓他們實時掌握消費情況。
場景二 消費/發送速度的影響
發送/消費速度跌零告警?有些場景速度不能跌零,如果跌零意味着業務出現異常。通過采集速度名額,對滿足門檻值的應用實時告警。
場景三 消費節點掉線
消費節點掉線需要通知給應用負責的同學,這類需要采集注冊節點資訊,當掉線時能實時觸發告警通知。
場景四 發送/消費不均衡
發送/消費的不均衡往往影響其性能。記得有一次咨詢時有同學将發送消息的key設定成常量,預設按照 key 進行 hash 選擇分區,所有的消息進入了一個分區裡,這個性能是無論如何也上不來的。另外還要檢測各個分區的消費積壓情況,出現過度不均衡時觸發實時告警通知。
- 發送分區詳情
- 消費各分區積壓
- 消費組積壓
- 注冊節點資訊
- 實時告警:對消費積壓、發送/消費速度、節點掉線、分區不均衡進行實時告警通知。
- 提升性能:對于有消費積壓不能滿足需求,可以通過增加拉取線程、消費線程、增加分區數量等措施加以提升。
- 自助排查:提供多元度檢索工具,例如通過時間範圍、msgId 檢索、鍊路系統等多元度檢索消息生命周期。
叢集健康治理
度量叢集健康的核心名額有哪些?
場景一 叢集健康檢測
叢集健康檢測回答一個問題:這個叢集是不是好的。通過檢測叢集節點數量、叢集中每個節點心跳、叢集寫入Tps水位、叢集消費Tps水位都是在解決這個問題。
場景二 叢集的穩定性
叢集流控往往展現出叢集性能的不足,叢集抖動也會引發用戶端發送逾時。通過采集叢集中每個節點心跳耗時情況、叢集寫入Tps水位的變化率來掌握叢集是否穩定。
場景三 叢集的高可用
高可用主要針對極端場景中導緻某個可用區不可用、或者叢集上某些主題和消費組異常需要有一些針對性的措施。例如:MQ 可以通過同城跨可用區主從交叉部署、動态将主題和消費組遷移到災備叢集、多活等方式進行解決。
- 叢集節點數量采集
- 叢集節點心跳耗時
- 叢集寫入 Tps 的水位
- 叢集消費 Tps 的水位
- 叢集寫入 Tps 的變化率
- 定期巡檢:對叢集 Tps 水位、硬體水位定期巡檢。
- 容災措施:同城跨可用區主從交叉部署、容災動态遷移到災備叢集、異地多活。
- 叢集調優:系統版本/參數、叢集參數調優。
- 叢集分類:按業務線分類、按核心/非核心服務分類。
最核心名額聚焦
如果說這些關鍵名額中哪一個最重要?我會選擇叢集中每個節點的心跳檢測,即:響應時間( RT ),下面看看影響 RT 可能哪些原因。
關于告警
- 監控名額大多是秒級探測
- 觸發門檻值的告警推送到公司統一告警系統、實時通知
- 巡檢的風險通知推送到公司巡檢系統、每周彙總通知
消息平台圖示
架構圖
看闆圖示
- 多元度:叢集次元、應用次元
- 全聚合:關鍵名額全聚合
RocketMQ 實戰中踩過的坑和解決方案
行動指南
我們總會遇到坑,遇到就把它填了。
1. RocketMQ 叢集 CPU 毛刺
問題描述
**
RocketMQ 從節點、主節點頻繁 CPU 飙高,很明顯的毛刺,很多次從節點直接挂掉了。
隻有系統日志有錯誤提示
2020-03-16T17:56:07.505715+08:00 VECS0xxxx kernel:[] ? __alloc_pages_nodemask+0x7e1/0x9602020-03-16T17:56:07.505717+08:00 VECS0xxxx kernel: java: page allocation failure. order:0, mode:0x202020-03-16T17:56:07.505719+08:00 VECS0xxxx kernel: Pid: 12845, comm: java Not tainted 2.6.32-754.17.1.el6.x86_64 #12020-03-16T17:56:07.505721+08:00 VECS0xxxx kernel: Call Trace:2020-03-16T17:56:07.505724+08:00 VECS0xxxx kernel:[] ? __alloc_pages_nodemask+0x7e1/0x9602020-03-16T17:56:07.505726+08:00 VECS0xxxx kernel: [] ? dev_queue_xmit+0xd0/0x3602020-03-16T17:56:07.505729+08:00 VECS0xxxx kernel: [] ? ip_finish_output+0x192/0x3802020-03-16T17:56:07.505732+08:00 VECS0xxxx kernel: [] ?
各種調試系統參數隻能減緩但是不能根除,依然毛刺超過 50%
解決方案
将叢集所有系統更新從 centos 6 更新到 centos 7 ,核心版本也從從 2.6 更新到 3.10 ,CPU 毛刺消失。
2. RocketMQ 叢集線上延遲消息失效
RocketMQ 社群版預設本支援 18 個延遲級别,每個級别在設定的時間都被會消費者準确消費到。為此也專門測試過消費的間隔是不是準确,測試結果顯示很準确。然而,如此準确的特性居然出問題了,接到業務同學報告線上某個叢集延遲消息消費不到,詭異!
将" delayOffset.json "和" consumequeue / SCHEDULE_TOPIC_XXXX "移到其他目錄,相當于删除;逐台重新開機 broker 節點。重新開機結束後,經過驗證,延遲消息功能正常發送和消費。
哪些是我們的核心服務,哪些是我們的非核心服務,這是服務治理的首要問題
服務能應對突如其來的陡增流量,尤其保障核心服務的平穩運作。
應用分級和分組部署
應用分級
根據使用者和業務影響兩個緯度來進行評估設定的,将應用分成了四個等級。
- 業務影響:應用故障時影響的業務範圍
- 使用者影響:應用故障時影響的使用者數量
S1:核心産品,産生故障會引起外部使用者無法使用或造成較大資損,比如主營業務核心鍊路,如單車、助力車開關鎖、順風車的發單和接單核心鍊路,以及其核心鍊路強依賴的應用。
S2: 不直接影響交易,但關系到前台業務重要配置的管理與維護或業務背景處理的功能。
S3: 服務故障對使用者或核心産品邏輯影響非常小,且對主要業務沒影響,或量較小的新業務;面向内部使用者使用的重要工具,不直接影響業務,但相關管理功能對前台業務影響也較小。
S4: 面向内部使用者使用,不直接影響業務,或後續需要推動下線的系統。
分組部署
S1 服務是公司的核心服務,是重點保障的對象,需保障其不被非核心服務流量意外沖擊。
- S1 服務分組部署,分為 Stable 和 Standalone 兩套環境
- 非核心服務調用 S1 服務流量路由到 Standalone 環境
- S1 服務調用非核心服務需配置熔斷政策
多種限流熔斷能力建設
我們建設的高可用平台能力
部分限流效果圖
- 預熱圖示
- 排隊等待
- 預熱+排隊
高可用平台圖示
- 中間件全部接入
- 動态配置實時生效
- 每個資源和 IP 節點詳細流量
總結
- 哪些是我們的關鍵名額,哪些是我們的次要名額,這是消息治理的首要問題
- 源碼&實戰 是一種比較好的工作學習方法。