哦哇資訊網

好大夫線上在解構服務風險治理方面的實踐

由 AI前線 發表于 歷史2021-12-14

作者 | 方勇

2019 年初,好大夫經歷了幾次嚴重的線上故障,面臨了中介軟體和服務治理危機。很多故障都是因為業務系統中不規範的 SQL 以及慢介面造成的,嚴重的幾次甚至雪崩到全站短暫不可用的程度,這種局面必須立即、徹底改變。於是,系統架構部痛定思痛,發起了“DOA“(Dead or Alive)工程,首先治理基礎設施,提升中介軟體的穩定性和高可用。之後緊接著又發起了服務風險治理專案,識別慢介面,不規範的 SQL,依賴不合理等服務風險。

在大家砥礪前行的完成這兩個大專案之後,全站的穩定性得到了大幅度提升。經過了這兩年多的沉澱,現在我來彙報一下在做服務風險治理過程的相關經驗心得,希望能帶給大家一起啟發。

說到風險,我先想到了認知意識,每個人對風險認知其實是不一樣的,大概可以分為一下四類:

我意識到我已經知道了;

我意識到我不知道;

我意識不到我知道;

我意識不到我不知道。

在日常工作中,我們收集了不少開發工程師的反饋,給我印象最深的就是“我意識不到我不知道”。SRE 小組探索服務風險治理已經快兩年了,迎來了新版本的迭代。藉此機會,想和大家深入聊一下服務風險治理,拓寬彼此認知的邊界。

這次分享主要分三個部分:

探險:首先梳理下開發工程師遇到的已知和未知的風險,介紹一下服務風險治理的相關概念名詞;

冒險:介紹下我們如何識別、量化、追蹤服務風險,如何整合到平臺裡的;

歷險:現場工作坊,實戰分析服務風險任務。

探  險

不知道大家有沒這樣的疑問:

奪命線 p99 到底是個啥,p50,p75,p95 這一家子暗藏什麼玄機?

我的服務介面平均響應耗時 30ms,是不是很健康,為何在蜘蛛抓取的時候,受傷的總是我呢?

常說的高層服務、低層服務、上下游服務、迴圈依賴、雙向依賴、慢介面、慢 SQL 等等基本概念說的是什麼?

到底有哪些因素影響服務的健康度?

衡量服務健康度的指標有哪些,是如何篩選的呢?

服務健康度是大吞吐量服務應該感興趣的事吧,我的服務 QPM 才幾十需要關心啥?

定時任務,非同步消費者裡面的慢介面不影響使用者,不算風險吧?

DB 抖動造成的波動會不會生成風險任務?

我只關心自己的服務健康度,將聚合介面邏輯扔給前端可以嗎?

。。。

且看我們是如何處理這些疑問的。

服務風險治理最終目標是為了服務健康,服務的健康體系是個複雜系統,影響因素很多,但我們需要抓住現階段最大的風險。經過反覆的對比,選擇從延遲風險入手,也是為了達到公司預期“全站秒開”的大目標。藉助 MDD(Metrics-Driven Development) 指導思想,確定 SLI,設定 SLO。並圍繞 SLO 去識別風險,解決風險。故此選擇 SLI:介面延遲 -p99。並設定了 SLO:後端服務 p99

延遲

曾經有人問為啥不用平均耗時呢,選擇 p99 是為啥,這裡再解釋一下。

現實生活中普遍存在兩種分佈,正太分佈 和 冪律分佈。典型的兩個例子:中國成年男性的身高符合正太分佈,程式設計師的收入卻符合冪律分佈。那什麼樣的資料具備這樣的特性呢?

一般如果有極值界限的,大多會符合正太分佈,比如人的身高,體重,不可能無限大和無限小。

有人會說人的財富也有上限呀,為啥不是正太分佈?由於財富聚集頭部和尾部差距拉的過大,財富會在一連串聚集後,越來越分化,從而演化成了冪律分佈。這麼說可能有些人還是不太理解,有研究表明冪律分佈一般由於連鎖效應產生的,詳細可以參考《失效的科學》。

這兩種分佈都具備長尾效應,取平均值就不能很好的反映模型特徵。

服務延遲就是符合正太分佈滿足長尾效應,故此我們取 p99 作為 SLI。在服務延遲中,如果 p50,p75,p95,p99 無限接近,服務越穩定,p99 值越小服務具備了更高的抗壓性,也就是彈性更強。p99 是個神奇的指標,我們以後會經常遇到。

好,關於為何選擇 p99,應該大家都清楚了吧。接下來我們就圍繞降低 p99 去挖掘服務存在的風險點。

尋找風險

哪些因素會影響介面延遲呢?

探尋很久,我們終於抓住了尾巴:

依賴

監控服務依賴的延遲,就能順藤摸瓜,從而解決了一大部分的高延遲服務風險。為什麼這麼說呢?

由於現在是微服務的架構,服務與服務之間,服務與中介軟體之間,服務與第三方介面之間,都可能隱藏風險點。監控好這些依賴的延遲,好把脈,服務風險治理就算成功一半了。

且看如何把脈。

第一大忌:服務之間依賴不合理

首先我們得了解幾個基本概念:服務層級,高層、低層、上下游

服務分層這部分分級模型我們參照《架構整潔之道》,大家可以看到越靠裡同心圓,層級越高。

這是一個元件依賴模組示意圖,其中 Translate 元件層級最高,同樣我們服務也符合這種模型。

好大夫線上在解構服務風險治理方面的實踐

所謂高層、低層,我們這麼界定,離使用者側越近層級越低,離使用者側越遠層級越高。換個說法,離輸入輸出端越近層級越低。

上下游服務,符合資料流返回方向,從上游到下游,從高層到低層。

低層依賴高層,下游依賴上游,避免不合理的依賴成為風險點,如雙向依賴,環形依賴等。

那依賴不合理為啥會影響延遲呢?

好大夫線上在解構服務風險治理方面的實踐

如果存在環形依賴 B->E->C->B,E 抖動會造成 C 負載高,從而可能造成 B 負載高,又會反過來作用 E。這時候排查定位問題會非常困難,三個服務都在告警,整個鏈路都在超時,恢復起來會非常麻煩。我們處理好合理的依賴,避免這樣的情況產生,不要讓已知風險成為定時炸彈。

由於網路開銷成本較高,另外一個風險就是迴圈依賴。由於我們走的 http 協議,網路成本比較高,如果一次請求 50ms,迴圈 10 次就是 500ms。從而變成了大殺器。服務拆分並不是越細越好,做好服務邊界的界定,減少不必要的服務間依賴。做好服務間依賴監控,就得依賴鏈路分析了。有機會我們再細聊這部分的實現。

第二大忌:中介軟體 100% 可用

很多開發工程師對中介軟體的認知停留黑盒層面,要麼盲目地認為中介軟體 100% 高可用,要麼認為中介軟體異常和我無關。然而中介軟體使用是否合理,是否存在風險點,一直是被大家忽視的一個問題。再加上中介軟體細節被框架遮蔽了,很多時候更是很難覺察到風險。這裡先拋開中介軟體選型是否合理的問題,假設依賴的中介軟體都是合理的,我們來分析一下中介軟體延遲問題。

中介軟體一般分建連和執行兩個階段,由於框架的異構性,有的實現了連線池的長連線,有的是短連線。網路連線也是一種資源型別,也屬於消耗品。延遲高會造成排隊,更有可能造成雪崩事件。當然中介軟體應該要考慮如何防止雪崩有過載防護機制。那作為服務方是不是什麼事都幹不了呢?

我們要警惕這種思想,至少我們應該關注高延遲的事件,現在我們資料庫和 redis 都是按服務維度隔離。延遲會直接反饋到使用者請求的鏈路上。建連超過 1s 可能是資源不夠用,吃不住這麼大的流量。如果是執行慢,大部分需要考慮是不是姿勢不太對,這裡面主要是可能存在慢 SQL。

我們針對不同的事件也提煉出了一些風險任務。

首先是建連耗時及重試次數,這部分對短連線的場景下尤為重要,頻繁建連會帶來巨大的開銷。我們選取 connection 耗時作為指標。

然後就是慢 SQL 風險任務,我們選取了執行時長作為指標,執行時長超過 1s 的需要重點關注。

其次我們大部分業務場景是基於 Mysql,如果有在大分頁,或者查詢結果集過大,或者有 like 語句,或者沒有 where 條件等,極有可能造成服務記憶體洩漏和執行過慢的問題。

還有快取依賴,鎖依賴問題。大部分業務使用 Redis 做片段快取和共享鎖,獲取鎖超時異常,快取被穿透等,可能會造成資料庫被拖死,我們需要關注命中率和 Redis 互動的延遲。

另外 RabbitMQ 消費者,Prefetch count 預取數,如果訊息過大,一次取的過多,都可能造成 OOM。php 框架與 RabbitMQ 心跳時間 60s,這塊就需要 php 消費者耗時不能超過兩個心跳週期,也就是 120s。

這塊涉及的細節比較多,今天就不展開了,總之,服務不能太依賴中介軟體的 100% 高可用,需要考慮失敗的可能及一些技巧。拓寬自己的認知邊界,以正確的姿勢更好地使用中介軟體。

第三大忌:第三方服務的鍋,我背不動

再講一下第三方依賴吧,這塊也是我在日常處理問題中比較常見的型別。一說第三方問題就各種抱怨,不是我的鍋。業務需求不可避免要與第三方互動,基於 SDK 或 Http 等。常見的有使用者請求同步等待短網址生成,調第三方語音轉文字服務,呼叫騰訊 api,呼叫簡訊、電話運營商服務,呼叫 ios/ 友盟 sdk 推送等等。遇到最多的就是業務反饋 mq 消費者夯住了不再工作了,指令碼執行超過 2 天了,使用者請求大量 499 了等等。

大部分是過度信賴第三方,或者沒有意識到第三方的問題,或者寫程式碼的時候只考慮功能,未相容異常情況。最常見的做法是需要做超時配置,如果是執行緒池或者長連線的模式,就需要做心跳保活機制了。提升第三方依賴高可用另外一個手段就是冗餘備份,支援災備切換。這部分只要意識到,做好幾個關鍵指標的監控如延遲和成功率,基本上都能避免。

處理好這些依賴風險點,服務的整體穩定性就提高了,關於服務高可用其他的點可以參考下面這張圖,這塊有時間我們再細聊。

好大夫線上在解構服務風險治理方面的實踐

冒  險

前面講了我們是如何分析依賴提煉出風險任務,大家也有了服務風險意識。接下來分享一下我們是如何錘鍊服務風險治理平臺的。平臺整體是基於鏈路日誌分析,整合風險通知,整合 DBA 慢 SQL 最佳化建議,整合資料視覺化畫像。

好大夫線上在解構服務風險治理方面的實踐

下面簡單聊一下平臺設計中遇到的一些問題。

如何保障收益最大化?

好大夫線上在解構服務風險治理方面的實踐

我們先來看一個模型,由於每個人對風險的好惡容忍度是不一樣的。有的開發工程師會說 p99 才 200ms 左右,很健康呀。因此我們需要給定衡量的標準。

還有些開發工程師會考慮最佳化後的收益,有些任務最佳化成本低但收益不高,有些最佳化成本高但收益也大。因此需要評定風險任務的等級,讓開發工程師關注質量而不是數量,以便抓住收益最大化。結合我們的現狀,現階段服務介面延遲風險是我們最大的痛點。

如何準確地識別服務延遲風險?為了識別延遲風險,制定收益最大化 SLO,我們做了很多實驗,並參考業內其他公司的經驗,我們結合 p99,慢介面 qpm 設定了標準。最終達到後端服務 p99 小於 100ms,前端服務 p99 小於 600ms。

sum(appslow_count>y) by(appname,method) and sum(appslow_p99>x) by (appname,method)

如何讓開發工程師抓住重點?我們有了 SLO,識別出延遲風險後,我們會根據耗時,訪問量給任務打上不同的優先順序。並且平臺支援開發工程師分階段制定最佳化計劃,方便任務追蹤。針對依賴的上游服務慢導致自己慢的,可以給對方送臭雞蛋,催促對方最佳化。每個 Q 會統計臭雞蛋最多的服務,邀請開發共賞。所以優先最佳化高風險和收到臭雞蛋多的介面。

如何最佳化延遲風險任務?延遲風險具備相似的特性,有的存在迴圈呼叫,有的存在慢 SQL,有的存在依賴不合理等。基於不同的特徵我們給風險任務打上不同的標籤,針對每種標籤給出相應的最佳化建議。如存在迴圈呼叫,就會給出具體的幾組詳情,配合 APM 鏈路分析,直達案發現場。如存在慢 SQL,打通 DBA SQL 最佳化引擎,給出最佳化建議。

如何實現資料視覺化?風險任務最佳化週期一般比較長,服務的健康度需也要拉大時間維度去檢視。不同的角色關注的維度也不太一樣,不同的場景關注的維度也不一樣。也就是平臺需要具備 OLAP 資料庫查詢的能力,支援上卷,下鑽按不同維度聚合資料並可視化展示。

按事業部維度:

好大夫線上在解構服務風險治理方面的實踐

按服務維度:

好大夫線上在解構服務風險治理方面的實踐

債務佔比趨勢:

好大夫線上在解構服務風險治理方面的實踐

歷  險

最後我們來實戰體驗一下服務風險治理平臺是如何工作的。

任務列表:

好大夫線上在解構服務風險治理方面的實踐

首先我們能直觀的看到服務的延遲線,p50,p75,p95,p99,四條線越聚攏服務越穩定。這塊有個設計技巧,需要按時間稀疏,支援檢視全年趨勢。30 分鐘內支援按秒實時聚合查詢,這塊我們採用直接查詢 Clickhouse 中儲存的原始日誌。然後每分鐘打點轉換成 metrics,然後儲存到 GraphiteMergeTree 引擎資料庫中。GraphiteMergeTree 支援稀疏策略,7d 內按 1h 的平均值進行稀疏,7d 以上按 1d 平均值進行稀疏。

任務列表支援不同維度,不同標籤的聚合檢索。預設按優先順序排序,方便開發工程師抓住收益高的風險任務,同時高亮計劃快過期任務。

任務詳情:

好大夫線上在解構服務風險治理方面的實踐

我們給出介面的詳細畫像,如果慢 SQL 會高亮提醒。給出相關的最佳化建議,結合 APM 鏈路入口,定位到案發現場。

好大夫線上在解構服務風險治理方面的實踐

針對慢 SQL,我們提取 SQL 指紋,與 DBA SQL 最佳化分析引擎對接,給出最佳化建議。

好大夫線上在解構服務風險治理方面的實踐

具體實戰工作涉及的細節比較多,需要從系統、中介軟體、程式碼甚至需求層面綜合考慮,本次就先不展開了,後續還會單獨講,感興趣的同學可以關注一下。

總之,最佳化風險任務是個長期工程,我們需要制定計劃,給予提醒,方便開發工程師提前將這些工作納入自己的 OKR 來落地。平臺也會提供最佳化工作總結報表,推出週報、季度報告等,直接傳送給相關事業部的業務和技術負責人。

小  結

本次分享主要基於 MDD 指導思想,以指標為導向,深入分析服務風險模型,講解了服務風險治理的一般模式,降低服務延遲,規避風險。一步步帶領大家探索如何將未知的未知風險,轉換成已知的未知風險,最終轉換成已知的已知風險。希望對大家的日常工作有所幫助,也歡迎大家一起交流學習。

年終理財爆款福利!領取8%+理財券,每日限額2000份,先到先得!

TAG: 服務風險中介軟體依賴延遲