餓了麼的架構設計及演進之路

餓了麼 編程語言 Python Java 51CTO傳媒 2017-05-05
餓了麼的架構設計及演進之路

作者:蘭建剛

編輯:齊琳 高陽

網站在剛開始的時候大概只是一個想法:一個產業的模型,快速地將它產生出來。“快”是第一位的,不需要花太多精力在架構設計上。

網站進入擴張期才需要對架構投入更多的精力來承載網站在爆發時的流量。餓了麼成立已經 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 臺機器上去。你只是看到了整個服務延時增加了,但有可能只是某一臺機器拖慢了整個服務集群。但是我們現在還做不到更多維度的監控。

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

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

IT技術群,期待你的加入

後臺回覆“入群”審核受邀

餓了麼的架構設計及演進之路

相關推薦

推薦中...