鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

不知不覺,美好的十一假期已經結束了。在假期的最後一天,大約有四千萬人同時失戀,我們迎來了 2017 年度最大甜蜜暴擊!

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

鹿晗在新浪微博高調宣布了自己的新戀情,並大方的@了女朋友關曉彤。消息一出,微博立馬就炸了。

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

短短几個小時之後,該條微博被轉發 736137 次、評論 1913926 次、點贊 4179888 次,短時間內轉發評論點贊分分鐘衝上百萬,瘋狂上漲的數字搞垮了新浪微博的伺服器……

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

終於,新浪工程師擔心的事情還是出現了:北京時間 10 月 8 日午間 12 時 32 分,新浪微博官方客服賬號發布公告稱,目前客戶端無法正常刷新、評論等多個頁面無法正常顯示的問題,工程師已在排查。

對於造成這一問題的具體原因,新浪微博在公告中稱「大家心裡也都有數」。

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

最後還是老闆弄來了一千台伺服器才搞定…

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

然而整個事件當中,除了無數粉碎的少女心,最無辜躺槍還如此敬業的小哥哥,非這位微博搜索工程師丁振凱莫屬啦,結婚當日,遇鹿晗公布戀情,不得不從酒席上離開處理微博異常後繼續婚禮,心疼小哥哥三秒鐘……

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

那一刻,被迫加班的程序員內心是這樣的:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

連今天的淘寶程序猿都是失戀了:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

微博工程師眼中的「鹿晗」:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

好的,言歸正傳,新浪伺服器到底是怎麼垮的?

新浪伺服器是怎麼垮的?

知友:蘇莉安(200+ 贊,程序員話題優秀回答者)

我覺得不像資料庫掛了,微博這種級別的架構根本不是簡單的分散式 server+DB 就能抗住的,別說鹿晗關曉彤搞個大新聞,就算平時運營的壓力也扛不住。

剛才王高飛說加一千台伺服器暫時頂住了,資料庫是不可能臨時這麼彈性伸縮的,能伸縮的無非就是 HTTP Server、各中間層服務、緩存或消息隊列。

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

大概是微博自動擴容的演算法沒寫好,或者沒敢全交給演算法來做。比如你發現流量升高了,自動下單加幾十台伺服器能接受,突然加一千台要是程序出 Bug 的話微博得白支出多少錢啊……多半是這個量級的擴容需要運維手工來確認。

而且是在長假最後一天的中午爆發的,不是訪問高峰期,伺服器也準備不足。明星公布戀情這件事又沒法預警,誰知道他們啥時候心血來潮忽然介紹女朋友啊……

知友(400+ 贊)

根據目前已有的信息猜測是資料庫被壓垮了,先發猜想,稍後寫個程序分析當時的點贊評論轉發數據驗證猜想。微博這樣的網站,如果被大流量壓垮,不太可能是非必需欄位沒有容錯。

之前經歷過幾次熱門事件,我相信在爆發熱點新聞的時候,微博會暫時犧牲一點數據準確性來保證關鍵服務可用,也就是說,光讀請求很難壓垮微博。

根據事故時的微博點贊數、轉發數、評論數、評論的回複數、評論的點贊數、轉發的評論轉發點贊數等的量,微博極可能是由於事發當時需要寫入資料庫的請求太多(寫行為峰值可能達到了幾十萬甚至更高),以及大部分寫都會落到同一條微博上,而且某些寫操作還需要觸發相應的其他寫行為(回複評論需要通知評論者、點贊需要進關注者
feed 等),資料庫壓力過大扛不過來,最終跪了一會兒。

其實如果緩存做好,這時候還是可以滿足核心數據讀請求的(當然微博緩存做的並不好,我微博個人頁數據錯誤很久了反饋也沒用)。

如果資料庫壓力過大時,對部分寫請求非同步化,或者考慮暫時拋棄部分請求換取穩定性,當然這樣也各有利弊,不一定是好的。

可以抓取當時鹿晗發的微博的所有評論轉發回復點贊的時間,看下故障前幾秒成功的寫行為究竟有多少。

不負責任的未經驗證的猜測(畫圖水平有限,省略了部分過程,但是從上下兩個過度的箭頭數,大致表達了很多請求是讀且未壓到資料庫,將就看吧:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

知友:佚名(150+ 贊)

讓我放兩張來自微博後台數據的圖片:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

這樣看可能不是很直觀?

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

沒有對比就沒有傷害啊!關曉彤熱議趨勢硬生生漲了 1122.9%,社會社會!

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

如何快速提高系統性能?

回顧一下,究竟是多大的流量使得曾豪言「微博伺服器穩定,能同時應付三對劈腿的」壯志秒破功,具體數據如下圖所示:

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

按照微博明星勢力榜各個榜單計分方式:滿分 100 分,由閱讀數、互動數、社會影響力、愛慕值四項組成,所佔比例分別為30%、30%、20%、20%。

由上可以看出,鹿晗所發微博的每一項都達到了峰值,那麼在如此高流量的情況之下,作為開發者是否有好的方法來快速提高系統性能呢?就鹿晗宣布戀情導致微博宕機事件淺談大型網站高可用性架構。

作為一名程序員,我更感興趣的是微博如何應對瞬時湧來的高併發大流量。從很久很久以前文章馬伊琍的 「周一見」,到後來 「出軌隊」、「吸毒隊」 的爭相奪分,再到前段時間的郭敬明事件、薛之謙事件,再到今天的鹿晗宣布戀情…… 

微博看似每次都在掛,一直都沒有進步,大家每次遇到熱點事件刷不出內容的時候都會吐槽微博的應用平台很辣雞。但是呢,微博的後台系統肯定一直在重構升級優化,我覺得能夠做到今天這種水平已經很不錯了。

01

從用戶的角度(主要是我的角度 hhhhh)來看

遇到熱點事件的時候微博大概率在短時間內(大約 10~15)可能會完全刷不出內容,過了一段時間之後(大約半小時)進行間隔刷新(間隔 10 秒左右),有可能某些時候會看到 5xx 的 error,5 開頭的 http 狀態碼代表伺服器或者是網關存在問題。

比如說伺服器拒絕連接、網關超時或者是應用代碼存在 Bug 等都會導致 5xx 的錯誤。在熱點事件發生 1 小時內,系統應該可以恢復正常的服務。

02

從網站開發、運維人員的角度來看

運維:卧槽?怎麼訪問流量這麼高?是出啥 Bug 了嗎?卧槽!不會是又有人出軌吸毒了吧?emmmm…. 我的國慶假期可還沒結束啊!

運維:兄弟們,快醒醒!快加機器啊!系統要崩了!

開發:別催!再催自殺!

leader:測試在擴容之後趕緊拉出來測測!

測試:人在家中躺,鍋從天上來!

上面都是我亂說的!

鹿晗和關曉彤是如何聯手搞垮新浪微博伺服器的?

為什麼我覺得微博在高併發大流量訪問方面的表現已經很不錯了呢?舉個例子吧:淘寶每年在雙 11 購物節的時候也要應對高併發的場景,但是這是可以提前做很多準備的。

比如說提前購買帶寬資源、增加伺服器資源、進行完備的異地容災等等,很多都是可預測的。而微博呢?熱點事件隨時都可能發生,所以這對於微博的運維工程師來說是很大的考驗。

當然,現在的運維平台也是非常的智能了,可以對各項指標進行實時監控,一有異常,馬上進行簡訊或者郵件報警,之後就是各個崗位的工程師人肉上場調配各類資源了。

那微博在平時為什麼不增加一些伺服器資源呢?伺服器資源、網路帶寬資源等既重要,又昂貴。

由於並不是每時每刻都必須應對高併發的場景,因此如果說在平時增加了冗餘的伺服器資源導致大量機器空載,也是一種很大的浪費。我們在考慮提供可用服務的同時,也必須考慮一下成本。下面我就針對高可用性架構中經常會提到的幾個點來講講。

大型網站高可用架構

不管是對於小型網站還是大型網站來說,分層都是必須的:粗粒度的分層一般為應用層、業務層和數據層。橫向分層之後,可能還會根據模塊的不同對每一層進行縱向的分割。

拿微博舉例,我覺得它的評論模塊和點贊模塊應該是解耦的。越是複雜的系統,橫向和縱向的分層分割粒度就會越細。很多時候你用起來以為它就是一個系統,其實後面可能是由幾百上千個獨立部署的系統對外提供服務。

集群

集群在大型網站架構中是一個非常非常重要的概念。由於伺服器(不管是應用伺服器還是數據伺服器)容易發生單點問題,一旦一台伺服器掛了,就必須進行失效轉移。

應用伺服器集群

一般來說,應用伺服器必須是無狀態的。什麼叫無狀態伺服器呢?在介紹它之前,我們先來說一下狀態伺服器:狀態伺服器一般會保存請求相關的信息,每個請求會默認地使用以前的請求信息。

這樣就很容易導致會話粘滯問題:如果一台狀態伺服器宕機了,那麼它保存的請求信息 (例如 session) 就丟失了,可能會導致不可預知的問題。

那麼相對的,無狀態伺服器就不保存請求信息,它處理的客戶信息必須由請求自己攜帶,或者是從其他伺服器集群獲取。

因此無狀態伺服器相對於狀態伺服器來說更加地健壯,就算是重啟伺服器甚至是伺服器宕機都不會丟失狀態。由此引申出來的另一個優點就是方便擴容:只要在增加的伺服器上部署相同的應用並做好反向代理就能對外提供正常的服務。

Session 管理

既然應用伺服器是無狀態的,那麼用戶的登錄信息 (session) 如何管理呢?比較常見的有下面四種方式:

  • session 複製

  • 源地址 hash(session 綁定)

  • 用 cookie 記錄 session

  • session 伺服器

但是由於前三種都有很大的局限性,這裡只聊聊基於集群的 session 伺服器管理方式。

我們在這裡是將伺服器的狀態進行分離:分為無狀態的應用伺服器和有狀態的 session 伺服器。

當然,這裡說的 session 伺服器肯定說的是 session 伺服器集群。我們可以藉助分散式緩存或者是關係型資料庫來存儲 session。

對於微博來說,這裡肯定得用分散式緩存了:因為用關係型資料庫的話,資料庫連接資源容易成為瓶頸,並且 I/O 操作也很耗時間。

比較常見的 K-V 內存資料庫有 Redis。我覺得微博內容中的贊數、用戶的關注數和粉絲數用 Redis 來存應該算是比較合適的。

負載均衡

既然提到了集群,肯定得說說負載均衡。但是感覺負載均衡應該可以歸類到可伸縮性裡面去,所以這裡就不詳細講啦,就簡單說說有哪些常見的負載均衡的方式以及負載均衡演算法。

負載均衡方式:

  • HTTP 重定向負載均衡。

  • DNS 域名解析負載均衡。

  • 反向代理負載均衡。

  • IP 負載均衡。

  • 數據鏈路層負載均衡。

負載均衡演算法:

  • 輪詢法。

  • 隨機法。

  • 源地址哈希。

  • 加權輪詢。

  • 加權隨機。

  • 最小連接數。

插播點別的

突然想到一個比較有意思的東西:在微博的架構中,應該採用的是非同步拉模型而不是同步推模型。

什麼意思呢?我們舉個例子:鹿晗的粉絲有 3000 多萬,關曉彤的粉絲有 1000 多萬。假如他倆發了條微博的同時需要往這 4000 萬粉絲的內容列表中 (假設這裡用的是關係型資料庫) 推送過去,這就是簡化的同步推模型。

那這樣有什麼缺點呢?首先,這樣會消耗大量的資料庫連接資源,更重要的是這樣不太符合軟體設計規範:因為對於兩人的粉絲來說,分別由有 3000 多萬和 1000 多萬的數據是冗餘的。

假如說陳赫、鄧超在第一時間對他倆的微博進行了點贊,此時瓶頸就來了:剛才往資料庫里插入 4000 多萬感覺還可以接受,但是現在四人的粉絲數加起來好幾億了,同時往資料庫插這麼多數據是不是感覺不太合適?

沒關係,我們現在換一種內容推送方式:我們現在不用同步推了,而是用非同步拉。我們每次在手機上刷微博的時候,如果想要看到更新的內容是不是都要下拉刷新獲取?沒錯這就是非同步拉。

非同步拉有什麼好處呢?很明顯的一個好處就是可以將熱點數據進行集中管理,並且不用進行大量的數據插入冗餘操作。另外對系統資源的消耗也較少。

那麼微博內容從哪裡拉呢?主流的解決方案是把熱點內容放到緩存中,每次都去查緩存,這樣可以減少 I/O 操作並且避免發生因資源枯竭造成的超時問題。

其實高可用性架構還包括服務升級、服務降級、數據備份、失效轉移等等。關於網站高可用、高性能、高拓展方面感覺還有很多很多東西來寫。但是有些知識沒有一定的實踐經驗呢,又不能很好的掌握。

發表迴響