微博“異地多活”部署經驗談

InfoQ - 劉道儒發表於2015-04-29

異地多活的好處阿里巴巴的同學已經充分闡述,微博的初始出發點包括異地災備、提升南方電信使用者訪問速度、提升海外使用者訪問速度、降低部署成本(北京機房機架費太貴了)等。通過實踐,我們發現優勢還包括異地容災、動態加速、流量均衡、線上壓測等,而挑戰包括增加研發複雜度、增加儲存成本等。

微博“異地多活”部署經驗談

(題圖來自:jimijones.com)

微博外部歷程

先說說微博外部的歷程,整個過程可謂是一波多折。微博的主要機房都集中在北京,只有很小一部分業務在廣州部署,2010年10月,因微博高速發展,所以準備擴大廣州機房伺服器規模,並對微博做異地雙活部署。

第一版跨機房訊息同步方案採取的是基於自研的MytriggerQ(藉助MySQL從庫的觸發器將INSERT、UPDATE、DELETE等事件轉為訊息)的方案,這個方案的好處是,跨機房的訊息同步是通過MySQL的主從完成的,方案成熟度高。而缺點則是,微博同一個業務會有好幾張表,而每張表的資訊又不全,這樣每發一條微博會有多條訊息先後到達,這樣導致有較多時序問題,快取容易花。

第一套方案未能成功,但也讓我們認識到跨機房訊息同步的核心問題,並促使我們全面下線MytriggerQ的訊息同步方案,而改用基於業務寫訊息到MCQ(MemcacheQ,新浪自研的一套訊息佇列,類MC協議)的解決方案。

微博“異地多活”部署經驗談

2011年底在微博平臺化完成後,開始啟用基於MCQ的跨機房訊息同步方案,並開發出跨機房訊息同步元件WMB(Weibo Message Broker)。經過與微博PC端等部門同學的共同努力,終於在2012年5月完成Weibo.com在廣州機房的上線,實現了“異地雙活”。

由於廣州機房總體的機器規模較小,為了提升微博核心系統容災能力,2013年年中我們又將北京的機房進行拆分,至此微博平臺實現了異地三節點的部署模式。依託於此模式,微博具備了線上容量評估、分級上線、快速流量均衡等能力,應對極端峰值能力和應對故障能力大大提升,之後歷次元旦、春晚峰值均順利應對,日常上線導致的故障也大大減少。上線後,根據微博運營情況及成本的需要,也曾數次調整各個機房的伺服器規模,但是整套技術上已經基本成熟。

異地多活面臨的挑戰

根據微博的實踐,一般做異地多活都會遇到如下的問題:

  • 機房之間的延時:微博北京的兩個核心機房間延時在1ms左右,但北京機房到廣州機房則有近40ms的延時。對比一下,微博核心Feed介面的總平均耗時也就在120ms左右。微博Feed會依賴幾十個服務上百個資源,如果都跨機房請求,效能將會慘不忍睹;
  • 專線問題:為了做廣州機房外部,微博租了兩條北京到廣州的專線,成本巨大。同時單條專線的穩定性也很難保障,基本上每個月都會有或大或小的問題;
  • 資料同步問題:MySQL如何做資料同步?HBase如何做資料同步?還有各種自研的元件,這些統統要做多機房資料同步。幾十毫秒的延時,加上路途遙遠導致的較弱網路質量(我們的專線每個月都會有或大或小的問題),資料同步是非常大的挑戰;
  • 依賴服務部署問題:如同阿里巴巴目前只做了交易單元的“異地雙活”,微博部署時也面臨核心服務過多依賴小服務的問題。將小服務全部部署,改造成本、維護成本過大,不部署則會遇到之前提到的機房之間延時導致整體效能無法接受的問題;
  • 配套體系問題:只是服務部署沒有流量引入就不能稱為“雙活”,而要引入流量就要求配套的服務和流程都能支援異地部署,包括預覽、釋出、測試、監控、降級等都要進行相應改造。

微博異地多活解決方案

由於幾十毫秒的延時,跨機房服務呼叫效能很差,異地多活部署的主體服務必須要做資料的冗餘儲存,並輔以快取等構成一套獨立而相對完整的服務。資料同步有很多層面,包括訊息層面、快取層面、資料庫層面,每一個層面都可以做資料同步。由於基於MytriggerQ的方案的失敗,微博後來採取的是基於MCQ的WMB訊息同步方案,並通過訊息對快取更新,加上微博快取高可用架構,可以做到即便資料庫同步有問題,從使用者體驗看服務還是正常的。

這套方案中,每個機房的快取是完全獨立的,由每個機房的Processor(專門負責訊息處理的程式,類Storm)根據收到的訊息進行快取更新。由於訊息不會重複分發,而且資訊完備,所以MytriggerQ方案存在的快取更新髒資料問題就解決了。而當快取不存在時,會穿透到MySQL從庫,然後進行回種。可能出現的問題是,快取穿透,但是MySQL從庫如果此時出現延遲,這樣就會把髒資料種到快取中。我們的解決方案是做一個延時10分鐘的訊息佇列,然後由一個處理程式來根據這個訊息做資料的重新載入。一般從庫延時時間不超過10分鐘,而10分鐘內的髒資料在微博的業務場景下也是可以接受的。

微博的異地多活方案如下圖(三個節點類似,訊息同步都是通過WMB):

微博“異地多活”部署經驗談

跟阿里巴巴遇到的問題類似,我們也遇到了資料庫同步的問題。由於微博對資料庫不是強依賴,加上資料庫雙寫的維護成本過大,我們選擇的方案是資料庫通過主從同步的方式進行。這套方案可能的缺點是如果主從同步慢,並且快取穿透,這時可能會出現髒資料。這種同步方式已執行了三年,整體上非常穩定,沒有發生因為資料同步而導致的服務故障。從2013年開始,微博啟用HBase做線上業務的儲存解決方案,由於HBase本身不支援多機房部署,加上早期HBase的業務比較小,且有單獨介面可以回撥北京機房,所以沒有做異地部署。到今年由於HBase支撐的物件庫服務已經成為微博非常核心的基礎服務,我們也在規劃HBase的異地部署方案,主要的思路跟MySQL的方案類似,同步也在考慮基於MCQ同步的雙機房HBase獨立部署方案。

阿里巴巴選擇了單元化的解決方案,這套方案的優勢是將使用者分割槽,然後所有這個使用者相關的資料都在一個單元裡。通過這套方案,可以較好的控制成本。但缺點是除了主維度(阿里巴巴是買家維度),其他所有的資料還是要做跨機房同步,整體的複雜度基本沒降低。另外就是資料分離後由於拆成了至少兩份資料,資料查詢、擴充套件、問題處理等成本均會增加較多。總的來講,個人認為這套方案更適用於WhatsApp、Instagram等國外業務相對簡單的應用,而不適用於國內功能繁雜、依賴眾多的應用。

資料同步問題解決之後,緊接著就要解決依賴服務部署的問題。由於微博平臺對外提供的都是Restful風格的API介面,所以獨立業務的介面可以直接通過專線引流回北京機房。但是對於微博Feed介面的依賴服務,直接引流回北京機房會將平均處理時間從百毫秒的量級直接升至幾秒的量級,這對服務是無法接受的。所以,在2012年我們對微博Feed依賴的主要服務也做了異地多活部署,整體的處理時間終於降了下來。當然這不是最優的解決方案,但在當時微博業務體系還相對簡單的情況下,很好地解決了問題,確保了2012年5月的廣州機房部署任務的達成。

而配套體系的問題,技術上不是很複雜,但是操作時卻很容易出問題。比如,微博剛開始做異地多活部署時,測試同學沒有在上線時對廣州機房做預覽測試,曾經導致過一些線上問題。配套體系需要覆蓋整個業務研發週期,包括方案設計階段的是否要做多機房部署、部署階段的資料同步、釋出預覽、釋出工具支援、監控覆蓋支援、降級工具支援、流量遷移工具支援等方方面面,並需開發、測試、運維都參與進來,將關鍵點納入到流程當中。

關於為應對故障而進行資料冗餘的問題,阿里巴巴的同學也做了充分的闡述,在此也補充一下我們的一些經驗。微博核心池容量冗餘分兩個層面來做,前端Web層冗餘同使用者規模成正比,並預留日常峰值50%左右的冗餘度,而後端快取等資源由於相對成本較低,每個機房均按照整體兩倍的規模進行冗餘。這樣如果某一個機房不可用,首先我們後端的資源是足夠的。接著我們首先會只將核心介面進行遷移,這個操作分鐘級即可完成,同時由於冗餘是按照整體的50%,所以即使所有的核心介面流量全部遷移過來也能支撐住。接下來,我們會把其他服務池的前端機也改為部署核心池前端機,這樣在一小時內即可實現整體流量的承接。同時,如果故障機房是負責資料落地的機房,DBA會將從庫升為主庫,運維調整佇列機開關配置,承接資料落地功能。而在整個過程中,由於我們核心快取可以脫離資料庫支撐一個小時左右,所以服務整體會保持平穩。

異地多活最好的姿勢

以上介紹了一下微博在異地多活方面的實踐和心得,也對比了一下阿里巴巴的解決方案。就像沒有完美的通用架構一樣,異地多活的最佳方案也要因業務情形而定。如果業務請求量比較小,則根本沒有必要做異地多活,資料庫冷備足夠了。不管哪種方案,異地多活的資源成本、開發成本相比與單機房部署模式,都會大大增加。

以下是方案選型時需要考慮的一些維度:

  • 能否整業務遷移:如果機器資源不足,建議優先將一些體系獨立的服務整體遷移,這樣可以為核心服務節省出大量的機架資源。如果這樣之後,機架資源仍然不足,再做異地多活部署。
  • 服務關聯是否複雜:如果服務關聯比較簡單,則單元化、基於跨機房訊息同步的解決方案都可以採用。不管哪種方式,關聯的服務也都要做異地多活部署,以確保各個機房對關聯業務的請求都落在本機房內。
  • 是否方便對使用者分割槽:比如很多遊戲類、郵箱類服務,由於使用者可以很方便地分割槽,就非常適合單元化,而SNS類的產品因為關係公用等問題不太適合單元化。
  • 謹慎挑選第二機房:儘量挑選離主機房較近(網路延時在10ms以內)且專線質量好的機房做第二中心。這樣大多數的小服務依賴問題都可以簡化掉,可以集中精力處理核心業務的異地多活問題。同時,專線的成本佔比也比較小。以北京為例,做異地多活建議選擇天津、內蒙古、山西等地的機房。
  • 控制部署規模:在資料層自身支援跨機房服務之前,不建議部署超過兩個的機房。因為異地兩個機房,異地容災的目的已經達成,且伺服器規模足夠大,各種配套的設施也會比較健全,運維成本也相對可控。當擴充套件到三個點之後,新機房基礎設施磨合、運維決策的成本等都會大幅增加。
  • 訊息同步服務化:建議擴充套件各自的訊息服務,從中介軟體或者服務層面直接支援跨機房訊息同步,將訊息體大小控制在10k以下,跨機房訊息同步的效能和成本都比較可控。機房間的資料一致性只通過訊息同步服務解決,機房內部解決快取等與訊息的一致性問題。跨機房訊息同步的核心點在於訊息不能丟,微博由於使用的是MCQ,通過本地寫遠端讀的方式,可以很方便的實現高效穩定的跨機房訊息同步。

異地多活的新方向

時間到了2015年,新技術層出不窮,之前很多成本很高的事情目前都有了很好的解決方案。接下來我們將在近五年異地多活部署探索的基礎上,繼續將微博的異地多活部署體系化。

升級跨機房訊息同步元件為跨機房訊息同步服務。面向業務隔離跨機房訊息同步的複雜性,業務只需要對訊息進行處理即可,訊息的跨機房分發、一致性等由跨機房同步服務保障。且可以作為所有業務跨機房訊息同步的專用通道,各個業務均可以複用,類似於快遞公司的角色。

推進Web層的異地部署。由於遠距離專線成本巨大且穩定性很難保障,我們已暫時放棄遠端異地部署,而改為業務邏輯近距離隔離部署,將Web層進行遠端異地部署。同時,計劃不再依賴昂貴且不穩定的專線,而藉助於通過演算法尋找較優路徑的方法通過公網進行資料傳輸。這樣我們就可以將Web層部署到離使用者更近的機房,提升使用者的訪問效能。依據我們去年做微博Feed全鏈路的經驗,中間鏈路佔掉了90%以上的使用者訪問時間,將Web層部署的離使用者更近,將能大大提升使用者訪問效能和體驗。

藉助微服務解決中小服務依賴問題。將對資源等的操作包裝為微服務,並將中小業務遷移到微服務架構。這樣只需要對幾個微服務進行異地多活部署改造,眾多的中小業務就不再需要關心異地部署問題,從而可以低成本完成眾多中小服務的異地多活部署改造。

利用Docker提升前端快速擴容能力。藉助Docker的動態擴容能力,當流量過大時分鐘級從其他服務池摘下一批機器,並完成本服務池的擴容。之後可以將各種資源也納入到Docker動態部署的範圍,進一步擴大動態排程的機器源範圍。

以上是對微博異地多活部署的一些總結和思考,希望能夠對大家有所啟發,也希望看到更多的同學分享一下各自公司的異地多活架構方案。

相關文章