首頁  >  文章  >  系統教程  >  餓了麼的架構演進與設計探索

餓了麼的架構演進與設計探索

WBOY
WBOY轉載
2024-01-03 09:12:251369瀏覽
導讀 一個產業的模型,快速地將它產生出來。 「快」是第一位的,不需要花太多精力在架構設計上。在網站進入擴張期才需要對架構投入更多的精力來承載網站在爆發時的流量。餓了麼成立已經8年,現在日訂單量突破900萬,我們也有了較完善的網站架構。
一、網站基礎架構

初期,我們使用了能夠更容易拓展SOA的框架。我們用SOA的框架解決兩件事:

1.分工協作

#網站初期,程式設計師可能就1~5個,那時大家忙同一個事情就可以了。彼此之間的工作都互相了解,往往是透過「吼」的方式就把問題解決了。

但隨著人員的增加,這種方式顯然是不行的,不可能一個人更新了程式碼再把其他人的所有程式碼重新上線一遍吧?於是就要考慮分工協作的問題。

2.快速擴充

#以前訂單量可能從1k到1w,雖然增加了10倍,但是總量並不是很高,對於一個網站的壓力來說,也不是那麼大。真正到了訂單量從10w到100w,從100w到 200w的時候,可能數字上只是擴大了10倍,但對整個網站的架構上來說卻是一個巨大的挑戰。

我們的背景就是2014年的100萬突破到現在的900萬,技術團隊由剛開始的30多個人,到現在已經是超過900人的團隊。這時候分工協作是個巨大的挑戰。服務的分分合合,團隊的分分合合,這都需要一套框架體系來支撐,這也是SOA框架的一個功能。

看一下我們的現狀,中間是我們整個架構的體系,右邊是和服務化相關的一些基礎,包括基礎的元件或服務。

先說語言,我們原本的網站是在PHP上的,後來慢慢轉型。

創辦人都是大學生創業,那麼理所當然Python是個很好的首選。到現在 Python也是很好的選擇,但我們為什麼要擴展到Java和Go呢?

Python很多人都會寫,但真正能把它做得很好的人並不多。隨著業務的發展,需要更多的開發人員。考慮到Java成熟的生態環境,以及新興的Go生態,我們最終選擇了Python、Java、Go多語言共存的一個生態。

WebAPI主要做一些HTTPS卸載、限流,還有安全校驗等一些通用的和業務邏輯無關的操作。

Service Orchestrator是服務編排層,透過配置的方式實現內外網路的協定轉換、服務的聚合裁剪。

架構圖右邊是一些圍繞這些服務化框架的輔助系統,比如說用來定期執行一個任務的Job系統。我們有將近快1000個服務,這些系統怎麼監控?所以必須有一套監控系統。剛開始只有30多個人時,我們更擅長的是跑到機器上去搜一下Log,但到了900多人時,你不可能都到機器上去搜一遍Log,需要有個集中式的日誌系統。其它的系統這裡就不一一贅述了。

羅馬不是一天造成的,基礎架構是個演進的過程。我們精力有限,那先做什麼?

二、服務拆分

當網站變大了,原本的架構跟不上發展的節奏了。我們要做的第一件事情就是:

把大Repo拆成一個小Repo,把大服務拆成小服務,把我們的集中基礎服務,拆分到不同的實體機器上去。

光是服務拆分花了一年多的時間才做完,這是一個比較漫長的過程。

這個過程中,首先要對API做一個很好的定義。因為一旦你的API上線之後,再做一些修改的成本是相當大的。會有很多人依賴你的API,很多時候你也不知道有誰依賴你的API,這是一個很大的問題。

然後再把一些基礎服務抽像出來。很多原來的服務其實是耦合在原來的業務代碼裡面的。比如說支付業務,業務很單一時,緊密耦合的程式碼沒有關係,但是擴展出的越來越多的業務都需要支付服務時,你每一個業務(比如說支付的功能)都要去做一個嗎?所以我們要把這些基礎服務抽離出來,像是支付服務、簡訊服務、推播服務等。

拆服務看似很簡單、沒什麼價值,但這正是我們剛開始就要做的事情。其實在這個時期,前面所有的那些架構都可以往後拖,因為不做架構調整其實不會死人,但是拆服務你不做的話,真的會死人。

服務拆分必定是一個漫長的過程,但這實際上是一個很痛苦的過程,也需要很多配套系統的系統工程。

三、發布系統

發布是最大的不穩定因素。很多公司對發布的時間窗口有嚴格的限定,比如說:

  • 每週只有兩天可以發布;
  • 週末是絕對不可以發布的;
  • 業務的高峰期絕對不允許發布;
  • 等等……

我們發現,發布的最大問題在於發布上去之後沒有簡單可執行的回退操作。回退操作到底是誰來執行,是發佈人員就可以執行,還是需要專人來執行?如果是發佈人員的話,發佈人員並非24小時在線上工作,出了問題找不到人怎麼辦?如果是有專人來執行回退,但又沒有簡單、統一的回退操作,那這個人需要熟悉發佈人員的程式碼,這基本上不可行。

所以我們需要有發布系統,發布系統定義了統一的回退操作,所有服務必須遵循發布系統的定義回退操作。

在餓了麼對接發布系統是對所有人的強制要求,所有的系統必須全部存取發布系統。發布系統的框架很重要,這個東西其實對公司來說是很重要的一件事情,需要放到第一優先順序的隊列裡面去考慮。

四、服務框架

緊接著就是餓了麼的服務框架,把一個大的Repo拆分成一個小的Repo,把一個大的服務拆成一個小的服務,讓我們的服務盡量獨立出去,這需要一套分散式服務框架來支撐。

分散式服務框架包含的服務註冊、發現、負載平衡、路由、流控、熔斷、降級等功能,這裡就不一一展開了。前面已經提及,餓了麼是多語言的生態,有 Python的,也有Java的,我們的服務化框架對應也是多語言的。這對我們後來一些中間件的選型是有影響的,比如說DAL層。

五、DAL資料存取層

當業務量越來越大的時候,資料庫會變成一個瓶頸。

前期可以透過提升硬體的方式來提升資料庫的效能。如:

  • 升級到一個有更多CPU的機器;
  • 把硬碟改成 SSD 的或更高級一點的。

但硬體提升終歸是有一個容量限制的。而且很多做業務的朋友,寫程式碼的時候都直接操作資料庫,發生過很多次服務一上線資料庫就被打爆的情形。資料庫被打爆掉了之後,除非等待資料庫恢復,沒有任何其它機會可以恢復業務。

如果資料庫裡面資料是正常的,業務其實都可以補償出來。所以我們做DAL服務層的時候,第一件事就是限流,其它的東西可以放一放。然後做連接復用,我們Python框架用的多進程單執行緒加協程的模型。

多進程之間其實是不可以共享一個連線的。例如:一台機器上部署了10個 Python進程,每個進程10個資料庫連線。再擴展到10台機器上,就有1000個資料庫連接。對資料庫來說,連線是一個很昂貴的東西,我們DAL層要做一個連線重複使用。

這個連接復用講的不是服務本身的連接復用,而是說DAL層上的連接復用,就是服務有1000個連接到DAL層,經過連接復用後對數據庫可能只是保持著十幾個連接。一旦發現某個資料庫請求是一個交易的話,那麼DAL就幫你保留這個連接的對應關係。當這個事務結束之後,就把資料庫的連接,放回共用池裡面去,供其他人使用。

然後做冒煙和熔斷。資料庫也可以熔斷的。當資料庫發生冒煙時,我們會殺死一些資料庫的請求,保證資料庫不會崩潰。

六、服務治理

服務架構之後,涉及服務治理的問題。服務治理其實是一個很大的概念。首先是埋點,你要埋很多的監控點。

例如有一個請求,請求成功了或失敗了,請求的回應時間是多少,把所有的監控指標放到監控系統上面去。我們有一個很大的監視器螢幕,上面有很多的監控指標。有專門小組72小時去盯著這個螢幕,如果有任何曲線波動了,就找人去解決。另外是警報系統,一個監控螢幕展示的東西總是有限的,只能放那些很重要的關鍵指標。這時候就需要有警報系統。

羅馬不是一天造成的,基礎架構更是演進的過程。我們的資源和時間總是有限的,身為架構師和 CTO 來說,如何在這種有限的資源下,產出更重要的東西?

我們做了很多系統,覺得自己做得很不錯了,但實則不是,我感覺我們又回到了石器時代,因為問題越來越多,需求也越來越多,總感覺你的系統裡還缺點什麼東西,想做的功能也一大堆。

例如對於流控系統,現在我們還是需要使用者去配一個並發數,那麼這個並發數,是不是根本不需要用戶去配?是不是可以基於我們服務本身的一個狀態自動去控制並發數?

然後是升級方式,SDK升級是個很痛苦的事情。比如說我們服務框架2.0發佈的時候是去年12月份,到現在還有人用的是1.0。是不是可以做到SDK的無損感升級,我們自己來控制升級的時間和節奏。

還有,我們現在的監控只支援同一個服務上的匯聚,是不分群集、不分機器的,那是不是以後的指標可以分群集、分機器?舉一個最簡單的例子,例如一個服務上有10台機器,那麼可能只是某一個機器上出了問題,但它所有的指標都會平均分攤到其它的9台機器上去。你只是看到了整個服務延遲增加了,但有可能只是某台機器拖慢了整個服務集群。但我們現在還做不到更多維度的監控。

還有智慧化的報警,這個報警,就是要快、全、準,我們現在做到更快了,做到更全了,怎麼才能做到更準?每天的警報量高峰時間一分鐘一千多個報警發出去。所有的一千報警都是有用的嗎?報警多了之後,就等於沒有報警。大家都疲勞了,就不去看了。我怎麼能夠把這個報警更準確地區分出來?還有更智慧化的連結分析?以後是不是我們的監控不要放監控指標,而是放鏈路分析,這樣就能夠很清楚地知道,這個問題對應的是哪一個結點上出了問題。

這些問題涉及我們做事的一個原則:東西夠用就好,但是要能夠未雨綢繆,做一定的超前規劃。

以上是餓了麼的架構演進與設計探索的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:linuxprobe.com。如有侵權,請聯絡admin@php.cn刪除