摘要:需要監(jiān)控的維度有登錄總數(shù)成功數(shù)失敗分類用戶地區(qū)版本號(hào)瀏覽器類型登錄來源服務(wù)所在機(jī)房等等。
引言
在任何一家互聯(lián)網(wǎng)公司,不管其主營(yíng)業(yè)務(wù)是什么,都會(huì)有一套自己的賬號(hào)體系。賬號(hào)既是公司所有業(yè)務(wù)發(fā)展留下的最寶貴資產(chǎn),它可以用來衡量業(yè)務(wù)指標(biāo),例如日活、月活、留存等,同時(shí)也給不同業(yè)務(wù)線提供了大量潛在用戶,業(yè)務(wù)可以基于賬號(hào)來做用戶畫像,制定各自的發(fā)展路徑。因此,賬號(hào)服務(wù)的重要性不言而喻,同時(shí)美團(tuán)業(yè)務(wù)飛速發(fā)展,對(duì)賬號(hào)業(yè)務(wù)的可用性要求也越來越高。本文將分享一些我們?cè)诟呖捎锰剿髦械膶?shí)踐。
衡量一個(gè)系統(tǒng)的可用性有兩個(gè)指標(biāo):
1. MTBF (Mean Time Between Failure)即平均多長(zhǎng)時(shí)間不出故障;
2. MTTR (Mean Time To Recovery)即出故障后的平均恢復(fù)時(shí)間。
通過這兩個(gè)指標(biāo)可以計(jì)算出可用性,也就是我們大家比較熟悉的“幾個(gè)9”。
因此提升系統(tǒng)的可用性,就得從這兩個(gè)指標(biāo)入手,要么降低故障恢復(fù)的時(shí)間,要么延長(zhǎng)不出故障的時(shí)間。
1. 業(yè)務(wù)監(jiān)控
要降低故障恢復(fù)的時(shí)間,首先得盡早的發(fā)現(xiàn)故障,然后才能解決故障,這就需要依賴業(yè)務(wù)監(jiān)控系統(tǒng)。
業(yè)務(wù)監(jiān)控不同于其他監(jiān)控系統(tǒng),業(yè)務(wù)監(jiān)控關(guān)注的是各個(gè)業(yè)務(wù)指標(biāo)是否正常,比如賬號(hào)的登錄曲線。大眾點(diǎn)評(píng)登錄入口有很多,從終端上分有App、PC、M站,從登錄類型上分有密碼登錄、快捷登錄、第三方登錄(微信/QQ/微博)、小程序登錄等。需要監(jiān)控的維度有登錄總數(shù)、成功數(shù)、失敗分類、用戶地區(qū)、App版本號(hào)、瀏覽器類型、登錄來源Referer、服務(wù)所在機(jī)房等等。業(yè)務(wù)監(jiān)控能從直觀上告訴我們系統(tǒng)的運(yùn)行狀況。
由于業(yè)務(wù)監(jiān)控的維度很多很雜,有時(shí)還要增加新的監(jiān)控維度,并且告警分析需要頻繁聚合不同維度的數(shù)據(jù),因此我們采用Elasticsearch作為日志存儲(chǔ)。整體架構(gòu)如下圖:
每條監(jiān)控都會(huì)根據(jù)過去的業(yè)務(wù)曲線計(jì)算出一條基線(見下圖),用來跟當(dāng)前數(shù)據(jù)做對(duì)比,超出設(shè)定的閾值后就會(huì)觸發(fā)告警。
每次收到告警,我們都要去找出背后的原因,如果是流量漲了,是有活動(dòng)了還是被刷了?如果流量跌了,是日志延時(shí)了還是服務(wù)出問題了?另外值得重視的是告警的頻次,如果告警太多就會(huì)稀釋大家的警惕性。我們?cè)?jīng)踩過一次坑,因?yàn)楦婢嗑桶迅婢P(guān)了,結(jié)果就在關(guān)告警的這段時(shí)間業(yè)務(wù)出問題了,我們沒有及時(shí)發(fā)現(xiàn)。為了提高每條告警的定位速度,我們?cè)诿織l告警后面加上維度分析。如下圖(非真實(shí)數(shù)據(jù)),告警里直接給出分析結(jié)果。
2. 柔性可用
柔性可用的目的是延長(zhǎng)不出故障的時(shí)間,當(dāng)業(yè)務(wù)依賴的下游服務(wù)出故障時(shí)不影響自身的核心功能或服務(wù)。賬號(hào)對(duì)上層業(yè)務(wù)提供的鑒權(quán)和查詢服務(wù)即核心服務(wù),這些服務(wù)的QPS非常高,業(yè)務(wù)方對(duì)服務(wù)的可用性要求很高,別說是服務(wù)故障,就連任何一點(diǎn)抖動(dòng)都是不能接受的。對(duì)此我們先從整體架構(gòu)上把服務(wù)拆分,其次在服務(wù)內(nèi)對(duì)下游依賴做資源隔離,都盡可能的縮小故障發(fā)生時(shí)的影響范圍。
另外對(duì)非關(guān)鍵路徑上的服務(wù)故障做了降級(jí)。例如賬號(hào)的一個(gè)查詢服務(wù)依賴Redis,當(dāng)Redis抖動(dòng)的時(shí)候服務(wù)的可用性也隨之降低,我們通過公司內(nèi)部另外一套緩存中間件Tair來做Redis的備用存儲(chǔ),當(dāng)檢測(cè)到Redis已經(jīng)非常不可用時(shí)就切到Tair上。
通過開源組件Hystrix或者我們公司自研的中間件Rhino就能非常方便地解決這類問題,其原理是根據(jù)最近一個(gè)時(shí)間窗口內(nèi)的失敗率來預(yù)測(cè)下一個(gè)請(qǐng)求需不需要快速失敗,從而自動(dòng)降級(jí),這些步驟都能在毫秒級(jí)完成,相比人工干預(yù)的情況提升幾個(gè)數(shù)量級(jí),因此系統(tǒng)的可用性也會(huì)大幅提高。下圖是優(yōu)化前后的對(duì)比圖,可以非常明顯的看到,系統(tǒng)的容錯(cuò)能力提升了,TP999也能控制在合理范圍內(nèi)。
對(duì)于關(guān)鍵路徑上的服務(wù)故障我們可以減少其影響的用戶數(shù)。比如手機(jī)快捷登錄流程里的某個(gè)關(guān)鍵服務(wù)掛了,我們可以在返回的失敗文案上做優(yōu)化,并且在登錄入口掛小黃條提示,讓用戶主動(dòng)去其他登錄途徑,這樣對(duì)于那些設(shè)置過密碼或者綁定了第三方的用戶還有其他選擇。
具體的做法是我們?cè)诿總€(gè)登錄入口都關(guān)聯(lián)了一個(gè)計(jì)數(shù)器,一旦其中的關(guān)鍵節(jié)點(diǎn)不可用,就會(huì)在受影響的計(jì)數(shù)器上加1,如果節(jié)點(diǎn)恢復(fù),則會(huì)減1,每個(gè)計(jì)數(shù)器還分別對(duì)應(yīng)一個(gè)標(biāo)志位,當(dāng)計(jì)數(shù)器大于0時(shí),標(biāo)志位為1,否則標(biāo)志位為0。我們可以根據(jù)當(dāng)前標(biāo)志位的值得知登錄入口的可用情況,從而在登錄頁(yè)展示不同的提示文案,這些提示文案一共有2^5=32種。
下圖是我們?cè)谧龉收夏M時(shí)的降級(jí)提示文案:
3. 異地多活
除了柔性可用,還有一種思路可以來延長(zhǎng)不出故障的時(shí)間,那就是做冗余,冗余的越多,系統(tǒng)的故障率就越低,并且是呈指數(shù)級(jí)降低。不管是機(jī)房故障,還是存儲(chǔ)故障,甚至是網(wǎng)絡(luò)故障,都能依賴冗余去解決,比如數(shù)據(jù)庫(kù)可以通過增加從庫(kù)的方式做冗余,服務(wù)層可以通過分布式架構(gòu)做冗余,但是冗余也會(huì)帶來新的問題,比如成本翻倍,復(fù)雜性增加,這就要衡量投入產(chǎn)出比。
目前美團(tuán)的數(shù)據(jù)中心機(jī)房主要在北京上海,各個(gè)業(yè)務(wù)都直接或間接的依賴賬號(hào)服務(wù),盡管公司內(nèi)已有北上專線,但因?yàn)閷>€故障或抖動(dòng)引發(fā)的賬號(hào)服務(wù)不可用,間接導(dǎo)致的業(yè)務(wù)損失也不容忽視,我們就開始考慮做跨城的異地冗余,即異地多活。
3.1 方案設(shè)計(jì)
首先我們調(diào)研了業(yè)界比較成熟的做法,主流思路是分set化,優(yōu)點(diǎn)是非常利于擴(kuò)展,缺點(diǎn)是只能按一個(gè)維度劃分。比如按用戶ID取模劃分set,其他的像手機(jī)號(hào)和郵箱的維度就要做出妥協(xié),尤其是這些維度還有性要求,這就使得數(shù)據(jù)同步或者修改都增加了復(fù)雜度,而且極易出錯(cuò),給后續(xù)維護(hù)帶來困難。考慮到賬號(hào)讀多寫少的特性(讀寫比是350:1),我們采用了一主多從的數(shù)據(jù)庫(kù)部署方案,優(yōu)先解決讀多活的問題。
Redis如果也用一主多從的模式可行嗎?答案是不行,因?yàn)镽edis主從同步機(jī)制會(huì)優(yōu)先嘗試增量同步,當(dāng)增量同步不成功時(shí),再去嘗試全量同步,一旦專線發(fā)生抖動(dòng)就會(huì)把主庫(kù)拖垮,并進(jìn)一步阻塞專線,形成“雪崩效應(yīng)”。因此兩地的Redis只能是雙主模式,但是這種架構(gòu)有一個(gè)問題,就是我們得自己去解決數(shù)據(jù)同步的問題,除了保證數(shù)據(jù)不丟,還要保證數(shù)據(jù)一致。
另外從用戶進(jìn)來的每一層路由都要是就近的,因此DNS需要開啟智能解析,SLB要開啟同城策略,RPC已默認(rèn)就近訪問。
總體上賬號(hào)的異地多活遵循以下三個(gè)原則:
1. 北上任何一地故障,另一地都可提供完整服務(wù)。
2. 北上兩地同時(shí)對(duì)外提供服務(wù),確保服務(wù)隨時(shí)可用。
3. 兩地服務(wù)都遵循BASE原則,確保數(shù)據(jù)最終一致。
最終設(shè)計(jì)方案如下:
3.2 數(shù)據(jù)同步
首先要保證數(shù)據(jù)在傳輸?shù)倪^程中不能丟,因此需要一個(gè)可靠接收數(shù)據(jù)的地方,于是我們采用了公司內(nèi)部的MQ平臺(tái)Mafka(類Kafka)做數(shù)據(jù)中轉(zhuǎn)站??墒窍⒃诮?jīng)過Mafka傳遞之后可能是亂序的,這導(dǎo)致對(duì)同一個(gè)key的一串操作序列可能導(dǎo)致不一致的結(jié)果,這是不可忍受的。但Mafka只是不保證全局有序,在單個(gè)partition內(nèi)卻是有序的,于是我們只要對(duì)每個(gè)key做一遍一致性散列算法對(duì)應(yīng)一個(gè)partitionId,這樣就能保證每個(gè)key的操作是有序的。
但僅僅有序還不夠,兩地的并發(fā)寫仍然會(huì)造成數(shù)據(jù)的不一致。這里涉及到分布式數(shù)據(jù)的一致性問題,業(yè)界有兩種普遍的認(rèn)知,一種是Paxos協(xié)議,一種是Raft協(xié)議。我們吸取了對(duì)實(shí)現(xiàn)更為友好的Raft協(xié)議,它主張有一個(gè)主節(jié)點(diǎn),其余是從節(jié)點(diǎn),并且在主節(jié)點(diǎn)不可用時(shí),從節(jié)點(diǎn)可晉升為主節(jié)點(diǎn)。簡(jiǎn)單來說就是把這些節(jié)點(diǎn)排個(gè)序,當(dāng)寫入有沖突時(shí),以排在最前面的那個(gè)節(jié)點(diǎn)為準(zhǔn),其余節(jié)點(diǎn)都去follow那個(gè)主節(jié)點(diǎn)的值。在技術(shù)實(shí)現(xiàn)上,我們?cè)O(shè)計(jì)出一個(gè)版本號(hào)(見下圖),實(shí)際上是一個(gè)long型整數(shù),其中數(shù)據(jù)源大小即表示節(jié)點(diǎn)的順序,把版本號(hào)存入value里面,當(dāng)兩個(gè)寫入發(fā)生沖突的時(shí)候只要比較這個(gè)版本號(hào)的大小即可,版本號(hào)大的覆蓋小的,這樣能保證寫沖突時(shí)的數(shù)據(jù)一致性。
寫并發(fā)時(shí)數(shù)據(jù)同步過程如下圖:
這種同步方式的好處顯而易見,可以適用于所有的Redis操作且能保證數(shù)據(jù)的最終一致性。但這也有一些弊端,由于多存了版本號(hào)導(dǎo)致Redis存儲(chǔ)會(huì)增加,另外在該機(jī)制下兩地的數(shù)據(jù)其實(shí)是全量同步的,這對(duì)于那些僅用做緩存的存儲(chǔ)來說是非常浪費(fèi)資源的,因?yàn)榫彺嬗袛?shù)據(jù)庫(kù)可以回源。而賬號(hào)服務(wù)幾乎一半的Redis存儲(chǔ)都是緩存,因此我們需要對(duì)緩存同步做優(yōu)化。
賬號(hào)服務(wù)的緩存加載與更新模式如下圖:
我們優(yōu)化的方向是在緩存加載時(shí)不同步,只有在數(shù)據(jù)庫(kù)有更新時(shí)才去同步。但是數(shù)據(jù)更新這個(gè)流程里不能再使用delete操作,這樣做有可能使緩存出現(xiàn)臟數(shù)據(jù),比如下面這個(gè)例子:
我們對(duì)這個(gè)問題的解決辦法是用set(若key不存在則添加,否則覆蓋)代替delete,而緩存的加載用add(若key不存在則添加,否則不修改),這樣能保證緩存更新時(shí)的強(qiáng)一致性卻不需要增加額外存儲(chǔ)??紤]到賬號(hào)修改的入口比較多,我們希望緩存更新的邏輯能拎出來多帶帶處理減少耦合,最后發(fā)現(xiàn)公司內(nèi)部數(shù)據(jù)同步組件Databus非常適用于該場(chǎng)景,其主要功能是把數(shù)據(jù)庫(kù)的變更日志以消息的形式發(fā)出來。于是優(yōu)化后的緩存模式如下圖:
從理論變?yōu)楣こ虒?shí)現(xiàn)的時(shí)候還有些需要注意的地方,比如同步消息沒發(fā)出去、數(shù)據(jù)收到后寫失敗了。因此我們還需要一個(gè)方法來檢測(cè)數(shù)據(jù)不一致的數(shù)量,為了做到這點(diǎn),我們新建了一個(gè)定時(shí)任務(wù)去scan兩地的數(shù)據(jù)做對(duì)比統(tǒng)計(jì),如果發(fā)現(xiàn)有不一致的還能及時(shí)修復(fù)掉。
項(xiàng)目上線后,我們也取得一些成果,首先性能提升非常明顯,異地的調(diào)用平均耗時(shí)和TP99、TP999均至少下降80%,并且在一次線上專線故障期間,賬號(hào)讀服務(wù)對(duì)外的可用性并沒有受影響,避免了更大范圍的損失。
總結(jié)
服務(wù)的高可用需要持續(xù)性的投入與維護(hù),比如我們會(huì)每月做一次容災(zāi)演練。高可用也不止體現(xiàn)在某一兩個(gè)重點(diǎn)項(xiàng)目上,更多的體現(xiàn)在每個(gè)業(yè)務(wù)開發(fā)同學(xué)的日常工作里。任何一個(gè)小Bug都可能引起一次大的故障,讓你前期所有的努力都付之東流,因此我們的每一行代碼,每一個(gè)方案,每一次線上改動(dòng)都應(yīng)該是仔細(xì)推敲過的。高可用應(yīng)該成為一種思維方式。最后希望我們能在服務(wù)高可用的道路上越走越遠(yuǎn)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/3952.html
摘要:淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì)后端掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營(yíng)銷手段。這兩個(gè)項(xiàng)目白話網(wǎng)站架構(gòu)演進(jìn)后端掘金這是白話系列的文章。 淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì) - 后端 - 掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營(yíng)銷手段。 不要整個(gè)系統(tǒng)宕機(jī)。 即使系統(tǒng)故障,也不要將錯(cuò)誤數(shù)據(jù)展示出來。 盡量保持公平公正。 實(shí)現(xiàn)效果 秒殺開始前,搶購(gòu)按鈕為活動(dòng)未開始。 秒殺開始時(shí),搶購(gòu)按鈕可以點(diǎn)擊下單。 秒殺結(jié)束后,按鈕按鈕變...
摘要:解決方案如圖所示,將軍令分塊,數(shù)據(jù)內(nèi)容權(quán)限平臺(tái)審批流平臺(tái)審計(jì)日志平臺(tái)提供各種靈活可插拔的服務(wù),支持在通用服務(wù)的基礎(chǔ)基礎(chǔ)上進(jìn)行定制開發(fā)。 背景 在大數(shù)據(jù)時(shí)代,數(shù)據(jù)已經(jīng)成為公司的核心競(jìng)爭(zhēng)力。此前,我們介紹了美團(tuán)酒旅起源數(shù)據(jù)治理平臺(tái)的建設(shè)與實(shí)踐,主要是通過各種數(shù)據(jù)分析挖掘手段,為公司發(fā)展決策和業(yè)務(wù)開展提供數(shù)據(jù)支持。 近期,業(yè)內(nèi)數(shù)據(jù)安全事件頻發(fā),給相關(guān)企業(yè)造成了無可挽回的損失,更為數(shù)據(jù)安全防護(hù)...
閱讀 1714·2021-11-02 14:47
閱讀 3661·2019-08-30 15:44
閱讀 1350·2019-08-29 16:42
閱讀 1743·2019-08-26 13:53
閱讀 945·2019-08-26 10:41
閱讀 3476·2019-08-23 17:10
閱讀 615·2019-08-23 14:24
閱讀 1729·2019-08-23 11:59