滴滴出行分而治之的架構設計之道
原創(chuàng)【本文是WOT2016互聯(lián)網(wǎng)運維與開發(fā)者大會的現(xiàn)場干貨, 新一屆主題為WOT2016企業(yè)安全技術峰會將在2016年6月24日-25日于北京珠三角JW萬豪酒店隆重召開!】
如今,我們去任何一個地方都要先問問有沒有Wi-Fi,網(wǎng)絡已經(jīng)明顯影響到我們的生活。
互聯(lián)網(wǎng)生下來就是為了服務海量用戶,在這個時代,幾乎沒有哪個應用再為單機而生。每個公司的每個產(chǎn)品將要面臨的都是不可預知的用戶海量請求。顯然這個靠分布式程序來解決,比依靠單機靠譜得多。然而不幸的是,如果一開始你的架構設計不可擴展,有再多的機器,有再多的云解決方案,對你來說至多是將單機程序跑在了一個虛擬的單機上。下面就讓我們回到WOT2016 互聯(lián)網(wǎng)運維與開發(fā)者大會現(xiàn)場,跟隨滴滴出行***架構師一起了解,分布時代架構設計和程序開發(fā)面臨著哪些新挑戰(zhàn),以及滴滴出行的應對思路。
李令輝,滴滴出行***架構師,于2014年中加入滴滴,經(jīng)歷了滴滴高速成長的階段,見證了滴滴從一個打車軟件變成一個出行平臺。移動互聯(lián)網(wǎng)資深從業(yè)者,對移動互聯(lián)網(wǎng)技術發(fā)展趨勢以及技術團隊的組建有獨道見解。他具有多年互聯(lián)網(wǎng)架構的設計經(jīng)驗,擅長高性能高并發(fā)高可用的架構設計工作,主導了滴滴打車技術迭代中的核心服務架構升級。
分布式時代的困境
為單機而生的應用將不復存在
很少有一個應用能準確預測自己的用戶量有多大,因此,一開始就為上億用戶去設計一個極為復雜的分布式架構,幾乎是不可能的。因為這不僅會帶來極高的成本,還會犧牲整個系統(tǒng)的靈活度。并不是每個公司都像谷歌一樣,在創(chuàng)業(yè)初期就有面對世界上所有數(shù)據(jù)的雄心壯志,來開發(fā)一個分布式文件系統(tǒng)。大多數(shù)公司一定是從幾臺服務器起家,在用戶不斷增長,并發(fā)請求增加,業(yè)務越來越復雜的過程中,百臨不得已將程序從單機搬到多臺機器。把單個進程拆成多個服務的問題。
分布式開發(fā)工具的缺乏
每個人的工作量平白無故一個互聯(lián)網(wǎng)的多個節(jié)點組成的,通過網(wǎng)絡耦合的一個分布式環(huán)境。平白無故的被這種分布式帶來的必然復雜性提高了。但是,真正的分布式開發(fā)工具還遠未成熟。 程序員可以使用的工具還是古老的VI,四十年前的Emacs和十幾年前的Eclipse等單機開發(fā)工具,服務之間的依賴關系完全無法管理,日志格式和日志內容無法保證一致和可追溯。上線,擴容,降級等運維工作和規(guī)范沒有被很好的設計。 任何一次問題或者開發(fā),都需要多人協(xié)作,效率極為低下。
重造車輪的解決方案
看起來,業(yè)界解決方案百花爭鳴。但實際上,大部分都是基于開源的RPC方案,比較成型的幾個方案包括Erlang OTP, Scala Akka等。公司內通過各種定制的方案去耦合,去互相管理關系,互相依賴,把一個事工作起來。大一點的公司會強制的推行運維規(guī)范。而每個公司或者社區(qū)都對這種分布式環(huán)境用自己的理解。 這帶來的后果是,大家都在開源社區(qū)的基礎上重復造同樣的東西,這個是成本很高的事情。
再者,很多解決方案都依賴于特定的業(yè)務場景來制定。比如通訊軟件,對實時性要求很高,對可用性要求非常高,然而電商并不那么關心一個請求能不能快速返回,而是強調數(shù)據(jù)的一致性。所以每個業(yè)務特點決定了有不同的解決方案,而且很少有為分布式而生的方案,都是從單機方案演化或者漸變來的,這些問題都會讓每一個在從中開發(fā)的人不得不知道全貌,對研發(fā)效率來講是個巨大的傷害。分布式也確實個足夠復雜的領域,很難有一攬子通用解決方案。
那么,在設計分布式系統(tǒng)架構時,應該考慮哪些方面?
分布式架構設計基本要素
容錯
在分布式環(huán)境里,錯誤無處不在,并且無時無刻不在發(fā)生。而且,錯誤不只是機器故障,當幾百人投入研發(fā)工作的時候,一定會有人犯錯,而且每個人都會犯錯,會常態(tài)的犯錯。因此,研發(fā)團隊不應該只想著如何避免錯誤的發(fā)生,而是如何在小錯誤下,不影響業(yè)務,保持服務健康運營。而一但不加考慮的對架構每個模塊進行降級,勢必帶來一場巨大的災難。
數(shù)據(jù)格式
數(shù)據(jù)格式實際面臨的困境和依賴管理是一樣的。因為每個人只負責單獨的模塊,而不會去關心整個業(yè)務用什么樣的數(shù)據(jù)格式通信。究竟代碼中到底多少是用來Verify Data的?又有多少是用來Pack/Unpack Data的?如果不統(tǒng)一就會陷入泥潭,工作效率低到無法接受,日志收集和監(jiān)控也幾乎沒法實現(xiàn)。
路由層
關于路由層的解決方案沒有高下之分,只要能解業(yè)務中的問題,降低運維成本和開發(fā)成本,就是好的方案。
但是,一定要盡量避免同時存在多種解決方案。函數(shù)調用是路由,反射是路由,URL是路由,RPC的IP+Port+Function也是路由。雖然說,并不是所有業(yè)務都能用統(tǒng)一的方法來路由的。路由的靈活性和規(guī)范性決定了運維難度,盲目追求靈活度平白無故的又把運維提的工作高一個量級。架構本質是控制復雜度,主要方法就是分而治之,解耦,耦合從本質上來說就是路由。
服務
為了滿足用戶新的要求,追上市場新的步伐,每個互聯(lián)網(wǎng)公司的研發(fā)團隊都不曾停下腳步,保證服務不斷進化和升級。這同時也帶來了許多問題:
- 如何穩(wěn)定高效的迭代?
- 依賴剛迭代的服務的舊服務怎么辦?
- 我想給某個服務/模塊做AB Test怎么辦?
- 多個模塊可以同時做AB Test么?
- 如果不能,研發(fā)變成串行上線真的好么?
看待這些問題一定要從全局出發(fā),而最重要的是接口的統(tǒng)一,形成一致的標準,讓大家在一條共同的準繩上。
監(jiān)控
現(xiàn)在大家所做的監(jiān)控,基本都是在監(jiān)控機器的狀態(tài)。其實在幾百臺機器這樣的較小規(guī)模下,這樣做的意義并不大。真正應該監(jiān)控的,應該是程序。而嚴控程序的狀態(tài),只能依賴日志。
因此,每個架構師都要考慮,如何設計可以監(jiān)控服務的日志系統(tǒng),要提供可監(jiān)控的接口。是每個架構師要考慮你的服務是怎么被監(jiān)控的,你要提供可監(jiān)控的接口。至于采集間隔,一般來說規(guī)模越大,采集粒度越低,規(guī)模越小,采集粒度越高。
另外,監(jiān)控的信息是Pull or Push?監(jiān)控的結果全部需要人來處理么?日志是否可以用來作為系統(tǒng)之間交互的數(shù)據(jù)?這些問題都需要大家根據(jù)自己的業(yè)務場景不斷探索。
你的運維方案***嗎?
每個公司的運維團隊都在考慮這個問題。你的目的是為了降低你的成本,提高你的效率。請合理的計算你的成本和效率,就是你要把人算進去,而不是就算機器。大家可以通過以下幾個維度來評估:
- 資源利用率如何?對大部分團隊來說,研發(fā)的人力成本要遠遠高于機器成本,你要首先考慮的是你的人都并發(fā)起來了,而不是你的CPU都被吃掉了
- 解決方案是否簡單?這對應著人才招聘的門檻。對于新人來說,總要讓他快速的上手做一個項目,驗證自己的能力,所以解決方案一定要相對簡單。怎么擴容,怎么縮容,都應該有成型的一整套方案
- 開發(fā)測試上線流程是否需要人工介入?
- 小流量測試的支持如何?
- 回滾、限流、斷流方案是否統(tǒng)一提供等等問題 ?
滴滴出行的分布式設構設計思路
Linux之所以強大,是因為每一個模塊都只負責最簡單的事情,面對輸入和輸出,而輸入和輸出的格式是確定的。分布式架構設計的思路也應如此,同樣的規(guī)則,同樣的用法組合在一起是可以發(fā)揮巨大作用的。
滴滴出行的分布架構設計想要解決的問題,不只是簡單的機器運維,而是人在研發(fā)過程中,如何避免復雜環(huán)境中可能面臨的風險,解決由于粗糙的架構設計帶來的效率低下,不可控,不穩(wěn)定的狀態(tài)。
這樣的架構設計帶來的一個巨大好處是,信息流在進來的時候進入信息分發(fā),信息分發(fā)把它分到合適的管道,那個管道處理完再放給下一個管道。每個管道都只做輸入和輸出的事情,實現(xiàn)高可用、高吞吐。這種方案很多云服務商都會提供。這樣做的好處時是,我們只需要管理消息隊列,可以在任意一個節(jié)點把流量復制走。在任何一個環(huán)節(jié)中可以拿到它所有的數(shù)據(jù),不再依賴日志,只依賴輸入、輸出。而輸入、輸出是存在硬盤上的,數(shù)據(jù)不會丟失。
另一個優(yōu)點是進程是異步傳輸?shù)?。同步模型一個很明顯的缺點是在所有的層次中,一個進程在執(zhí)行某個請求的時候如果需要一段時間才能返回信息,那么這個進程將會一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去。在流量很大的時候,做一個重試可能某一個環(huán)節(jié)就會面臨崩潰了,某個環(huán)節(jié)的連接數(shù)被打滿。
而在這個方案中,連接就只有兩三處,不需要等待數(shù)據(jù)回報,只需要確認收據(jù)接收,而且不需要逐條驗證。成本很低,性能很高。
但這種架構設計顯然不能解決所有的問題。比如用MySQL作為存儲等必須同步的服務時,需要給有狀態(tài)的服務提供一個抽象層Service,上面的服務可以請求它。大家可以理解為在Linux中敲一個命令要讀一個文件,那個文件是有狀態(tài)的,是存在那里的,而這些模塊是沒有狀態(tài)的。
滴滴選擇了Docker+Kubernetes作為分布集群管理解決方案,它的好處是可以直接提供資源管理,資源隔離,部署,升級,路由等等需求。但是,只有Kubernetes是不夠的,Kubernetes只能管理那些無狀態(tài)的事務。并不是所有的事情都可以完全抽象成無狀態(tài)的,有狀態(tài)的部分應該如何實現(xiàn)擴容,都要依據(jù)具體的業(yè)務場景,這是很難的設計。
***要說的是,沒有***的方案,如果你自己要開發(fā)這個事情,建議大家***用一種方案,不要每一個用一種。但是沒辦法,面對不同的研發(fā)人員,不同的場景等現(xiàn)實,現(xiàn)在還沒有最終的結論。也希望能借此文,與各位業(yè)界同仁共同探討。
【演講視頻】