當前位置:
首頁 > 科技 > 左耳朵耗子:從亞馬遜的實踐,談分散式系統的難點

左耳朵耗子:從亞馬遜的實踐,談分散式系統的難點

接收程序員的技術早餐

作者|陳皓

編輯|楊爽

本文摘自陳皓(左耳朵耗子)在極客時間 App/ 小程序上開始的全年付費專欄《左耳聽風》,已獲授權。更多分散式系統關鍵技術、性能調優攻略,請點擊下圖查看,新用戶註冊立減 30 元,支持微信支付

從目前可以得到的信息來看,對分散式服務化架構實踐最早的應該是亞馬遜。因為早在 2002 年的時候,亞馬遜 CEO 傑夫·貝索斯(Jeff Bezos)就向全公司頒布了下面的這幾條架構規定(來自《Steve Yegge 對 Google 平台吐槽》一文)。

所有團隊的程序模塊都要通過 Service Interface 方式將其數據與功能開放出來。

團隊間程序模塊的信息通信,都要通過這些介面。

除此之外沒有其它的通信方式。其他形式一概不允許:不能直接鏈結別的程序(把其他團隊的程序當做動態鏈接庫來鏈接),不能直接讀取其他團隊的資料庫,不能使用共享內存模式,不能使用別人模塊的後門,等等。唯一允許的通信方式是調用 Service Interface。

任何技術都可以使用。比如:HTTP、CORBA、Pub/Sub、自定義的網路協議等。

所有的 Service Interface,毫無例外,都必須從骨子裡到表面上設計成能對外界開放的。也就是說,團隊必須做好規劃與設計,以便未來把介面開放給全世界的程序員,沒有任何例外。

不這樣做的人會被炒魷魚。

這應該就是 AWS(Amazon Web Service)出現的基因吧。當然,前面說過,採用分散式系統架構後會出現很多的問題。比如:

一個線上故障的工單會在不同的服務和不同的團隊中轉過來轉過去的。

每個團隊都可能成為一個潛在的 DDoS 攻擊者,除非每個服務都要做好配額和限流。

監控和查錯變得更為複雜。除非有非常強大的監控手段。

服務發現和服務治理也變得非常複雜。

為了克服這些問題,亞馬遜這麼多年的實踐讓其可以運維和管理極其複雜的分散式服務架構。我覺得主要有以下幾點。

分散式服務的架構需要分散式的團隊架構。在亞馬遜,一個服務由一個小團隊(Two Pizza Team 不超過 16 個人,兩張 Pizza 可以餵飽的團隊)負責,從前端負責到數據,從需求分析負責到上線運維。這是良性的分工策略——按職責分工,而不是按技能分工。

分散式服務查錯不容易。一旦出現比較嚴重的故障,需要整體查錯。出現一個 S2 的故障,就可以看到每個團隊的人都會上線。在工單系統里能看到,在故障發生的一開始,大家都在簽到並自查自己的系統。如果沒問題,也要在線待命(standby),等問題解決。(我在《故障處理最佳實踐:應對故障》一文中詳細地講過這個事)。

沒有專職的測試人員,也沒有專職的運維人員,開發人員做所有的事情。開發人員做所有事情的好處是——吃自己的狗糧(Eat Your Own Dog Food) 最微觀的實踐。自己寫的代碼自己維護自己養,會讓開發人員明白,寫代碼容易維護代碼複雜。這樣,開發人員在接需求、做設計、寫代碼、做工具時都會考慮到軟體的長期維護性。

運維優先,崇尚簡化和自動化。為了能夠運維如此複雜的系統,亞馬遜內部在運維上下了非常大的功夫。現在人們所說的 DevOps 這個事,亞馬遜在 10 多年前就做到了。亞馬遜最為強大的就是運維,拚命地對系統進行簡化和自動化,讓亞馬遜做到了可以輕鬆運維擁有上千萬台虛機的 AWS 雲平台。

內部服務和外部服務一致。無論是從安全方面,還是介面設計方面,無論是從運維方面,還是故障處理的流程方面,亞馬遜的內部系統都和外部系統一樣對待。這樣做的好處是,內部系統的服務隨時都可以開放出來。而且,從第一天開始,服務提供方就有對外服務的能力。可以想像,以這樣的標準運作的團隊其能力會是什麼樣的。

在進化的過程中,亞馬遜遇到的問題很多,甚至還有很多幾乎沒有人會想到的非常生僻的東西,它都一一學習和總結了,而且都解決得很好。

構建分散式系統非常難,充滿了各種各樣的問題,但亞馬遜還是毫不猶豫地走了下去。這是因為亞馬遜想做平台,不是「像淘寶這樣的中介式流量平台」,而是那種「可以對外輸出能力的平台」。

亞馬遜覺得自己沒有像史蒂夫·喬布斯(Steve Jobs)這樣的牛人,不可能做出像 iPhone 這樣的爆款產品,而且用戶天生就是眾口難調,與其做一個大家都不滿意的軟體,還不如把一些基礎能力對外輸出,引入外部的力量來一起完成一個用戶滿意的產品。這其實就是在建立自己的生態圈。雖然在今天看來這個事已經不稀奇了,但是貝索斯早在十五年前就悟到了,實在是個天才。

所以,分散式服務架構是需要從組織,到軟體工程,再到技術上的一個大的改造,需要比較長的時間來磨合和改進,並不斷地總結教訓和成功經驗。

分散式系統中需要注意的問題

我們再來看一下分散式系統在技術上需要注意的問題。

問題一:異構系統的不標準問題

這主要表現在:

軟體和應用不標準。

通訊協議不標準。

數據格式不標準。

開發和運維的過程和方法不標準。

不同的軟體,不同的語言會出現不同的兼容性和不同的開發、測試、運維標準。不同的標準會讓我們用不同的方式來開發和運維,引起架構複雜度的提升。比如:有的軟體修改配置要改它的.conf 文件,而有的則是調用管理 API 介面。

在通訊方面,不同的軟體用不同的協議,就算是相同的網路協議里也會出現不同的數據格式。還有,不同的團隊因為用不同的技術,會有不同的開發和運維方式。這些不同的東西,會讓我們的整個分散式系統架構變得異常複雜。所以,分散式系統架構需要有相應的規範。

比如,我看到,很多服務的 API 出錯不返回 HTTP 的錯誤狀態碼,而是返回個正常的狀態碼 200,然後在 HTTP Body 里的 JSON 字元串中寫著個:error,bla bla error message。這簡直就是一種反人類的做法。我實在不明白為什麼會有眾多這樣的設計。這讓監控怎麼做啊?現在,你應該使用 Swagger 的規範了。

再比如,我看到很多公司的軟體配置管理里就是一個 key-value 的東西,這樣的東西靈活到可以很容易地被濫用。不規範的配置命名,不規範的值,甚至在配置中直接嵌入前端展示內容……

一個好的配置管理,應該分成三層:底層和操作系統相關,中間層和中間件相關,最上面和業務應用相關。於是底層和中間層是不能讓用戶靈活修改的,而是只讓用戶選擇。比如:操作系統的相關配置應該形成模板來讓人選擇,而不是讓人亂配置的。只有配置系統形成了規範,我們才 hold 得住眾多的系統。

再比如:數據通訊協議。通常來說,作為一個協議,一定要有協議頭和協議體。協議頭定義了最基本的協議數據,而協議體才是真正的業務數據。對於協議頭,我們需要非常規範地讓每一個使用這個協議的團隊都使用一套標準的方式來定義,這樣我們才容易對請求進行監控、調度和管理。

這樣的規範還有很多,我在這就不一一列舉了。

問題二:系統架構中的服務依賴性問題

對於傳統的單體應用,一台機器掛了,整個軟體就掛掉了。但是你千萬不要以為在分散式的架構下不會發生這樣的事。分散式架構下,服務是會有依賴的,於是一個服務依賴鏈上,某個服務掛掉了,會導致出現「多米諾骨牌」效應,會倒一片。

所以,在分散式系統中,服務的依賴也會帶來一些問題。

如果非關鍵業務被關鍵業務所依賴,會導致非關鍵業務變成一個關鍵業務。

服務依賴鏈中,出現「木桶短板效應」——整個 SLA 由最差的那個服務所決定。

這是服務治理的內容了。服務治理不但需要我們定義出服務的關鍵程度,還需要我們定義或是描述出關鍵業務或服務調用的主要路徑。沒有這個事情,我們將無法運維或是管理整個系統。

這裡需要注意的是,很多分散式架構在應用層上做到了業務隔離,然而,在資料庫結點上並沒有。如果一個非關鍵業務把資料庫拖死,那麼會導致全站不可用。所以,資料庫方面也需要做相應的隔離。也就是說,最好一個業務線用一套自己的資料庫。這就是亞馬遜伺服器的實踐——系統間不能讀取對方的資料庫,只通過服務介面耦合。這也是微服務的要求。我們不但要拆分服務,還要為每個服務拆分相應的資料庫。

問題三:故障發生的概率更大

在分散式系統中,因為使用的機器和服務會非常多,所以,故障發生的頻率會比傳統的單體應用更大。只不過,單體應用的故障影響面很大,而分散式系統中,雖然故障的影響面可以被隔離,但是因為機器和服務多,出故障的頻率也會多。另一方面,因為管理複雜,而且沒人知道整個架構中有什麼,所以非常容易犯錯誤。

你會發現,對分散式系統架構的運維,簡直就是一場噩夢。我們會慢慢地明白下面這些道理。

出現故障不可怕,故障恢復時間過長才可怕。

出現故障不可怕,故障影響面過大才可怕。

運維團隊在分散式系統下會非常忙,忙到每時每刻都要處理大大小小的故障。我看到,很多大公司,都在自己的系統里拚命地添加各種監控指標,有的能夠添加出幾萬個監控指標。我覺得這完全是在「使蠻力」。一方面,信息太多等於沒有信息,另一方面,SLA 要求我們定義出「Key Metrics」,也就是所謂的關鍵指標。然而,他們卻沒有。這其實是一種思維上的懶惰。

但是,上述的都是在「救火階段」而不是「防火階段」。所謂「防火勝於救火」,我們還要考慮如何防火,這需要我們在設計或運維繫統時都要為這些故障考慮,即所謂 Design for Failure。在設計時就要考慮如何減輕故障。如果無法避免,也要使用自動化的方式恢復故障,減少故障影響面。

因為當機器和服務數量越來越多時,你會發現,人類的缺陷就成為了瓶頸。這個缺陷就是人類無法對複雜的事情做到事無巨細的管理,只有機器自動化才能幫助人類。 也就是,人管代碼,代碼管機器,人不管機器!

問題四:多層架構的運維複雜度更大

通常來說,我們可以把系統分成四層:基礎層、平台層、應用層和接入層。

基礎層就是我們的機器、網路和存儲設備等。

平台層就是我們的中間件層,Tomcat、MySQL、Redis、Kafka 之類的軟體。

應用層就是我們的業務軟體,比如,各種功能的服務。

接入層就是接入用戶請求的網關、負載均衡或是 CDN、DNS 這樣的東西。

對於這四層,我們需要知道:

任何一層的問題都會導致整體的問題;

沒有統一的視圖和管理,導致運維被割裂開來,造成更大的複雜度。

很多公司都是按技能分工是,把技術團隊分為產品開發、中間件開發、業務運維、系統運維等子團隊。這樣的分工導致各管一攤,很多事情完全連不在一起。整個系統會像 「多米諾骨牌」一樣,一個環節出現問題,就會倒下去一大片。因為沒有一個統一的運維視圖,不知道一個服務調用是如何經過每一個服務和資源,也就導致我們在出現故障時要花大量的時間在溝通和定位問題上。

之前我在某雲平台的一次經歷就是這樣的。從接入層到負載均衡,再到服務層,再到操作系統底層,設置的 KeepAlive 的參數完全不一致,導致用戶發現,軟體運行的行為和文檔中定義的完全不一樣。工程師查錯的過程簡直就是一場惡夢,以為找到了一個,結果還有一個,來來回回花了大量的時間才把所有 KeepAlive 的參數設置成一致的,浪費了太多的時間。

分工不是問題,問題是分工後的協作是否統一和規範。這點,你一定要重視。

小 結

好了,我們來總結一下今天分享的主要內容。首先,我以亞馬遜為例,講述了它是如何做分散式服務架構的,遇到了哪些問題,以及是如何解決的。我認為,亞馬遜在分散式服務系統方面的這些實踐和經驗積累,是 AWS 出現的基因。隨後分享了在分散式系統中需要注意的幾個問題,同時給出了應對方案。

我認為,構建分散式服務需要從組織,到軟體工程,再到技術上的一次大的改造,需要比較長的時間來磨合和改進,並不斷地總結教訓和成功經驗。

專欄目錄

下面是《左耳聽風》的部分目錄,呈現你面前的每一篇文章,都是左耳朵耗子僅在小範圍分享的獨家經驗,20 年大規模系統架構和開發經驗總結:

本專欄自 2017 年 10 月更新以來,已有 6000+ 學員加入學習,更有專屬學員群 + 答疑時間,讓你和左耳朵耗子溝通交流。

用戶福利

即日起,

福利一:原價¥199/ 年,極客時間新用戶註冊立減¥30

福利二:每邀請一位好友購買,你可獲得 36 元現金返現,多邀多得,上不封頂,立即提現(提現流程:極客時間服務號 - 我的 - 現金獎勵提現)

如何訂閱

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 InfoQ 的精彩文章:

谷歌資深工程師辭職稱公司不再創新;Win 10將讓用戶跟蹤微軟收集的數據;Linus稱英特爾的補丁是垃圾
霍金:手握日月摘星辰,世間無我這般人

TAG:InfoQ |