作者:張冬洪
背景&挑戰
背景
正是圖1這條微網誌動态,讓一個平常的國慶假期變得不同尋常,微網誌剛一發出就引爆網絡,它将明星CP動态推向了輿論的高潮,并霸占微網誌熱搜榜好幾天,也正是因為這個突發的流量,緻使流量過大一度引發微網誌伺服器癱瘓,而成為吃瓜群衆熱議的話題。微網誌擁有超過3.76億月活使用者,是目前社會熱點事件傳播的最主要平台,其中包括但不限制于大型活動(如裡約奧運會、十九大等)、春晚、明星動态(如王寶強離婚事件、女排奪冠、喬任梁去世、白百合出軌、TFBOYS生日、鹿晗關曉彤CP等)。而熱點事件往往具有不可預見性和突發性,并且伴随着極短時間内流量的數倍增長,甚至更多,有時持續時間較長。如何快速應對突發流量的沖擊,確定線上服務的穩定性,是一個挑戰巨大且頗有意義的事情。
圖1 鹿晗發博截圖
熱點事件的特點
從上述系列流量圖中,我們可以看出這兩起事件對微網誌的核心服務如Feed、評論、贊、話題等帶來的壓力都是成倍的,創造了曆史的新高點。仔細分析不難發現,這類事件基本可以分為:發生期、發酵期、暴漲期和緩解期,隻是由于天時地利人和等各種因素的綜合影響,各個時期的持續時間、流量變化不盡相同,對服務的壓力也有所差異,在暴漲期所表現出的不亞于天貓雙11,以及12306搶票的盛況。總體上反映出這類熱點事件的特點為:
- 不可預見性和突發性
- 峰值流量大
- 持續時間短
- 參與人數多
- 涉及資源廣
圖2 鹿晗關曉彤CP Feed業務量
圖3 鹿晗關曉彤CP評論業務量
圖4 鹿晗關曉彤CP 話題業務
面臨的挑戰
微網誌研發中心資料庫部門主要負責全微網誌平台後端資源的托管和運維,主要涉及的後端資源服務包括MySQL、Memcached、Redis、HBase、Memcacheq、Kafka、Pika、PostgreSQL等。為了應對峰值流量并保證使用者的良好體驗,資源層會面臨哪些挑戰?又将如何解決呢?
- 面對不可預期的峰值流量,有時惡意的刷站行為,如何應對數倍,甚至數十倍于日常通路量的壓力?
- 如何應對瞬時可達幾萬/秒的發表量?
- 如何做到異地容災?
- 如何保證緩存的命中率,減少緩存穿透甚至“雪崩”?
- 如何實作緩存的快速動态擴縮容?
- 如何保證服務的低延遲、高可用?
- 如何保證核心系統的穩定性?
- 如何實時監控系統服務狀态?
- ……
微網誌資料庫運維體系架構解析
業務架構
微網誌目前使用者基數龐大,DAU和MAU均為數億。從整個技術體系來看,微網誌核心總體分為前端和後端平台,端上主要是PC端、移動端、開放平台以及企業開放平台。後端平台主要是Java編寫的各種接口層、服務層、中間件層及存儲層。除此之外,微網誌搜尋、推薦、廣告、大資料平台也是非常核心的産品。從業務角度看,整體架構圖如下:
圖5 業務架構圖
這裡以微網誌平台的業務為例,微網誌平台的服務部署架構如圖6。
圖6 平台服務部署架構圖
就平台業務而言,後端的資源每天承載着千億次的寫請求,萬億次的讀請求,如MySQL在流量極端峰值的情況下承載着幾十萬,甚至上百萬的QPS,面對這麼大體量的業務壓力,對于後端資源的穩定性和RTT也提出了極高的要求,對業務部門承諾的SLA必須達到3個9,部分業務甚至4個9,且平均響應時間不能高于50ms。是以面臨的挑戰不言而喻。為了達到這一目标,需要有一個完善的,穩定可靠的,健壯的資料庫運維體系來提供支撐和管理全平台25個分支下600多個産品線的業務運維。
資料庫運維體系架構
圖7 資料庫運維體系架構圖
整個運維體系由三大部分組成:UI層、應用服務層、基礎服務層。UI層是各種管理平台的Dashboard和功能入口以及提供基礎的Restful API等;應用服務層是資料庫運維過程中所用到的各種功能子產品集合,為RD和DBA提供最全面的資料庫管理功能,這部分是整個運維體系中的核心組成部分,也是整個體系中最龐大和最複雜的部分;基礎服務層是整個運維體系中最基礎的依賴層,為資料庫運維體系提供底層的基礎服務,這裡需要特别提出是,熱點事件應對過程中的彈性擴縮容就是依賴這一層的DCP系統和Docker鏡像,結合私有雲和公有雲提供的ECS虛拟機來完成。
MySQL高可用架構
圖8 MySQL高可用架構圖
MHA(Master High Availability)目前在MySQL高可用方面是一個相對成熟的解決方案,它由日本DeNA公司Youshimaton(現就職于Facebook公司)開發,是一套優秀的作為MySQL高可用性環境下故障切換和主從提升的高可用軟體。在MySQL故障切換過程中,MHA能做到在0~30秒之内自動完成資料庫的故障切換操作,并且在進行故障切換的過程中,MHA能在最大程度上保證資料的一緻性,以達到真正意義上的高可用。微網誌MySQL高可用也基于MHA方案實作,這裡MHA是在Youshimaton開發的MHA思想上自研而成。整個架構由三部分組成:監控、MHA和MySQL叢集(主從執行個體)組成。為了實作MySQL的高可用和災備:
- 在部署拓撲結構上,我們把MySQL的從庫執行個體部署在不同的資料中心,給業務提供的是域名方式通路後端的DB資源,跨資料中心的同步帶來的另一個好處是業務結構清晰和同機房前端通路同機房的後端資源,而不必跨機房通路,同時也友善架構上做流量切換的操作。
- 我們會為被監控的MySQL主庫添加一個白名單,白名單内的端口,在啟用監控的條件下,能夠實作在主庫伺服器當機,所有從庫執行個體都不可連主庫,長時間伺服器網絡故障的條件下,自動完成主從切換。其中,主庫check階段,首先用從管理機上用Python自帶的MySQL庫去連接配接MySQL測試,如果連接配接失敗,再檢查主機層面連通性以及程序存活情況,如果失敗,再考慮從所有從庫去檢查主庫情況,優先先檢查一台從庫,這樣做主要是為了防止誤切。
- 在MHA自身的高可用上,我們也是基于KeepAlive做了高可用的方案,保證MHA的可用性。
多級緩存架構
圖9 多級緩存架構圖
Config Service
這一子產品是基于現有微網誌的配置服務中心,它主要是管理靜态配置和動态命名服務的一個遠端服務,能夠在配置發生變更的時候實時通知監聽的Config Client。
Proxy
這一子產品是作為獨立的應用對外提供代理服務,用來接收來自業務端的請求,并基于路由規則轉發到後端的Cache資源,它本身是無狀态的節點。它包含了如下部分:
- 異步事件處理(Event Handler):用來管理連接配接、接收資料請求、回寫響應;
- Processor:用來對請求的資料進行解析和處理;
- Adapter:用來對底層協定進行适配,比如支援MC協定、Redis協定;
- Router:用來對請求進行路由分發,分發到對應的Cache資源池,進而隔離不同業務;
- LRU Cache:用來優化性能,緩解因為經過Proxy多一跳(網絡請求)而帶來的性能弱化;
- Timer:用來執行一些後端的任務,包含對底層Cache資源健康狀态的探測等;
- Stat:Proxy節點資訊狀态統計。
Proxy啟動後會去從Config Service加載後端Cache資源的配置清單進行初始化,并接收Config Service配置變更的實時通知。
Cluster Manager
這一子產品是作為實際資料緩存的管理子產品,通過多層結構來滿足服務的高可用。 首先解釋一下各層的作用:
圖10 多級緩存中各角色含義
其中,Master是主緩存節點,Slave是備份節點,當Master緩存失效或執行個體挂掉後,資料還能夠從Slave節點擷取,避免穿透到後端DB資源,L1主要用來抗住熱點的通路,它的容量一般比Master要小,平台的業務通常部署多組L1,友善進行水準擴容以支撐更高的吞吐。
Client用戶端
這一子產品主要是提供給業務開發方使用的Client(SDK包),對外屏蔽掉了所有細節,隻提供了最簡單的get/set/delete等協定接口,進而簡化了業務開發方的使用。
應用啟動時,Client基于namespace從Config Service中擷取相應的Proxy節點清單,并建立與後端Proxy的連接配接。正常一個協定處理,比如set指令,Client會基于負載均衡政策挑選目前最小負載的Proxy節點,發起set請求,并接收Proxy的響應傳回給業務調用端。
Client會識别Config Service推送的Proxy節點變更的情況重建Proxy連接配接清單,同時Client端也會做一些容災,在Proxy節點出現問題的時候,對Proxy進行摘除,并定期探測是否恢複。
目前微網誌平台部分業務子系統的Cache服務已經遷移到了CacheService之上,它在實際運作過程中也取得了良好的性能表現,目前整個叢集線上上每天支撐着超過千萬級的QPS,平均響應耗時低于1ms。
它本身具備了以下特性。
- 高可用
所有的資料寫入請求,Cache Service會把資料雙寫到HA的節點,這樣,在Master緩存失效或挂掉的時候,會從Slave讀取資料,進而防止節點fail的時候給後端資源(DB等)帶來過大的壓力。
- 服務的水準擴充
Cache Service Proxy節點本身是無狀态的,在Proxy叢集存在性能問題的時候,能夠簡單地通過增減節點來伸縮容。而對于後端的Cache資源,通過增減L1層的Cache資源組,來分攤對于Master的請求壓力。這樣多數熱點資料的請求都會落L1層,而L1層可以友善的通過增減Cache資源組來進行伸縮容。
- 實時的運維變更
通過整合内部的Config Service系統,能夠在秒級别做到資源擴容、節點替換等相關的運維變更。目前這塊主要結合DCP系統,利用Docker鏡像以及虛拟機資源完成彈性的擴縮容。
- 跨機房特性
微網誌系統會進行多機房部署,跨機房的伺服器網絡時延和丢包率要遠高于同機房,比如微網誌廣州機房到北京機房需要40ms以上的時延。Cache Service進行了跨機房部署,對于Cache的查詢請求會采用就近通路原則,對于Cache的更新請求支援多機房的同步更新。
異步消息隊列更新機制
網際網路應用有個顯著特點,就是讀多寫少。針對讀多有很多成熟的解決方案,比如可以通過Cache來緩存熱資料以降低資料庫的壓力等方式來解決。而對于寫多的情況,由于資料庫本身的寫入性能瓶頸,相對較難解決。我們知道春晚發祝福,或娛樂熱點的時候發評論、點贊等場景下,會有大量的并發寫入,我們為了解決這類問題,引入了“異步消息隊列更新機制”。從微網誌平台的服務部署架構圖中也可以看到,當使用者發微網誌或評論等時候,不是直接去更新緩存和DB,而是先寫入到MCQ消息隊列中,再通過隊列機處理程式讀取消息隊列中的消息,再寫入到資料庫和緩存中。那麼,如何保證消息隊列的讀寫性能,以及如何保證隊列機處理程式的性能,是系統的關鍵所在。
- 按消息大小設定雙重隊列,保證寫入速度
衆所周知,2016年中旬之前微網誌的最大長度不超過140個字,現在放開了這個限制。但是大部分使用者的實際發表的微網誌長度都比較小,為了提高寫入隊列的速度,我們針對不同長度的微網誌消息,寫入不同大小的消息隊列,比如以512位元組為分界線,大于512位元組的寫入長隊列,小于512位元組的寫入短隊列,其中短隊列的單機寫入性能要遠遠高于長隊列。實際線上結果表明,短隊列的QPS在萬/s級别,長隊列的QPS在千/s級别,而95%的微網誌消息長度均小于512位元組。這種優化,大大提高了微網誌消息的寫入和讀取性能。
- 堵塞隊列,壓測隊列的承載能力和隊列機極限處理能力
為了驗證隊列機處理程式的極限處理能力,我們在業務低峰時期,對線上隊列機進行了實際的壓測,具體方法如下:通過開關控制,使隊列機處理程式停止讀取消息,進而堵塞消息隊列,使堆積的消息分别達到10萬,20萬,30萬,60萬,100萬,然後再打開開關,使隊列機重新開始處理消息,整個過程類似于大壩蓄水,然後開閘洩洪,可想而知,瞬間湧來的消息對隊列機将産生極大的壓力。通過分析日志,來查找隊列機處理程式最慢的地方,也就是瓶頸所在。通過兩次實際的壓測模拟,出乎意料的是,我們發現系統在極限壓力下,首先達到瓶頸的并非是資料庫寫入,而是緩存更新。是以,為了提高極限壓力下,隊列機處理程式的吞吐量,我們對一部分緩存更新進行了優化。
另一方面,通過壓測,也可以幫助我們發現隊列的承載能力和處理能力,有效幫助我們找到隊列的短闆,友善我們進行優化和擴容,通常情況下,核心隊列都會保證3到4倍的備援。
應對熱點事件的手段和政策
擴容這是DBA常采用的手段。擴容通常分為水準擴容和垂直擴容:
- 垂直擴容
垂直擴容,可以了解為保證架構不變的前提下,通過增加硬體投入即可實作的擴容方式。對于緩存而言,擴容是很容易、很友善、很快捷實作的,而對于DB來說,通常體積比較大,擴容起來很不友善,周期時間很長,尤其是應對流量的情況下,通常優先擴容緩存來抗熱點,減少對後端DB的通路。而對于DB的擴容,我們會不定期對核心DB資源進行評估,随着業務的不斷發展,當超過一定的水位線時,為了保證DB的可用性,需要保留3到4倍的備援,當不滿足時,便需要擴容。因為熱點總是不期而來,往往擴容緩存并沒有那麼及時,這時候保證足夠的備援,有助于預防DB被打挂,保障服務的穩定性,就顯得很重要。
- 水準擴容
水準擴容,可以了解為通過調整架構,擴充資源的承載能力。比如:對于Redis服務來說,原本一個業務是4主4從,在業務量并發不高的情況下,完全滿足業務需求,但是随着業務量上漲後,Redis的寫性能變差,響應時間變慢,此時,我們需要對該業務進行水準擴充,将業務架構調整為8主8從或者更多,進而部署更多的主庫還抗寫入量。
降級
對于一個高可用的服務,很重要的一個設計就是降級開關,其目的是抛棄非重要服務,保障主要或核心業務能夠正常提供服務。對于後端資源,包括MySQL、MC、Redis、隊列等而言,并不能保證時時刻刻都是可用的,一旦出現問題,降級政策就能派上用場。那麼如何降級?降級的标準是什麼?這裡拿話題頁舉個例子。
圖11 話題首頁
圖12 點選“導語”進入的二級頁面
- 抛棄非核心大量運算業務,減輕自身計算服務壓力。
任何一個系統,都包含核心系統和非核心系統。在出現異常的情況下,棄車保帥,隻保障核心系統的穩定性也是可以接受的。對于上面的這個話題來說,話題首頁是核心業務,話題二級頁面是非核心業務。當話題DB資源出現瓶頸時,我們可以優先讓RD同學降級二級頁,釋放DB的連接配接資源并減少查詢請求,保障話題首頁能夠有更多的資源可用。
- 抛棄非核心子產品,減輕自身資源壓力。
同樣,對于同一個業務,也要區分核心邏輯和非核心邏輯。對于話題首頁的這個資源,微網誌時尚釋出的Feed流屬于核心邏輯,而頭像下方的時尚美妝榜TOP1 榜單則屬于非核心邏輯。毫無疑問,為了減負,非核心邏輯必要時是可以被降級的。
- 抛棄高耦合邏輯,避免依賴服務性能下降導緻雪崩。
在微網誌複雜的架構體系中,各種依賴和接口調用,錯綜複雜。就話題首頁資源來看,“閱讀11.8億 讨論36萬 粉絲1.9萬”的計數就是調用微網誌平台的接口擷取Redis計數器資源的結果。對于熱點事件而言,尤其是對于這種全平台都可能會調用的資源來說,當時的通路量是極大的,響應時間肯定會比平時差,如果話題首頁因為要取該資源而逾時,導緻話題“白頁”,那必然不是想要的結果,是以需要抛棄這類高耦合邏輯。對于後端資源而言,當某個資源,比如某台MCQ伺服器當機,嚴重影響V4啟動,拖累整體動态擴容時,業務方就會考慮暫時503這台伺服器執行個體資源,保證整個擴容流程的順暢和速度。同時業務方也會根據請求的後端資源使用特點的不同,有時在降級前會使用一些fast fail或fast over的政策來保障服務的穩定性和可用性。
切流量
對于一個大型系統而言,這也是一個常用手段,通常可用從DNS、LVS、H5、HaProxy(四層負載均衡)、Nginx(七層負載均衡)等層面上來實作流量的切換。常見的使用場景有:
1. 某機房業務流量達到瓶頸,影響業務的請求耗時和使用者體驗的時候,需要将到這個機房的請求量,一部分切到其他機房,使得流量相對均衡一點。
2. 機房搬遷、機房斷網/斷電,也需要進行切流量操作,保證服務的可用性。
3. 業務架構調整、鍊路壓測,比如将晚高峰的流量,從一個機房切到另一個機房,壓測另一個機房的資源承載能力。
4. 線路帶寬打滿,由于某條專線的承載能力達到上限,不得不将流量從該線路切到其他線路。春晚前,彈性擴縮容的需求很多,經常有很多業務方同時進行擴容,因為需要下載下傳鏡像、遷移資料、下發配置等,專線很容易成為瓶頸,故需要準備一個備用專線或提前提升專線容量。
5. 營運商故障,雖然現在一般的機房都具備BGP的能力,但有時還是需要從業務層面去解決。
限流
從字面意思可以看出,限流的目的就是為了防止惡意請求(如刷站)、惡意攻擊,或者防止流量超出系統的峰值。處理的原則就是限制流量穿透到後端的資源,保障資源的可用性。舉個例子:比如圖13的QPS異常現象,請求流量超出平時晚高峰的好幾倍,嚴重影響了服務的穩定性和後端DB的承載能力,為了保障DB資源的可用性,經排查是屬于通過user_timeline接口的惡意刷站行為,此時,我們要做的就是封殺該接口,限制流量穿透到DB層,封殺後,效果很明顯。
圖13 刷站時QPS圖
限流(封殺)後的效果如圖14所示:
圖14 限流效果圖
除了封殺接口之外,其他一些可借鑒的思路是:
- 對于惡意IP:可以使用Nginx deny進行屏蔽或采用iptables進行限制。
- 對于穿透到後端DB的請求流量:可以考慮用Nginx的limit子產品處理或者Redis Lua腳本實作或者啟用下面的過載保護政策。
- 對于惡意請求流量:隻通路到Cache層或直接封殺。
過載保護
這個政策是針對DB資源設計的,就是當請求超過DB的承載範圍時,啟動的一個自我保護機制。比如,在某個明星出軌的時候,有使用者惡意刷評論清單,導緻評論的資料庫從庫資源出現大量延遲,嚴重影響服務的性能,為了防止DB資源因過載而不可用,通過和業務方溝通後,果斷啟動了過載保護機制,進而保證了評論服務的穩定性。圖15就是應用了過載保護機制後的效果。開源的工具可以使用percona公司開源的pt-kill工具實作。
圖15 過載保護效果圖
鍊路壓測
壓測的目的是找出資源或者鍊路上的瓶頸點或者驗證技術選型的可行性或測試優化的效果,這也是一個常态化的過程,一般分為兩種場景:
- 找瓶頸點
這個通常是配合業務方共同完成,如上面的異步消息隊列更新機制中提到的一樣,通過切流量、堵塞隊列、壓測隊列的承載能力和隊列機極限處理能力,找出資源的瓶頸點,友善作為進行優化和擴容的依據,有時候也作為設定水位線的一個标準。
- 驗證技術選型的可行性或測試優化效果
有時候為了引入新的技術,需要進行性能/壓力測試,或者有時候為了驗證某項優化的效果,然而壓測很難模拟真實的線上環境場景,此時在保證服務穩定可控的情況下,通過TCPCopy的方式引入線上的真實流量加以驗證。
- 水位線&預警機制
這可以快速有效地幫助了解線上業務的變化趨勢,以及快速定位業務的實時運作情況,如果超過水位線,會觸發預警機制,通過這種手段可以輔助DBA做出相應的政策判斷,比如:擴容、限流、過載保護等。
需要完善和改進的地方或未來的規劃
智能擴縮容
目前很多情況下,尤其是當有熱點的時候,DBA都是通過申請資源,部署服務,然後上線,完成一系列的手動操作完成擴容,這顯然會浪費很多的人力,效率也不高。未來,可以通過設定水位線,增加對熱key的預判,以及帶寬的門檻值,當超過警戒位後,通過開發的自動化工具來智能地進行MC的動态擴縮容。
故障自愈系統
故障無處不在,因為任何硬體都有使用壽命,都有折損率。現在每天都可能有伺服器當機、伺服器異常重新開機、伺服器系統readonly、記憶體損壞、RAID卡損壞、CPU損壞、主機闆損壞、磁盤損壞、電源子產品損壞等,各種硬體的故障都有可能會導緻服務異常,那麼如何應對這些故障,保證伺服器的高可用,是一個普遍面臨的問題。微網誌有很多伺服器都過保,它們就像一個“雷” 一樣無處不在,但是這些故障也是有輕有重,有緊急有非緊急的,根據具體部署業務的不同而不同。伺服器數量之多,每天報警幾千條,全憑人工處理很難覆寫全面,這就急需結合監控和故障采集樣本開發一套自愈系統,完成基礎的,甚至大部分類型的故障修複工作,比如自動報修。
移動辦公
移動網際網路時代,移動辦公已經不是什麼時髦的事情,很多的工作都能直接在手機或智能終端裝置上完成。雖然目前有部分工作,比如工單稽核、登入伺服器執行指令等都可以在手機上實作,但是還有很多工作沒有辦法完成,比如檢視監控、手動擴容等複雜操作,需要後續的完善。
服務自助化
服務自助化,需要依賴完善的基礎服務和健壯穩定的自動化平台,以及充足的備援資源和完備的标準服務流程和規範才能完成。這是一個長期的過程,目前微網誌已經能夠在SQL稽核、Online DDL方面提供自助式服務,但是還有很多方面需要完善和提高,比如:資源申請、資源下線、資源擴容等。