微博春晚背後的技術故事

infoq發表於2014-03-13

 前言

  一年一度的春晚再次落下帷幕,而微博也順利地陪伴大家度過除夕之夜。

  談及馬年春晚,人們首先想到的不是春晚上精彩的節目,而是微博上的吐槽,邊看春晚,邊刷微博,邊吐槽,已經成了國人的習慣。看春晚不再是為了看節目,而是為了能夠在微博上吐槽,知道大家在吐槽什麼,更有人戲稱不是春晚成就了微博,而是微博拯救了春晚。

  馬年春晚又格外引人注目,不僅僅是因為馮小剛親自坐鎮,擔當總導演,更值得一提的是本屆春晚首次將社交平臺作為其與觀眾互動的主要途徑,而新浪微博更是成為官方二維碼獨家合作方。在節目播出時,使用者通用手機客戶端,掃描螢幕右下角的官方二維碼,即可參與春晚的話題討論。不僅如此,參與討論的觀眾,還可以免費獲得微博紅包,抽大獎的機會。如此一來,大大的提升了微博的活躍度瞬間提升,同時線上人數翻了幾倍,給微博系統帶來前所未有的訪問壓力。

  根據以往統計的資料,春晚期間微博的訪問量將激增到日常水平的數倍之多,而瞬時發表量更是飆升數十倍,如此場景絲毫不亞於淘寶雙11和12306搶票時的”盛況”。

  而最後的統計資料結果表明,馬年春晚直播期間,微博的訪問量和發表量都再創新高,而我們系統也自始至終平穩執行,經受住了此次高峰的考驗。這成功的背後,是我們的工程師將近一個月的努力。其間面臨了哪些問題,又是如何解決的呢?下面,我們一一為大家揭祕。

 挑戰1:如何應對數倍於日常訪問量的壓力?

  每年春運搶票時,12306都會崩潰;淘寶雙11時,也會有短暫的購買失敗的情況。究其原因還是,有限的伺服器資源難以承受上千萬人同時線上訪問。同樣,春晚的時候,微博的訪問量也會激增,同時線上人數到達日常的數倍之多。面對突然增長的訪問壓力,大部分網際網路公司都會臨時擴容來加以應對,同樣我們也需要進行擴容。那麼如何進行擴容?哪些部分需要擴容?具體擴容多少?這都是厄需解決的問題。

  需要提到一點的是,微博目前線上部署了幾千臺伺服器,來保障日常的正常訪問。假如面對原來數倍的訪問壓力時,如果簡單粗暴通過線性擴容來應對的話,需要部署原來數倍的伺服器,也就是需要上萬臺伺服器。無論從硬體成本還是從管理成本上,這都是不可接受的。那麼,又該如何做呢?

  線上壓測,找極限,最小化擴容前端機

  眾所周知,為了儘可能的保障線上執行的伺服器的穩定,資源都是有一定冗餘度的,一般安全值在30%以上。在面臨5倍的訪問量時,出於成本的考慮,單純的擴容難以令人接受。這個時候,就要充分利用每臺伺服器,在不影響業務效能的前提下,使每臺伺服器的利用率發揮到極限,可以極大的降低資源擴容的數量。如何評估伺服器的承受極限是其中的關鍵,為此我們在業務低峰時期,對線上的伺服器進行了實際的壓測。具體方法如下:

  假如線上一個服務池裡有300臺 tomcat伺服器在提供API服務,正常情況下,每臺伺服器的負載都小於1(為了簡化模型,我們這裡只提到了系統load這個指標,實際情況要比這個複雜的多,還要考慮CPU 利用率、頻寬、io延遲等)。通過運維繫統,我們以10%、20%、30%、40%、50%等比例逐步將該服務池裡的300臺 tomcat 機器503,通過觀察一臺 tomcat 伺服器的負載以及 API 服務的介面效能,當伺服器的負載達到極限或者 API 服務的介面效能達到閾值時,假設此時服務池裡正常狀態的 tomcat 伺服器的數量是100臺,那麼我們就可以推斷出該服務池,極限情況下可以承受3倍與日常的訪問壓力。同理,為了承擔5倍的訪問量,只需再擴容一倍機器即可。

 挑戰2:如何應對瞬時可達幾萬/s 的發表量?

  網際網路應用有個顯著特點,就是讀多寫少。針對讀多有很多成熟的解決方案,比如可以通過cache 來快取熱資料來降低資料庫的壓力等方式來解決。而對於寫多的情況,由於資料庫本身寫入效能瓶頸,相對較難解決。

  微博系統在處理髮表微博時,採用了非同步訊息佇列。具體來講,就是使用者發表微博時,不是直接去更新資料庫和快取,而是先寫入到 mcq訊息佇列中。再通過佇列機處理程式讀取訊息佇列中的訊息,再寫入到資料庫和快取中。那麼,如何保證訊息佇列的讀寫效能,以及如何保證佇列機處理程式的效能,是系統的關鍵所在。

  按訊息大小設定雙重佇列,保證寫入速度。

  眾所知之,微博最大長度不超過140個字,而大部分使用者實際發表的微博長度都比較小。為了提高寫入訊息佇列的速度,我們針對不同長度的微博訊息,寫入不同大小的訊息佇列。比如以512位元組為分界線,大於512位元組的寫入長佇列,小於512位元組的寫入短佇列,其中短佇列的單機寫入效能要遠遠高於長佇列。實際線上結果表明,短佇列的QPS 在萬/s 級別,長佇列的QPS 在千/s 級別,而99%的微博訊息長度均小於512位元組。這種優化,大大提高了微博訊息的寫入和讀取效能。

  堵塞佇列,壓佇列機極限處理能力。

  為了驗證佇列機處理程式的極限處理能力,我們在業務低峰時期,對線上佇列機進行了實際的壓測,具體方法如下:

  通過開關控制,使佇列機處理程式停止讀取訊息,從而堵塞訊息佇列,使堆積的訊息分別達到10萬,20萬,30萬,60萬,100萬,然後再開啟開關,使佇列機重新開始處理訊息,整個過程類似於大壩蓄水,然後開閘洩洪,可想而知,瞬間湧來的訊息對佇列機將產生極大的壓力。通過分析日誌,來查詢佇列機處理程式最慢的地方,也就是瓶頸所在。

  通過兩次實際的壓測模擬,出乎意料的是,我們發現系統在極限壓力下,首先達到瓶頸的並非是資料庫寫入,而是快取更新。因此,為了提高極限壓力下,佇列機處理程式的吞吐量,我們對一部分快取更新進行了優化。

 挑戰3:如何保證系統的可靠性?

  無論是發微博,還是刷 feed,在微博系統內的處理過程都十分複雜,依賴著各種內部資源和外部服務,保證系統的可靠性顯得尤為困難。

  為此,我們內部開發了代號為試金石——TouchStone的壓測系統,對系統的可靠性進行全面檢測。

  首先,我們對微博的各個介面進行了服務依賴和資源依賴的梳理,並針對每個服務和資源定義了相應的 SLA 和降級開關。然後,模擬資源或者服務出現異常,再來檢視其對介面效能的影響。以 redis資源為例, 假設系統定義了redis的 SLA是300ms,相應的埠是6379,通過 TouchStone,使該埠不可用,從而模擬 redis 資源出現異常,然後驗證依賴該資源的介面的效能,確保 SLA 。同時,通過降級開關,對該資源進行降級,驗證降級開關的有效。

  基於以上方法,對系統進行了全面的檢測,並對各個服務和資源的 SLA 和降級開關進行梳理,總結成業務降級手冊,保證在出現問題時,運維人員無需開發的介入,也能第一時間根據降級手冊進行降級,確保問題能夠儘快解決。

 挑戰4:如何保證核心系統的穩定性?

  任何一個系統,都包含核心系統和非核心繫統。在出現異常的情況下,棄車保帥,只保障核心系統的穩定性也是可以接受的。

  為此,我們降核心介面和非核心介面拆分,部分部署到不同的應用池子當中,確保非核心業務不會影響核心業務。比如發微博和刷 feed 屬於核心業務,而評論,贊屬於非核心業務,所以兩者應當部署到不同的應用池中。在評論或者贊出現異常時,發微博和刷 feed 就不會受到影響,從而保障系統核心業務的穩定性。

  同樣,對於一個業務,也要區分核心邏輯和非核心邏輯。以發微博為例,更新快取和寫資料庫屬於核心邏輯,而給其它業務部門推送資料則屬於非核心邏輯。因此,可以將推送資料進行非同步化處理,交給單獨的執行緒池處理,在出現異常時,不會對更新快取和寫資料庫造成影響。

 挑戰5:如何做到異地容災?

  近些年來,異地容災成為全球性網際網路企業面臨的難題之一。無論是在國內,以微信為例,還是在國外,以 twitter 為例,都曾經出現過全球性當機的事故。由此可見,異地容災仍舊是一個挑戰。

  微博早在2010年就開始了多機房的部署,如今已經具備三大機房(分別針對聯通、電信和海外使用者)。

  由於人為或者天氣等不可抗拒因素,網路故障近年來時有發生。微博的三個機房,各自獨立承擔了一部分使用者的訪問。在一個機房出現故障或者壓力過大的時候,通過DNS切換等手段,將流量遷移到另外兩個機房,從而確保該訪問該機房的使用者不受影響。一個現實的情況例子,在馬年春晚直播期間,由於觀看人群的地域分佈的特點,出現了聯通機房的訪問量突增,同時線上人數的增長超過了電信機房和廣州機房,我們通過切換一部分聯通機房的流量到電信機房,使得聯通機房的負載降到了安全值的範圍。

 挑戰6:如何實時監控系統狀態?

  我們都知道,地震的發生都是有前兆的,比如一些動物的異常反應。同樣,系統中的任何問題出現之前,也是有線索可尋的。這就需要對系統的關鍵指標做實時的監控,當指標出現異常時,能夠第一時間發出報警資訊。

  為此,我們基於實時流處理系統 Storm 開發了一套監控系統——dashboard。有別於以往的監控系統,它能實時處理系統產生的海量日誌,繪製出更加直觀的曲線,方便運維進行管理。通過 dashborad,我們能夠了解系統的實時狀態,主要包括feed的訪問量、微博的發表量、佇列機的處理效能,訊息佇列的堆積量等指標。當某個監控指標出現異常時,能夠第一時間在 dashboard 中反映出來,從而第一時間採取措施,解決問題,避免問題擴大化。

 後記

  春晚已經過去一個月了,漸漸成為回憶。但春晚背後,我們的工程師所付出的巨大的努力所產生的價值,卻是一筆寶貴的財富,希望這篇文章能給大家帶來啟發甚至幫助,也在此向為微博春晚默默貢獻的工程師們致敬!

相關文章