餓了麼:日訂單量超900萬的架構設計及演進之路

網站在剛開始的時候大概只是一個想法:一個產業的模型,快速地將它產生出來。「快」是第一位的,不須要花太多精力在架構設計上。在網站進入擴張期才須要對架構投入更多的精力來承載網站在爆發時的流量。程序員


餓了麼成立已經8年,如今日訂單量突破900萬,咱們也有了較爲完善的網站架構。數據庫


1、網站基礎架構安全


初期,咱們使用了可以更容易拓展SOA的框架。咱們用SOA的框架解決兩件事情:微信


1. 分工協做架構


網站初期,程序員可能就1~5個,那時你們忙同一個事情就能夠了。彼此之間的工做都互相瞭解,每每是經過「吼」的方式就把問題解決了。

負載均衡

但隨着人員的增長,這種方式顯然是不行的,不可能一我的更新了代碼再把其餘人的全部代碼從新上線一遍吧?因而就要考慮分工協做的問題。框架


2. 快速擴展編輯器



看一下咱們的現狀,中間是咱們整個架構的體系,右側是和服務化相關的一些基礎,包括基礎的組件或者服務。分佈式



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



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


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


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


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


2、服務拆分


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

把大Repo拆成一個小Repo,把大服務拆成小服務,把咱們的集中基礎服務,拆分到不一樣的物理機器上去。


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


這個過程當中,首先要對API作一個很好的定義。由於一旦你的API上線以後,再作一些修改的成本是至關大的。會有不少人依賴於你的API,不少時候你也並不知道有誰依賴於你的API,這是一個很大的問題。


而後再把一些基礎服務抽象出來。不少原來的服務實際上是耦合在原來的業務代碼裏面的。好比說支付業務,業務很單一時,緊耦合的代碼沒有關係,可是擴展出的愈來愈多的業務都須要支付服務時,你每個業務(好比說支付的功能)都要去作一個嗎?因此咱們要把這些基礎服務抽離出來,好比支付服務、短信服務、推送服務等。


拆服務看似很簡單、沒什麼價值,但這偏偏是咱們剛開始就要作的事情。其實在這個時期,前面全部的那些架構均可以日後拖,由於不作架構調整其實不會死人,可是拆服務你不作的話,真的會死人。


服務拆分一定是一個漫長的過程,可這實際是一個很痛苦的過程,也須要不少配套系統的系統工程。


3、發佈系統


發佈是最大的不穩定因素。不少公司對發佈的時間窗口有嚴格的限定,好比說:

  • 每週只有兩天能夠發佈;

  • 週末是絕對不能夠發佈的;

  • 業務的高峯期絕對不容許發佈;

  • 等等……


咱們發現,發佈的最大問題在於發佈上去以後沒有簡單可執行的回退操做。回退操做究竟是誰來執行,是發佈人員就能夠執行,仍是須要專人來執行?若是是發佈人員的話,發佈人員並不是24小時在線工做,出了問題找不到人怎麼辦?若是是有專人來執行回退,而又沒有簡單、統一的回退操做,那這我的須要熟悉發佈人員的代碼,這基本上不可行。


因此咱們就須要有發佈系統,發佈系統定義了統一的回退操做,全部服務必須遵循發佈系統的定義回退操做。


在餓了麼對接發佈系統是對全部人的強制要求,全部的系統必須所有接入發佈系統。發佈系統的框架很重要,這個東西其實對於公司是很重要的一件事情,須要放到第一優先級的隊列裏面去考慮。


4、服務框架


緊接着就是餓了麼的服務框架,把一個大的Repo拆分紅一個小的Repo,把一個大的服務拆成一個小的服務,讓咱們的服務儘可能獨立出去,這須要一套分佈式服務框架來支撐。


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


5、DAL數據訪問層


當業務量愈來愈大的時候,數據庫會變成一個瓶頸。


前期能夠經過提高硬件的方式來提高數據庫的性能。好比:

  • 升級到一個有更多CPU的機器;

  • 把硬盤改爲 SSD 的或者更高級一點的。


但硬件提高終歸是有一個容量限制的。並且不少作業務的小夥伴,寫代碼的時候都直接操做數據庫,發生過不少次服務一上線數據庫就被打爆的情形。數據庫被打爆掉了以後,除非等待數據庫恢復,沒有任何其它機會能夠恢復業務。


若是數據庫裏面數據是正常的,業務其實均可以補償出來。因此咱們作DAL服務層的時候,第一件事情是限流,其它的東西能夠放一放。而後作鏈接複用,咱們Python框架用的多進程單線程加協程的模型。


多進程之間實際上是不能夠共享一個鏈接的。好比:一臺機器上部署了10個 Python進程,每一個進程10個數據庫鏈接。再擴展到10臺機器上,就有1000個數據庫鏈接。對數據庫來講,鏈接是一個很昂貴的東西,咱們DAL層要作一個鏈接複用。


這個鏈接複用講的不是服務自己的鏈接複用,而是說DAL層上的鏈接複用,就是服務有1000個鏈接到DAL層,通過鏈接複用後對數據庫可能只是保持着十幾個鏈接。一旦發現某個數據庫請求是一個事務的話,那麼DAL就幫你保留這個鏈接的對應關係。當這個事務結束以後,就把數據庫的鏈接,放回到共用池裏面去,供其餘人使用。


而後作冒煙和熔斷。數據庫也能夠熔斷的。當數據庫發生冒煙時,咱們會殺掉一些數據庫的請求,保證數據庫不至於崩潰。


6、服務治理


服務框架以後,涉及服務治理的問題。服務治理實際上是一個很大的概念。首先是埋點,你要埋不少的監控點。


好比有一個請求,請求成功了或者失敗了,請求的響應時間是多少,把全部的監控指標放到監控系統上面去。咱們有一個很大的監控屏幕,上面有不少的監控指標。有專門小組72小時去盯着這個屏幕,若是有任何曲線波動了,就找人去解決。另外是報警系統,一個監控屏幕展現的東西老是有限的,只能放那些很重要的關鍵指標。這個時候就須要有報警系統。


羅馬不是一天建成的,基礎架構更是一個演進的過程。咱們的資源和時間老是有限的,做爲架構師和 CTO 來講,如何在這種有限的資源下,產出更重要的東西?


咱們作了不少系統,以爲本身作得很不錯了,但實則不是,我感受咱們又回到了石器時代,由於問題愈來愈多,需求也愈來愈多,總感受你的系統裏還缺點什麼東西,想作的功能也一大堆。




這些問題涉及咱們作事的一個原則:東西夠用就好,可是要可以未雨綢繆,作必定的超前規劃。

Java高級架構 乾貨|交流
長按,識別二維碼,加關注
轉載是一種動力 分享是一種美德

本文分享自微信公衆號 - JAVA高級架構(gaojijiagou)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索