分享:備戰 618 如何保障系統穩定

分享:備戰 618 如何保障系統穩定

每年 618 的大促都是一場技術團隊大練兵的時候。作為技術研發人員,在這場戰鬥中,加深了對線上系統的敬畏之心,通過系統的備戰,在技術上也得到了提升。大戰在即,如何保障系統穩定,我們的備戰思路是什麼?

首先確定自己的備戰思路,梳理核心流程、找出薄弱點,對薄弱點進行優化,針對業務進行資源隔離,同時協調壓測對優化結果進行驗證,並針對場景準備預案,比如降級開關在什麼場景下開啟,以及降級之後的影響有哪些等等,後面還要實際演練,防止實際情況發生時準備好的預案不可用。

我們知道,618 期間發生的問題都不是小問題,所以,如何做到更周密的籌備,我們可以秉承如下幾個原則:

  • 墨菲定律:任何事都沒有表面看起來那麼簡單;所有的事都會比你預計的時間長;會出錯的事總會出錯;如果你擔心某種情況發生,那麼它就更有可能發生。
  • 二八原則:19世紀末意大利經濟學家巴萊多認為,在任何一組東西中,最重要的只佔其中一小部分,約20%,其餘80%儘管是多數,卻是次要的,這就是二八法則。二八法則告訴我們,不要平均地分析、處理和看待問題,要把主要精力花在解決主要問題、抓主要項目上。

我們可以利用墨菲定律來梳理系統薄弱點,那些總是小問題不斷的地方,一定會在某天釀成大的災難,必須儘早解決。還可以利用二八原則梳理黃金流程,那些出了問題可能極大影響公司或影響用戶的地方,就是不容有失的黃金流程。

分享:備戰 618 如何保障系統穩定

我們以此為思路,從四個方面進行逐一介紹。

一、梳理薄弱點

1. 梳理系統架構

備戰第一步,就是要對系統做一次全面的梳理診斷,其目的就是要甄別出系統的薄弱點。而梳理的第一步,就是要梳理出系統架構。通過梳理系統架構,梳理系統的層次結構和調用關係,由此排查系統調用的瓶頸和薄弱點。如是否有服務節點是熱點或單點服務,是否有過長的調用鏈路,是否存在業務耦合相互影響等等。

以我現在負責的京東服務市場為例,服務市場採用 SOA 微服務化的架構設計理念,將服務市場設計為模塊化和層次化的架構風格,高層次模塊調用低層次模塊,低層次模塊通過接口向上提供服務。而複雜的調用鏈路,必然造成業務之間的相互影響,所以,通過對服務市場從部署、數據庫訪問、服務 PRC 調用、消息接收等進行了縱向垂直部署隔離,實現即使任一垂直域無論因為服務器還是數據庫問題,影響不會擴散到其他業務上。這我會在後面詳細講述如何實現縱向垂直部署隔離。

分享:備戰 618 如何保障系統穩定

2. 梳理系統薄弱點

無論系統架構是以哪種形式展示,我們都希望能夠通過梳理把系統的薄弱點甄別出來。那系統薄弱點都有哪些特徵呢?通過哪些手段能檢查出系統薄弱點?

我們想一下,系統薄弱點可能引發哪些災難,嚴重的有系統宕機,服務不可用,性能下降,404,CPU 100%,OOM 等等,所以,可能產生上述隱患的點就是我們要關注的系統薄弱點。對於系統薄弱點,我們可以通過以下幾點進行排查:

  • 檢查沒有脫庫的功能:我們知道大促時的流量可能是平時的2~10倍,所以一些平時性能還好的查詢接口,極有可能因調用量猛增,造成性能的極劇下降,如果其中的某些接口還是查詢數據庫的,那可能就會給數據庫產生極大的壓力,極端情況可能造成數據庫 CPU 100%,出現服務不可用,因為數據庫本身的架構設計就不是抗量的,所以對沒有必要查庫的功能進行脫庫改造,以保證數據庫的穩定,是非常重要的,尤其是那些嚴重依賴數據庫的系統。
  • 檢查慢 sql:不是所有的功能都能實現脫庫的,所以慢 sql 的檢查就是為了保證數據庫的穩定,因為一個慢 sql 就有可能把數據庫的 CPU 打到100%,一是由於慢 sql 最容易出現的是沒有索引,二是由於慢 sql 大多是關聯查詢、嵌套查詢,以及使用聚合函數等造成的,還有就是慢 sql 大多需要回源查詢,大量的請求會造成查詢能力特別慢,還會造成其他請求無法獲取連接,影響正常服務。所以,對於那些特別依賴數據庫的系統,要每日訂閱慢 sql,進行優化。優化就是優化數據庫索引,將慢 sql 變成快 sql。
  • 檢查 ump 和 log:人常說,研發人員有兩隻眼睛,一隻是監控報警,另一隻就是日誌,所以無論什麼情況監控報警日誌一定不能少。因為有了監控就能做到即時發現問題,有了日誌就能做到迅速定位問題。否則,出了問題,就是兩眼一抹黑,一通胡猜。我經常看到,當有些問題從客服那裡投訴過來,才發現,要麼該有的監控沒有,要麼有監控卻沒有報警,以及在解決問題時總是找不到關鍵的日誌,只能乾著急。
  • 檢查 jsf、mysql、jmq 等 timeout:設置 timeout 實際上是一種快速失敗策略,使系統具備自我保護的能力。檢查超時,一是檢查該有的設置有沒有,二是檢查設置的時間是否過長。沒有超時設置,則系統就沒有自我保護的能力,這自不必說,當大量請求連接因為長時間運行而無法得到釋放時,系統的資源很快就會被耗盡,從而造成了服務的不可用。而過長的設置,同樣在訪問量大的時候,就會導致請求連接積壓,這也會導致系統的 CPU 快速飆升。那超時應該設置多少合適,這需要具體情況具體分析,但一個查詢請求設置 10s 超時肯定是跟沒設置一樣的。
  • 檢查 redis 熱 key、大 key、慢日誌:熱 key 和 大 key 是不同的,熱 key 是某些 key 可能會被突然暴增的流量大量訪問,這些 key 又碰巧集中存儲在同一分片上,從而使得該分片的 IO、CPU 等資源吃緊,極端情況下迫使 redis 進行 failover 主從切換,但切換後的瞬時流量可能又一下子擊穿 redis,迫使 redis 再次 failover,如此反覆,服務幾乎就是不可用的。而大 key 則是某些 key 存儲的 value 很大,或者結果集很多,也是在可能暴增的流量下,大 key 不合理的查詢,使得 value 在 IO 傳輸中阻塞,這情況和慢 sql 很像,又因為 redis 是單線程,所以大 key 查詢造成 IO 問題就會很容易凸顯出來。所以,如果檢查出熱 key 或大 key,就建議進行修改。
  • 檢查 master-slave 同步延遲:master-slave 同步延遲很大可能造成數據不一致性,這有可能影響業務正常運營,如創建訂單寫到 master,然後從 slaver 查詢訂單,但由於延遲太大,就可能影響用戶查不到,你可能會說,這還好吧,慢1~2s不會有太大影響,但這個邏輯如果放在創建訂單之後馬上查詢訂單,根據查到的訂單創建結算,在這個場景下,如何查詢 slave 找不訂單,就是不可接受的,這可能導致流程代碼出錯。所以,需要評估這種延遲是否對業務產生影響。
  • 檢查定時 worker 全量掃描任務:定時 worker 大多數是在運行數據訂正的任務,而數據訂正往往又需要查詢大量數據進行比對,其實,這都還好,不好的就是幾次深分頁的查詢,可能造成數據庫性能的極劇下降。所以,檢查定時 worker,尤其要避免慢 sql 和大數據集的查詢,否則會造成人為的流量洪峰。還有,檢查定時 worker的執行頻率,檢查不同 worker 的執行時間,儘量避免不同 worker 同時執行,檢查定時 worker 執行的服務器是否單獨部署。
  • 與運營溝通 618 運營節奏,應戰調用量高峰:提前與運營溝通運營節奏,可以做到知己知彼,並可以預知流量可能流向哪裡,這可以有針對性的進行備戰。

3. 梳理黃金流程

黃金流程也稱核心流程,什麼是黃金流程,就是那些出了問題可能極大影響公司或影響用戶的地方,就是不容有失的黃金流程。以服務市場為例,服務市場包括服務發佈、服務審核、服務訂購、服務結算、服務使用共五個環節,那其中哪些是重中之重的核心環節呢?服務市場是面向供需雙方的雙邊市場,以需求方為大頭,所以服務訂購和服務使用是服務市場的核心環節。

梳理黃金流程,我們要整理出它的大致流向和關鍵節點,通過系統流向和關鍵節點發現系統設計不合理的地方,以服務市場交易流程問題,我們看到在履約中心訂單完成後,通過觀察者模式發送消息、創建訂購、推送結算的設計是存在風險的,因為每個觀察者失敗了就失敗了,且每個觀察者的業務邏輯都不是冪等邏輯。這種設計的不合理,就必須通過梳理黃金流程來發現。

分享:備戰 618 如何保障系統穩定

二、資源隔離

梳理依賴資源(docker、vip、mysql、jimdb、es、jsf、jmq),及目前資源的服務器狀況是否健康(cpu、memory、dish 等),進行縱向垂直部署隔離,實現即使任一垂直域無論因為服務器還是數據庫問題,影響不會擴散到其他業務上,而這也是所謂的分離技術。

docker 資源

梳理系統 docker 資源部署情況,設定 x 軸是各個業務線,y 軸是業務系統,整理出一張二維表,根據之前梳理的系統架構圖,可以清晰的看到各業務線下各個業務系統在不同機房的部署情況,如是否雙機房部署,是否有熱備機房,是否部署資源不合理等。機房1和機房2之間是兩個不同的地域部署,所以通過地域可以實現容災。還有,雖然系統都是一套代碼,但可以根據各業務線的具體情況,某些業務線不需要的某些系統就不部署,因為代碼走不到那裡,並可根據業務調用量,合理配置資源情況。

梳理資源,一是梳理自己的資源部署情況,二是需要對上下游依賴系統,做到資源對齊(為了效率考慮,目前很多應用正常情況是同機房調用)譬如:如果上游部署在3個機房,機房A、機房B、機房C,流量配比是5.3.2,那我們也應該按照該比例部署。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

vip 資源

檢查 vip 配置,避免因為 docker 擴容或縮容,導致的 vip 配置錯誤,將擴容的 docker 加到 vip 中,將縮容的 docker 從 vip 中去掉。檢查運營商的 IP 解析情況,譬如,需要支持電信、聯通、移動、教育網等。當然,並不是所有業務系統都提供對外服務。熱備機房不掛 vip,否則就會有線上流量了。當主力機房出問題的時候,通過將問題機房的 vip 飄到熱備機房,從而實現流量切換。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

MySQL 隔離

在 docker 資源的部署背景下,我們繪製 mysql 資源的部署情況,其中,有些業務線下的機房雖然有部署系統,但該業務線的流程是已經脫庫的,所以就可以不配置數據庫。還有某些流程在某些業務線下只有讀操作,沒有寫操作的,所以,數據庫只配置讀庫,而不配置寫庫。以及最重要的,不同業務線的應該使用不同的從庫,並根據查詢數據庫的業務量,合理配置從庫資源規格。mysql 與 docker 儘可能在同機房部署,這也可以有效的實現系統容災。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

Redis / Solr / ES 隔離

繪製 redis、solr、es 部署情況與繪製 mysql 思路一樣。特別說下,服務市場部署 redis 與 mysql 不同之處在於,redis 是一主一從架構,各業務線共享同一 redis 集群,但不同系統之間使用不同的 redis 集群,所以,如果 redis 掛了,還是會影響所有業務線的,而避免 redis 宕機,則就要注意前面提到的,檢查 redis 的大 key 和熱 key。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

JSF 業務隔離

梳理業務依賴關係,調整 jsf 調用鏈路,通過 jsf 分組進行業務隔離,這其實是最重要的,也是最難的,也只有把這個做好,才能實現各業務線出了問題不會相互影響。我們知道,一個系統裡,既有 provider 也有 consumer,我們要做的就是保證在某一個業務線內,該業務線內 consumer 一定調用該業務線內的 provider 的,如服務市場的業務線 B,那一定是大前臺在業務線 B 下只能調用業務線 B 的商品中心、交易中心、服務引擎等,而這實現就是通過 jsf 的分組別名,這沒有啥技術含量,就是要了解業務依賴關係,認真仔細。由於系統是一套代碼,對於那些有部署系統,但不提供 jsf 的服務分組,我們可以設置為 disable,以此區分和隔離。

在進行 jsf 分組隔離時,因為工作量很大,很是耗神,還有就會想到一個問題,一個系統提供幾十個甚至上百個 jsf 接口出去,為什麼分組命名會千奇百怪,幾乎是每個 jsf 分組都有自己的命名,但仔細想來 jsf 接口可以做到細粒度隔離,因為 jsf 可以實現進程隔離和線程隔離,這使得即使是同一系統的 provider,也可以實現進一步的細分業務,來隔離各業務間的相互影響。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

JMQ 業務隔離

jmq 大量應用在系統解耦的場景中,而 jmq 同樣有 provider 和 consumer,它不像 jsf 那樣靈活,可以支持多個分組,jmq 只能控制哪些系統生產消息,哪些系統可消費消息。因為 jmq 是通過 topic 進行消息傳遞的,我們不能給每個業務線申請一個 topic,所以 jmq 的隔離更多的是,梳理業務依賴關係,對那些不會生產或消費 jmq 的業務線,設置 topic 為 disable,確定消息會被哪些系統生產,又會被哪些系統消費。

分享:備戰 618 如何保障系統穩定

* 數據僅為示例,不是真實數據;表格形式僅供參考

三、壓測

壓測不是為了把系統壓掛,是否需要測出峰值,需按照業務場景決定。很多業務,可能就需要知道自己的峰值。壓測一定是根據當前調用量進行評估,以2~10倍為預期值進行壓測,壓測還要選在掉用量少的時間,並逐步加量。壓測儘量做到服務器及依賴資源的隔離,如果無法做到,需要控制好量。尤其當壓測會查詢數據庫的服務,一定不要把數據庫壓出問題來,如果壓出問題,就違背了壓測的初衷,壓測是為了把系統的瓶頸壓出來,而不是把系統壓出問題來。即使是完全讀取緩存的服務,也會因壓測造成系統性能的下降,因為數據在傳輸過程中的序列化和反序列化,以及對多線程的切換,都會造成 CPU 的飆升,還有注意磁盤空間是否會被日誌打滿,諸如以上等等問題,不要因為壓測造成一場線上事故。

壓測我們要關注哪些是結果指標,有併發數、TPS、TP99、成功率,這些結果指標能有效反應服務的好壞,以及關注被壓測服務的 docker 的 CPU、內存、load 等系統性能。所以,壓測策略一定是逐步加量,從併發10 - 50 - 100 - 200 - 500,觀察服務的 TPS、TP99、成功率是否有降低,還有被壓測機從 1 - 5 容器數增加,對比單機服務性能是否有所提升。所以,壓測的目的是為了能檢驗服務能力是否支持可水平擴展,即加機器就可以抵抗洪峰。

分享:備戰 618 如何保障系統穩定

分享:備戰 618 如何保障系統穩定

最後,壓測一定要制定計劃,今天壓什麼,明天壓什麼,還有跟兄弟團隊打好招呼,因為別的團隊也會壓測,如果他的服務會調用到你這裡,而這是你也在壓測這個接口,結果超出預期的流量就可能造成意想不到的麻煩。

四、預案

預案准備至關重要,它能保證系統在出問題時,進行及時止損,避免大出血。止損主要以降級開關來實現有損降級,以保證核心黃金流程不受到影響。因為系統業務演進多是混沌的,所以需要對系統的降級開關進行有效的梳理,哪些是有用的,那些是無效的,還要協調兄弟團隊,一起溝通 618 備戰方案,確定演練方案,聯合備戰。

對降級開關的梳理,不能只停留在知道有這個開關的基礎上,還要知道這個降級開關在什麼場景下開啟,以及降級之後的影響有哪些等等,降級邏輯必須場景化,否則出了問題,開關開還是不開,都沒有一個準則。

分享:備戰 618 如何保障系統穩定

總結

當然,在備戰 618 的過程中,有很多事要做,不僅僅是業務隔離和壓測,還要在梳理系統薄弱點過程中發現潛藏的問題,進行針對性的優化改造。這裡有個題外話要說,備戰過程中,我偶爾會聽到一些聲音,讓我非常生氣。

一是說,”之前沒出問題,所以覺得就沒問題“。我見過多少次線上事故,就是因為思想上的怠慢,問題並不是不知道,就是本著僥倖的思想,覺得之前沒問題,覺得現在就沒有問題。這種想法我認為就是錯的,之前沒問題,不代表它不是問題,是問題就是問題。我犯過錯一個錯誤,就是大上週上線報警出一個問題,排查有個慢 sql 查庫,然後進行了修改,不急不慢改一週準備第二天晚上上線,結果第二天早上就被人刷了,數據庫 CPU 直接幹到 80%,好在這個功能有降級,且業務之間進行隔離部署,沒有造成很大的影響。所以,發現問題一定要即時修改。

二是說,”之前的邏輯不是我寫的,我就改了這些,那些代碼我不太清楚“。這種說辭更不可接受,你連你改的代碼上下文都不瞭解,你改什麼代碼,你能不改錯麼。所以,我要求大家,之前的代碼不管誰寫的,我不管了,但現在代碼在你手上,你就必須負責把它寫好,不能總是個臨時方案,開個分支出去,最後代碼一團漿糊。舉個例子,上線新代碼為了能實現快速降級,通常使用開關進行切換,這時系統裡就會有新老兩套代碼,那老代碼什麼時候刪除,如果當時寫代碼的人不負起責任,代碼就那麼放著,也不刪,那後面不僅系統代碼會越來越臃腫,而且代碼的可讀性也會越來越差。甚至不小心弄錯了開關,還會出現意外的彩蛋什麼的。


分享到:


相關文章: