[點(diǎn)晴永久免費(fèi)OA]國民級應(yīng)用:微信是如何防止崩潰的?
導(dǎo)讀 微信作為月活過10億的國民級應(yīng)用,經(jīng)常面臨特殊節(jié)點(diǎn)消息量暴增的問題,服務(wù)很容易出現(xiàn)過載。但微信的服務(wù)一直比較穩(wěn)定,是如何做到的呢?本文邀請到了騰訊WXG后開開發(fā)工程師alexccdong以微信 2018 年發(fā)表于Socc會議上的文章《Overload Control for Scaling Wechat Microservices》 為基礎(chǔ),介紹微信大規(guī)模微服務(wù)的過載保護(hù)策略,其中很多方法很有借鑒意義。歡迎繼續(xù)閱讀。 過載保護(hù)基本概念1)什么是服務(wù)過載?服務(wù)過載就是服務(wù)的請求量超過服務(wù)所能承受的最大值,從而導(dǎo)致服務(wù)器負(fù)載過高,響應(yīng)延遲加大。用戶側(cè)表現(xiàn)就是無法加載或者加載緩慢。這會引起用戶進(jìn)一步的重試,服務(wù)一直在處理過去的無效請求,導(dǎo)致有效請求跌 0,甚至導(dǎo)致整個系統(tǒng)產(chǎn)生雪崩。 2)為什么會發(fā)生服務(wù)過載?互聯(lián)網(wǎng)天生就會有突發(fā)流量。秒殺、搶購、突發(fā)大事件、節(jié)日甚至惡意攻擊等,都會造成服務(wù)承受平時數(shù)倍的壓力。微博經(jīng)常出現(xiàn)某明星官宣結(jié)婚或者離婚導(dǎo)致服務(wù)器崩潰的場景,這就是服務(wù)過載。 3)過載保護(hù)的好處提升用戶體驗(yàn)、保障服務(wù)質(zhì)量。在發(fā)生突發(fā)流量時仍然能夠提供一部分服務(wù)能力,而不是整個系統(tǒng)癱瘓,系統(tǒng)癱瘓就意味著用戶流失、口碑變差、夫妻吵架甚至威脅生命安全(例如提供醫(yī)療資源協(xié)調(diào)服務(wù)的app)。 微信中的過載場景微信采用的是微服務(wù)。微服務(wù)采用統(tǒng)一的 RPC 框架搭建一個個獨(dú)立的服務(wù),服務(wù)之間互相調(diào)用,實(shí)現(xiàn)各種各樣的功能,這也是現(xiàn)代服務(wù)的基本架構(gòu)。畢竟誰也不想看到自己朋友圈崩掉導(dǎo)致聊天功能也無法正常使用。 微信的服務(wù)是分三層:接入服務(wù)、邏輯服務(wù)、基礎(chǔ)服務(wù)。大多數(shù)服務(wù)屬于邏輯服務(wù),接入服務(wù)如登錄、發(fā)消息、支付服務(wù),每日請求量在 10 億-100 億之間,入口協(xié)議觸發(fā)對邏輯服務(wù)和基礎(chǔ)服務(wù)更多的請求,核心服務(wù)每秒要處理上億次的請求。 在大規(guī)模微服務(wù)場景下,過載會變得比較復(fù)雜。如果是單體服務(wù),一個事件只用一個請求。但微服務(wù)下,一個事件可能要請求很多的服務(wù),任何一個服務(wù)過載失敗,就會造成其他的請求都是無效的。如下圖所示: 比如在一個轉(zhuǎn)賬服務(wù)下,需要查詢分別兩者的卡號,再查詢 A 時成功了,但查詢B失敗,對于查卡號這個事件就算失敗了,比如查詢成功率只有 50%,那對于查詢兩者卡號這個成功率只有 50% * 50% = 25% 了,一個事件調(diào)用的服務(wù)次數(shù)越多,那成功率就會越低。 如何判斷過載通常判斷過載可以使用吞吐量、延遲、CPU 使用率、丟包率、待處理請求數(shù)、請求處理事件等等。微信使用在請求在隊(duì)列中的平均等待時間作為判斷標(biāo)準(zhǔn),就是從請求到達(dá),到開始處理的時間。 為啥不使用響應(yīng)時間?因?yàn)轫憫?yīng)時間是跟服務(wù)相關(guān)的,很多微服務(wù)是鏈?zhǔn)秸{(diào)用,響應(yīng)時間是不可控的,也是無法標(biāo)準(zhǔn)化的,很難作為一個統(tǒng)一的判斷依據(jù)。 那為什么不使用 CPU 負(fù)載作為判斷標(biāo)準(zhǔn)呢?因?yàn)?CPU 負(fù)載高不代表服務(wù)過載,一個服務(wù)請求處理及時,CPU 處于高位反而是比較良好的表現(xiàn)。實(shí)際上 CPU 負(fù)載高,監(jiān)控服務(wù)是會告警出來,但是并不會直接進(jìn)入過載處理流程。 騰訊微服務(wù)默認(rèn)的超時時間是 500ms,通過計(jì)算每秒或每 2000 個請求的平均等待時間是否超過 20ms,判斷是否過載,這個 20ms 是根據(jù)微信后臺 5 年摸索出來的門檻值。 采用平均等待時間還有一個好處是這個是獨(dú)立于服務(wù)的,可以應(yīng)用于任何場景,而不用關(guān)聯(lián)于業(yè)務(wù),可以直接在框架上進(jìn)行改造。 當(dāng)平均等待時間大于 20ms 時,以一定的降速因子過濾調(diào)部分請求。如果判斷平均等待時間小于 20ms,則以一定的速率提升通過率。一般采用快降慢升的策略,防止大的服務(wù)波動。整個策略相當(dāng)于一個負(fù)反饋電路。 過載保護(hù)策略一旦檢測到服務(wù)過載,需要按照一定的策略對請求進(jìn)行過濾。前面分析過,對于鏈?zhǔn)秸{(diào)用的微服務(wù)場景,隨機(jī)丟棄請求會導(dǎo)致整體服務(wù)的成功率很低。所以請求是按照優(yōu)先級進(jìn)行控制的, 優(yōu)先級低的請求會優(yōu)先丟棄。 1)業(yè)務(wù)優(yōu)先級 對于不同的業(yè)務(wù)場景優(yōu)先級是不同的。比如登錄場景是最重要的業(yè)務(wù),不能登錄一切都白費(fèi)。支付消息也比普通消息優(yōu)先級高,因?yàn)橛脩魧疱X是更敏感的。但普通消息又比朋友圈消息優(yōu)先級高。所以在微信內(nèi)是天然存在業(yè)務(wù)優(yōu)先級的。 用戶的每個請求都會分配一個優(yōu)先級。在微服務(wù)的鏈?zhǔn)秸{(diào)用下,下游請求的優(yōu)先級也是繼承的。比如我請求登錄,那么檢查賬號密碼等一系列的的后續(xù)請求都是繼承登錄優(yōu)先級的,這就保證了優(yōu)先級的一致性。 每個后臺服務(wù)維護(hù)了業(yè)務(wù)優(yōu)先級的hash表。微信的業(yè)務(wù)太多,并非每個業(yè)務(wù)都記錄在表里,不在表里的業(yè)務(wù)就是最低優(yōu)先級。 2)用戶優(yōu)先級很明顯,只基于業(yè)務(wù)優(yōu)先級的控制是不夠的。首先不可能因?yàn)樨?fù)載高,丟棄或允許通過一整個業(yè)務(wù)的請求。每個業(yè)務(wù)的請求量很大,那一定會造成負(fù)載的大幅波動。另外如果在業(yè)務(wù)中隨機(jī)丟棄請求,在過載情況下還是會導(dǎo)致整體成功率很低。 解決這個問題可以引入用戶優(yōu)先級。首先用戶優(yōu)先級也不應(yīng)該相同,對于普通人來說通過 hash 用戶唯一 ID,計(jì)算用戶優(yōu)先級,為了防止出現(xiàn)總是打豆豆的現(xiàn)象,hash 函數(shù)每小時更換,跟業(yè)務(wù)優(yōu)先級一樣,單個用戶的訪問鏈條上的優(yōu)先級總是一致的。 為啥不采用會話 ID 計(jì)算優(yōu)先級呢?從理論上來說采用會話 ID 和用戶 ID 效果是一樣的。但是采用會話 ID 在用戶重新登錄時刷新,這個時候可能用戶的優(yōu)先級可能變了,在過載的情況下,可能因?yàn)樘岣吡藘?yōu)先級就恢復(fù)了。這樣用戶會養(yǎng)成壞習(xí)慣,在服務(wù)有問題時就會重新登錄,這樣無疑進(jìn)一步加劇了服務(wù)的過載情況。 引入了用戶優(yōu)先級,那就和業(yè)務(wù)優(yōu)先級組成了一個二維控制平面。根據(jù)負(fù)載情況,決定這臺服務(wù)器的準(zhǔn)入優(yōu)先級(B,U),當(dāng)過來的請求業(yè)務(wù)優(yōu)先級大于 B,或者業(yè)務(wù)優(yōu)先級等于 B,但用戶優(yōu)先級高于 U 時,則通過,否則決絕。 3)自適應(yīng)優(yōu)先級調(diào)整在大規(guī)模微服務(wù)場景下,服務(wù)器的負(fù)載是變化非常頻繁的,所以服務(wù)器的準(zhǔn)入優(yōu)先級是需要動態(tài)變化的。微信分了幾十個業(yè)務(wù)優(yōu)先級,每個業(yè)務(wù)優(yōu)先級下有 128 個用戶優(yōu)先級,所以總的優(yōu)先級是幾千個。 如何根據(jù)負(fù)載情況調(diào)整優(yōu)先級呢?最**簡單的方式是從右到左遍歷,每調(diào)整一次判斷下負(fù)載情況,這個時間復(fù)雜度是 O(n), 就算使用二分法,時間復(fù)雜度也為 O(logn)。**在數(shù)千個優(yōu)先級下,可能需要數(shù)十次調(diào)整才能確定一個合適的優(yōu)先級,每次調(diào)整好再統(tǒng)計(jì)優(yōu)先級,可能幾十秒都過去了,這個方法無疑是非常低效的。 微信提出了一種基于直方圖統(tǒng)計(jì)的方法快速調(diào)整準(zhǔn)入優(yōu)先級,服務(wù)器上維護(hù)者目前準(zhǔn)入優(yōu)先級下,過去一個周期的(1s 或 2000 次請求)每個優(yōu)先級的請求量,當(dāng)過載時,通過消減下一個周期的請求量來減輕負(fù)載,假設(shè)上一個周期所有優(yōu)先級的通過的請求總和是N。下一個周期的請求量要減少N*a,怎么去減少呢?每提升一個優(yōu)先級就減少一定的請求量,一直提升到減少的數(shù)目大于目標(biāo)量,恢復(fù)負(fù)載使用相反的方法,只不是系數(shù)為b,比a小,也是為了快降慢升。根據(jù)經(jīng)驗(yàn)值a為 5%,b為1%。 為了進(jìn)一步減輕過載機(jī)器的壓力,能不能在下游過載的情況下不把請求發(fā)到下游呢?否則下游還是要接受請求、解包、丟棄請求,白白浪費(fèi)帶寬也加重了下游的負(fù)載。 為了實(shí)現(xiàn)這個能力,在每次請求下游服務(wù)時,下游把當(dāng)前服務(wù)的準(zhǔn)入優(yōu)先級返回給上游,上游維護(hù)下游服務(wù)的準(zhǔn)入優(yōu)先級,如果發(fā)現(xiàn)請求優(yōu)先級達(dá)不到下游服務(wù)的準(zhǔn)入門檻,直接丟棄,而不再請求下游,進(jìn)一步減輕下游的壓力。 總結(jié)微信整個負(fù)載控制的流程如圖所示: 當(dāng)用戶從微信發(fā)起請求,請求被路由到接入層服務(wù),分配統(tǒng)一的業(yè)務(wù)和用戶優(yōu)先級,所有到下游的字請求都繼承相同的優(yōu)先級。根據(jù)業(yè)務(wù)邏輯調(diào)用1個或多個下游服務(wù)。當(dāng)服務(wù)收到請求,首先根據(jù)自身服務(wù)準(zhǔn)入優(yōu)先級判斷請求是接受還是丟棄。服務(wù)本身根據(jù)負(fù)載情況周期性的調(diào)整準(zhǔn)入優(yōu)先級。當(dāng)服務(wù)需要再向下游發(fā)起請求時,判斷本地記錄的下游服務(wù)準(zhǔn)入優(yōu)先級。如果小于則丟棄,如果沒有記錄或優(yōu)先級大于記錄則向下游發(fā)起請求。下游服務(wù)返回上游服務(wù)需要的信息,并且在信息中攜帶自身準(zhǔn)入優(yōu)先級。上游接受到返回后解析信息,并更新本地記錄的下游服務(wù)準(zhǔn)入優(yōu)先級。 整個過載保護(hù)的策略有以下三個特點(diǎn):第一,業(yè)務(wù)無關(guān)的,使用請求等待時間而不是響應(yīng)時間來制定用戶和業(yè)務(wù)優(yōu)先級,這些都與業(yè)務(wù)本身無關(guān)。第二,獨(dú)立控制和聯(lián)合控制結(jié)合,準(zhǔn)入優(yōu)先級取決于獨(dú)立的服務(wù),但又可以聯(lián)合下游服務(wù)的情況,優(yōu)化服務(wù)過載時的表現(xiàn)。第三,高效且公平。請求鏈條的優(yōu)先級是一致的,并且會定時改變hash函數(shù)調(diào)整用戶優(yōu)先級。過載情況下,不會總是影響固定的用戶。 該文章在 2023/6/25 9:06:20 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |