1. 程式人生 > >微信架構(轉)

微信架構(轉)

周顥,2001年畢業於華南理工大學,計算機專業碩士。2005年加入騰訊廣州研發部,歷任QQ郵箱架構師,廣研技術總監,T4技術專家,微信中心助理總經理。

騰訊廣研助理總經理、微信技術總監 周顥 CSDN配圖

周顥把微信的成功歸結於騰訊式的“三位一體”策略:即產品精準、專案敏捷、技術支撐。微信的成功是在三個方面的結合比較好,能夠超出絕大多數同行或對手,使得微信走到比較前的位置。所謂產品精準,通俗的講就是在恰當的時機做了恰當的事,推出了重量級功能,在合適的時間以最符合大家需求的方式推出去。他認為在整個微信的成功中,產品精準佔了很大一部分權重。

敏捷是一種態度 敏捷就是試錯

微信研發團隊裡鼓勵一種試錯的信仰:他們堅信,在網際網路開發裡,如果能夠有一個團隊在更短的時間內嘗試了更多機會(並能改進過來),就能有(更多的)機會勝出。敏捷是一種態度,在軟體開發過程中,專案管理者都會非常忌諱“變更”這個詞,但是在微信的專案運作中是不可以的。因為微信必須要容忍說哪怕在釋出前的十分鐘,也要允許他變更。這是非常大的挑戰,因為打破了所有傳統專案開發的常識。所有人都說不可能做到的,但微信做到了。研發團隊所做的一切都是要給產品決策者有最大的自由度,而這個決策正是微信能夠勝出的關鍵。

海量系統上的敏捷 無異於懸崖邊的跳舞

敏捷有很多困境,如果做一個單機版程式,是可以做到很敏捷的,但是騰訊正在運作的是一個海量系統,有千萬級使用者同時線上,在一個單獨的功能上每天有百億級的訪問,同時還要保證99.95%的可用性。在海量系統上應對專案開發會有很嚴謹的規範,都說要儘可能少的變化,因為90%-95%的錯誤都是在變更中產生的,如果系統一直不變更會獲得非常高的穩定度,但是微信就是要在懸崖邊跳舞。微信的研發團隊要做一些事情,讓敏捷開發變得更簡單。

如何做到這一切?周顥認為,首先,必須建立起一種狂熱的技術信念,就是一定是可以做到的。然後,需要用一些穩固的技術(理念)來支撐,例如大系統小做、讓一切可擴充套件、必須有基礎元件、輕鬆上線(灰度、灰度、再灰度;精細監控;迅速響應)...等等來支撐。

四大法器大系統小做、讓一切可擴充套件、要有基礎元件、輕鬆上線

大系統小做:當設計龐大系統的時候,應該儘量分割成更小的顆粒,使得專案之間的影響是最小的。一切可擴充套件:在高穩定度、高效能的系統中間,為了穩定效能把它設計成不變化的系統,但為了支援敏捷需要讓一切的東西都要變得可以擴充套件。必須建立基礎元件:要解決複雜問題的時候,需要將已有的經驗固化下來,固化下來的東西會成為系統中的一部分。輕鬆上線:當做了變化並把它從開發環境中部署到現有的運營環境中去,在這個過程中,“灰度”這個詞非常關鍵,就是在黑和白之間的選擇,必須要變成一種小規模嘗試,再逐步擴充套件到海量過程中的一個問題。

大系統小做——僅僅把模組變得更為清晰,這在海量系統設計開發中是不夠的,還需要在物理環境上進行分離部署,出現問題的時候可以快速發現,並且在最快的情況下解決掉。

轉播到騰訊微博

大系統小做 混搭模式

將不同的應用邏輯物理分割獨立出來,使用者註冊登入、LBS邏輯、搖一搖邏輯、漂流瓶邏輯、訊息邏輯獨立開來。把關鍵的邏輯混搭在一起,當所有的邏輯部署在同一個伺服器上,確實也會帶來很大敏捷上的好處,因為不需要額外的考慮部署和監控的問題。在整個微信的邏輯中,可能現在已經有上百種不同的邏輯,因為會在邏輯的分割上拆分成8-10種做分離部署。

一切可擴充套件——網路協議可擴充套件、資料儲存可擴充套件

擴充套件的關鍵點有兩塊。一個是網路協議需要擴充套件,當要升級一個新功能的時候,會有一些比較大的困難,所以所有協議設計都比較向前相容,但是向前相容還是不夠的,因為網路協議設計本身有非常多的功能也會有比較大的欄位,相關的程式碼可能會有數千行,這一塊不能通過手寫方式完成。可以通過XML描述,再通過工具自動生成所有的程式碼,這是微信獲得快速開發的一個重要的點。

另外一塊就是在資料儲存方面是必須可擴充套件的。在2005年絕大多數海量系統的設計都是採用固定欄位的儲存,但是在現代系統中會意識到這個問題,會採用KV或者TLV的方式,微信也做了不同的設計。

把複雜邏輯都固化下來,成為基礎軟體。在微信後臺會有幾種不同的基礎元件。大致包括:

Svrkit——Client/Server自動程式碼生成框架:10分鐘搭建內部伺服器LogicServer——邏輯容器:隨時新增新邏輯OssAgent——監控/統計框架:所見即所得的監控報表儲存元件——遮蔽容災/擴容等複雜問題

灰度、灰度、再灰度 

在變更後的部署方式上,微信在一些規則會限定不能一次把所有的邏輯變更上去,每一次變更一小點觀察到每一個環節沒有問題的時候,才能佈局到全網上去。微信後臺每一天可以支撐超過20個後臺變更,在業界來說,通常做到5個已經是比較快了,但是微信可以做到快4倍。 

轉播到騰訊微博

騰訊內部的上線系統 

而所謂灰度釋出,是指在黑與白之間,能夠平滑過渡的一種釋出方式。AB test就是一種灰度釋出方式,讓一部使用者繼續用A,一部分使用者開始用B,如果使用者對B沒有什麼反對意見,那麼逐步擴大範圍,把所有使用者都遷移到B上面 來。灰度釋出可以保證整體系統的穩定,在初始灰度的時候就可以發現、調整問題,以保證其影響度。(在騰訊,灰度釋出是最常採用的釋出方式之一) 

孫子兵法:古之所謂善戰者,勝於易勝者也 

常識上,解決一個複雜問題的時候,會用高明的技巧解決複雜的問題,這個不是微信團隊的目標,他們追求的要做到讓所有問題很自然和簡單的方式解決掉。在周顥看來,微信架構的技術複雜點在四個要點:協議、容災、輕重、監控。 

轉播到騰訊微博

微信架構 

協議。手機終端跟後臺伺服器之間的互動協議,這個協議的設計是整個系統的骨架,在這一點做好設計可以使得系統的複雜度大大降低。容災。當系統出現了若干伺服器或若干支架(宕機的時候),仍然需要讓系統儘可能的提供正常的服務。輕重。如何在系統架構中分佈功能,在哪一個點實現哪一個功能,代表系統中間的功能配置。監控。為系統提供一個智慧儀表盤。 

在協議設計上,移動網際網路和常規網際網路有很大的區別。首先有CMWAP和CMNET的不同,在中國現在有相當多的手機使用者使用WMWAP連線,還有就是線上和離線的概念,當QQ下線的時候叫離線,當你登入的時候叫線上。但是在移動網際網路這兩個概念比較模糊。從微信的設計中,不管線上還是離線系統表現都應該是一致的。還有一個是連線不穩定的問題,由於手機訊號強弱的變化,當時訊號很好,5秒鐘走到訊號不好的地區,連線就必須斷掉。這個中間帶來不穩定的因素為協議設計帶來較大困難。此外就是資費敏感的問題,因為移動網際網路是按照流量計費的,這個計費會使得在協議設計中如何最小化傳輸的問題。最後就是高延遲的問題。 

對此,業界標準的解決方案:Messaging And Presence Protocol:1)XMPP;2)SIP/SIMPLE。它的優點是簡單,大量開源實現。而缺點同樣明顯:1)流量大:狀態初始化;2)訊息不可靠。 

微信在系統中做了特殊設計,叫SYNC協議,是參考Activesyec來實現的。特點首先是基於狀態同步的協議,假定說收發訊息本身是狀態同步的過程,假定終端和伺服器狀態已經被遲了,在伺服器端收到最新的訊息,當客戶端、終端向伺服器對接的時候,收取訊息的過程實際上可以簡單的歸納為狀態同步的過程,收訊息以及收取你好友狀態更新都是相同的。在這樣的模式之下,我們會也許會把互動的模式統一化,只需要推送一個訊息到達的通知就可以了,終端收到這個通知就來做訊息的同步。在這樣的簡化模式之下,安卓和塞班都可以得到統一。這樣的系統本身的實現是更為複雜的,但是獲得很多額外的好處。 

讓剩下系統實現的部分更加簡單,簡化了互動模式,狀態同步可以通過狀態同步的差值獲得最小的資料變更,通過增量的傳輸得到最小的資料傳輸量。通過這樣的協議設計,微信可以確保訊息是穩定到達的,而且是按序到達。引用一句俗話:比它炫的沒它簡單,比它簡單的沒它快,沒誰比他更快,哪怕在GPRS下,微信也能把進度條輕易推到底。 

追求完美設計的團隊不能勝任海量服務 

在容災之前面向最壞的思考,如果系統真的掛了,需要做一些事情,首先是防止雪崩,避免蝴蝶效應。如果關注春節訂火車票就知道了,使用者的請求量會因為系統服務不了而不斷的重試,意味著發生雪崩的時候,系統可能會承載原先3-10倍的流量,使得所有的事情更加惡化。所以微信有很多“放雪”功能的設計。第二個詞是柔性可用,在任何的系統中不要追求完美設計,追求完美設計的是團隊是不能勝任海量服務的。如果在一個系統出現問題的時候,這個系統就掛了,那麼這是一個不好的設計,最好的做法是提供0-1中間的選擇。舉一個例子,當一個使用者向另外一個使用者發訊息的時候,可能會通過一個垃圾資訊過濾的檢測,如果垃圾資訊過濾這個模組突然掛掉了,這個訊息難道就不能達到了嗎?在這樣的情況下,要忽略掉這個錯誤,使得訊息正常達到對方。要精確定位出哪一個環節是最為重要的,把不是重要的錯誤儘可能的忽略掉。當不能做到完美的時候,儘可能為使用者提供服務。另外一個重要方面叫做“保護點前置”,最前的一個點就是終端,在手機終端上蘊埋更多的保護點,這樣會為使用者系統贏得更大的處理空間。如果終端具備這樣的能力,會獲得更大的反應空間。 

周顥介紹了在微信上具體容災設計的做法。在所有的容災中儲存層的容災是最難的,一個系統的設計分為三層:接入層、邏輯層、儲存層。接入層和邏輯層的容災都有比較成熟的方案。邏輯層的容災相對來說比較簡單,儘量不要有狀態的設計,比如說當你做上一個請求的時候,會保持一些狀態,要使得下一個請求發到下一個伺服器。如果任何一個請求之間互相不關聯的話,這個就是無狀態的設計,只要做到這一點邏輯層的容災可以隨意的切換。在回到儲存層本身的容災設計上,相對來說困難一些,但是微信研發團隊採用了一些技巧,叫分而治之,分離業務場景,尋求簡單的設計,並不會尋求大而同一的解決方案,因為這樣會使得系統的複雜度大幅度上升,而微信會盡可能把產品拆細,尋求簡化的設計。 

首先是主備容災,這是最常見的方案。在有一些業務場景中是可以容忍最終一致性的,比如賬號系統的設計,每天寫入賬號系統的請求是非常少的,但是訪問的請求非常多,這個差異可能會達到數萬倍的規模,在這樣的場景下,微信會在賬號系統中採用簡化的方案,也可以獲得比較大的穩定度。 

轉播到騰訊微博

SET模型+雙寫 

第二種容災的模式叫雙寫,兩臺Master的機器,當一臺機故障的時候,另外一臺機還是可以接收到寫請求,當兩臺機交錯啟動的時候,會得到資料的丟失。但是有一些場景是可以容忍輕度資料丟失的,比如說會有一個儲存專門記錄使用者終端的型別,比如說安卓還是塞班以及他們使用終端的微信版本是什麼,這樣的資料是可以容忍輕度資料丟失的,因為偶爾有一些丟失的話,下一次訪問會把這些資料帶上來,會盡快的修復所有的資料。雙寫也是非常簡單的模式。 

微信的研發團隊做了一個叫Simple Quorum的機制,在微信的後臺中,同步協議有一個很重要的基石叫序列發生器,這樣的一個序列發生器需要有極高的穩定度。首先可以看到序列號有一個特點永遠是遞增的,用遞增方式往前推進的時候,最大的序列號就是最新的系列號。有一個畢業才加入廣研的畢業生想到一個絕佳的方案,按SET分佈,從2G減到200K。

前輕後重 功能點後移 

周顥還談到了輕重的概念。這個概念的提出主要是從終端本身的一些困境所帶來的。首先在終端上需要表現最多的一個產品的邏輯,邏輯非常複雜,變更的成本也非常高,當需要修復的時候必須釋出一個新版本,這個新版必須由自己下載才能完成,下載的成本非常高。在這樣的前提下,如果手機終端產生了任何變化的時候,如果這個變化有非常大的問題就會有極大的困境,所以需要在每一個釋出之前做一些充分的資料,確保不會發生致命問題。如果一旦出現致命問題難以修復,需要把關鍵的點從終端移到後臺實現,把功能點後移,來充分發揮後臺快速變更的能力。 

轉播到騰訊微博

接入優化:從GSLB到IP重定向 

在接入層的優化,速度很重要的因素,是不是能夠就近接入一個最優的節點,比如說移動使用者最好接入移動的節點,海外的使用者可能需要尋找更佳的路由,有的時候可能無法自動做到這一點,一點是在終端上做測速,微信會通過在後臺IP逆向的能力,通過後臺指揮微信終端聯網的能力,尋找最優的接入點。上圖就是每分鐘收到同一項指令曲線的報表。 

如何解決“偷流量”的問題——當國內類微信類產品釋出的時候出現一個大的問題就是“偷流量”,當用戶在某一些邏輯下進行一個死迴圈,不斷訪問某一些資料,這樣的死迴圈是非常可怕的,如果在使用者不知覺的情況之下,可能會在一個小時之內偷到數10兆甚至數百兆的流量。有非常多業內的同行都需要花大量的精力解決這個問題,微信研發團隊用了非常強大的方式解決它。通過在後臺建立起嚴厲的監控系統,對每一個使用者的行為做一個監控,當發現異常的時候,後臺會給終端發出指令,使得微信終端在一段時間無法聯網,但是可以保證使用者流量不會白白的使用掉。 

功能適配的例子——第一期微信版本釋出的時候,當時沒有群聊的功能,第二版釋出的時候做了這個功能。當時有兩個選擇,對於早期版本的使用者,因為不支援群聊,就無法享用到這個功能,但是微信希望提供更好的選擇,想讓早期不支援群聊的版本,也可以被拉到一個群裡面收訊息、發訊息,通過後臺功能的適配也能做到這個事情。 

分而治之 把監控嵌入基礎框架 

對於一個海量系統來說,一個精密的儀表盤非常重要。監控是非常痛苦的,對於這樣一個系統來說,每小時會產生數百G的監控日誌。微信希望在1分鐘之內監控的資料就能夠顯示在報表上,因為只有這樣的精準和實時度才能夠贏得處理故障的時間。微信會做關聯統計,通過搖一搖加了好友,他們活躍度如何,過了一段時間他們的活躍度變化情況又是如何。這種需求是需要通過大量日誌的關聯統計來獲得的。研發團隊也花了一段時間來理解這個問題,發現了中間一個重要的經驗叫做“魚和熊掌不能兼得”。 

為了讓監控數值更敏感,需要把監控細化再細化,上面資料表示每一欄子系統的資料,下面這個是按微信版本號來劃分的,這裡的資料項是非常多。 

微信還需要採集一些異常的點,如果有異常的話會發布緊急的版本,儘可能快的替換它。對收發訊息延時做的監控,比如說0—1秒端到端的速度,會對不同的區段做一些統計,當某一個環節出現異常的時候,通常會在中間的延時上體現出來。有一個很重要的點叫自動報警,現在有數千項的資料,不可能每一項都靠人工去看的,必須要跟自動報警相關聯,微信有一些智慧的演算法,是不是在正常的範圍內,跟歷史的數值進行對比,如果有異常的話,會通過簡訊、郵件還有微信本身來發出報警資訊。 

轉播到騰訊微博

把監控嵌入基礎框架 

微信會把監控嵌入到基礎框架裡面去,因為並不是每一個人都會意識到在需要的地方嵌入一個監控點,所以在基礎框架本身內建很重要的監控點,比如說這個表上的欄目,非常多的欄目大概會有數百項的欄目,都不需要程式設計師自己去寫,當用基礎元件搭建一個系統的時候,就可以直接觀測系統資料。 

在談到微信未來的技術挑戰時,周顥首先希望能夠讓微信成為可用性99.99%的系統;設計出面向現在10倍容量的系統以及完全的IDC容災。 

網上盛傳的凌晨兩點,騰訊大廈那多層大片大片的燈光和樓下那長長的計程車隊伍說明了一切。引用一句話做結尾,可怕的不是微信,真正可怕的是,比你領先比你更有天賦的團隊比你更努力。