從頭搭建一個“微博”有多難

今天是分佈式專題的第13篇

,今天的文章我們不講空洞的理論,來聊一個實際點的問題。


眾所周知,微博的程序員經常不定期加班。和別的程序員不同,別的崗位的程序員可能加班是可控的,但是微博的程序員不是。為什麼呢?因為程序員們無法預知明星們什麼時候有新的大料產生,一旦有新料,微博崩潰是妥妥的。甚至很多粉絲用微博有沒有崩潰來衡量一個明星的知名度。


這當然只是個段子,但是對於我們搞技術的來說總忍不住問一個問題,微博也算是一個蠻大不小的公司,不缺錢也不缺人,為什麼系統這麼不穩定呢?


當然我沒有在微博呆過,為了嚴謹起見,我們假設我們現在開了一個類似的新的app,就叫做微特好了。我們來看看微特這個app從0開始成長的過程當中究竟會遇到哪些問題。通過微特這個虛假的項目,我們多少也可以推測一下微博不穩定背後的原因。


微特的誕生


某年某月某天,微特誕生了,為了簡化問題,我們假設微特只有兩個功能,就是發微特和看微特


剛剛誕生的小企業嘛,請不起知名的架構師,當然是怎麼簡單怎麼來。我們拆分一下功能,會發現一共只有三個功能,用戶發微特、關注其他用戶和查看微特,這三個功能都很簡單,幾乎就是裸的增刪改查,我們一個一個看。


先看用戶發微特,用戶發微特我們只需要用一張表記錄微特的內容即可。這個表呢大概長這樣:

從頭搭建一個“微博”有多難


第二個功能是關注用戶,我們再用一張表記錄一下用戶之間的關注關係即可,這也非常簡單:

從頭搭建一個“微博”有多難

有了這兩張表之後,我們要查看微特就簡單了,我們只需要通過userid去關注表裡面去關聯關注的用戶,然後在用關注的用戶的id去關聯發過的微特即可。


我們用SQL來表示一下這個查詢關係。

<code>select wetwi.*
from (
  select followeeid
  from follower
  where followerid = curid
)a join wetwi
on a.followeeid = wetwi.userid/<code>

經過一番測試之後,微特順利上線,老闆試用了一下,覺得很滿意。新用戶也漲得很快,負責的程序員A得到老闆的賞識,一路晉升上去變成管理層,不再直接負責項目的技術問題了。


此人的一個手下B被委以重任,負責起了項目,但是就在這個時候,問題出現了。


微特一階段


隨著用戶數量的增大,用戶們關注的數字開始了迅速增長,很快平均一個用戶都關注了好幾十個其他用戶。每次用戶刷新的時候,都會同時加載這好幾十人發佈的微特內容。加上微特支持圖片,最多的時候一時刻需要加載好幾十張圖片和大量文本,

服務器來不及傳輸這麼多數據,頻繁的有用戶反饋說刷新的時候總是超時。


B想了想,這個簡單啊,我們可以分成開源和節流兩步。


首先我們需要開源,除了加大機器數量之外,我們需要租借CDN,將用戶上傳的圖片放到CDN上而不存儲在數據庫裡,從而加速數據傳輸的速度。


節流怎麼辦呢,也簡單我們再用一張表來存儲用戶最近一次刷新的時間。這樣我們在查詢的時候,只需要查詢這個時間點之後的數據就行了。於是我們多了一張記錄時間的表。

從頭搭建一個“微博”有多難

這麼一搞,系統總算穩定住了,用戶抱怨的人數進一步變少。很快用戶量又有了爆炸式的提升,終於有一天,熱點事件一個接著一個,系統終於扛不住了,接二連三地宕機。


為什麼會宕機呢?


因為數據庫的查詢需要時間,本來就比較慢,加上了join操作之後,系統變得更慢。現在由於要判斷微特發送的時間來做過濾,額外增加了一次查詢,到達瓶頸之後自然就扛不住了。


B絞盡腦汁,終於想到了辦法,就是緩存。他緩存了用戶最後一次刷新的時間,這樣就可以減少一次數據庫的查詢。系統稍微變快了一點,但是並沒有堅持多久,終於老闆忍無可忍開除了B,花大價錢從大公司挖來了一個架構師C。


與此同時,微特的用戶量進一步增長,到了第二個階段。


微特二階段


C熟悉了環境之後,氣得直罵娘,不從架構考慮問題,只會修修補補要不得啊。怎麼可以直接用DB存儲數據呢,搞成這樣不崩潰才有鬼。


新官上任三把火,搞走了幾個混吃等死的老白兔,C又招來當年的幾個手下,開始大張旗鼓地重構系統。在分佈式系統當中,DB往往都是瓶頸,能不用DB的就不應該用DB。而且微特的模式非常明顯,用戶發佈了新內容之後,最關心的就是他的粉絲,那麼我們直接在他更新的時候,就把內容推送到粉絲的緩存裡,當用戶刷新的時候,直接從緩存拉取數據,這不是要方便得多嗎?


C畫出了新的架構圖(可見C也是靈魂畫手):

從頭搭建一個“微博”有多難

微特直接通過kafka等消息系統推送給用戶,效率要比DB高多了,C的一幫手下也給力,很快就完成了架構升級。上線之後,果然效果非凡,系統立刻變得穩定了許多,用戶抱怨大幅減少。


在這幾年裡,公司聲名鵲起,積累了大量的資源,一舉去美國上市了。公司的高管都財富自由了,C來得晚沒分到多少,並且看到當年埋了大坑的A混的風生水起,加上長久以來的不和,氣不過跑路了。


就在這風生水起的時候,意想不到的事情又發生了。而我們的微特也來到了階段3。


微特三階段


C走了之後,系統從此再也沒有大的改動,大家都只想把眼前修修補補的工作做好。反正公司也上市了,老闆也自由了,底層的員工只想安安穩穩賺點工資。加上系統也穩定得很,沒有人覺得有什麼改動的必要。


但是由於微特現在太火了,使用的用戶越來越多,除了普通用戶之外,還把明星藝人吸引來了。這些明星藝人,一個個都有好幾千萬的粉絲。不是之前升級了架構,改成了通過kafka推送消息而不是去DB查詢嗎?這下好了,這些明星每次一發微特,都需要發送好幾千萬次消息。


有幾天不知道是過節還是碰巧,這些明星藝人偏偏一起發推,直接就把發送消息的系統擠壓掛了。這一掛,雖然微特整個系統沒有崩潰,但是吃瓜群眾發現再也搜索不到微特了。於是一起在網上罵微特,這一罵,需要發送的消息更多,系統更加扛不住,徹底成了死循環,公司的口碑急轉直下。


公司也想解決這個問題,奈何之前做了太多修修補補的工作,整個系統變得非常複雜,很多模塊耦合在了一起,加上也沒有一個很好的方案,一直也沒有一個人下得了決心整個重構,反而往上加了更多補丁


直到後來,A離職了之後,公司新來的CTO招來了一個業內技術骨幹D。D提出了新的想法,將前面兩種方案作了折中。大V發送的時候,並不推送到所有粉絲,而是

只推送給當前在線的粉絲。離線的粉絲還是通過查詢來獲取數據。這樣一來對流量進行了分流,微特系統變得穩定了許多。


但是這並沒有真正徹底解決問題,系統仍然有時候會宕機,但是一時半會也沒有什麼特別好的辦法,系統也變得極為臃腫徹底經不起折騰。於是微特就這樣修修補補,變成了程序員加班不規律的公司。


後續


所謂的微特當然是個段子,故事也不是真的,但是技術架構的變遷還是很有參考意義。一個看似簡單的問題,真正落地到應用場景當中,往往沒有那麼簡單。系統眼前的穩定也不能代表長遠,這也是我們在開始一個項目的時候就需要眼光長遠做好規劃的原因。更是一個優秀的架構師的價值所在,只不過可惜的是,世上的道理總是這樣,知道的人太多,做到的太少。


希望今天這個的這個故事在博君一笑的同時也能給大家一點啟發,一個成功的優秀的系統背後,究竟藏著多少思考和心血呢?


今天的文章就是這些,如果覺得有所收穫,請順手點個關注或者轉發吧,你們的舉手之勞對我來說很重要。


分享到:


相關文章: