1. 程式人生 > >微服務架構的兩大解耦利器與最佳實踐

微服務架構的兩大解耦利器與最佳實踐

架構 微服務 沈劍

這幾年,微服務架構這個術語漸成熱門詞匯,但它不是一個全新架構,更不是一個包治百病的架構。那麽,微服務架構究竟能夠解決什麽問題,又帶來哪些痛點?

本文將與大家談談這個問題,以及微服務架構的兩大解耦利器配置中心和消息總線的最佳實踐。

微服務架構解決的問題與帶來的痛點


互聯網高可用架構為什麽要服務化?


技術分享

上圖是互聯網典型的高可用架構,大部分公司如果沒有使用微服務,正在使用這樣的架構:

  • 用戶端是瀏覽器 browser,APP 客戶端

  • 後端入口是高可用的 nginx 集群,用於做反向代理

  • 中間核心是高可用的 web-server 集群,研發工程師主要在這一層進行編碼工作

  • 後端存儲是高可用的 db 集群,數據存儲在這一層。更典型的公司,web-server 層是通過 DAO/ORM 等技術來訪問數據庫。

最初的架構都沒有服務層,這樣的架構會遇到怎樣的痛點?對於沒有使用微服務架構的公司來說,要不要升級到微服務架構呢?

58 同城和 58 到家的架構痛點

回答這個問題之前,先來看看您是否遇到和 58 同城及 58 到家類似的架構痛點:

技術分享

圖一,代碼拷貝。A、B、C 業務線,如果沒有微服務架構,可能要直接訪問數據庫裏的數據來實現自己的業務需求。拿訪問用戶數據舉例,用戶中心包括所有公司必備的業務,比如登陸、註冊、查找用戶信息等。如某業務線需要訪問用戶信息,需要通過封裝用戶訪問代碼模塊實現。如業務繁多,每個業務線都需要訪問用戶信息,潛在的會存在代碼拷貝問題。

圖二,底層復雜性擴散。隨著流量的增長,需要加入緩存,對數據的訪問模式和流程都會帶來影響。從直接訪問數據庫,變到先訪問緩存再訪問數據庫。這樣的復雜性,所有的業務都需關註,代碼都要重新做一遍。包括數據量增大後,要進行的水平線切分、分庫、分表,存儲引擎的變化等復雜性,要擴展到業務線。

圖三,代碼庫耦合。58 同城遇到圖一和圖二問題,最初想到的方案並不是微服務,而是將相互拷貝的復雜性代碼封裝到一個代碼庫(DLL 或 jar 包),實現統一的相關功能,屏蔽復雜性。

拷貝代碼的好處是代碼獨立演化,做改動互不影響。弊端是一旦用上庫,業務就會耦合在一起,因共用jar包,一旦其中某個業務升級,其他的業務就可能受影響。

圖四,數據庫耦合。業務線不只訪問 user 數據,還會結合自己的業務訪問自己的數據:典型的情況是通過 join 數據表來實現各自業務線的一些業務邏輯。這樣的話:

  • 業務線 A 的 table-user 與 table-A 耦合在了一起;

  • 業務線 B 的 table-user 與 table-B 耦合在了一起;

  • 業務線 C 的 table-user 與 table-C 耦合在了一起;

結果就是:table-user,table-A,table-B,table-C都耦合在了一起。隨著數據量的越來越大,業務線 ABC 數據庫無法進行垂直拆分,必須使用一個大庫(瘋了,一個大庫 300 多個業務表 =_=)。

圖五,SQL 質量得不到保證,業務之間互相影響。由業務方拼裝的 SQL 語句調用方式,通過 ORM(對象關系映射)的方法生成 SQL 語句數據庫,這個庫是共用的,會影響所有的業務線。一旦某業務有慢 SQL 出現,其他業務就會受影響。

回到要不要做微服務升級的問題,如果大家所負責的系統、模塊或公司也存在以上的這些問題,建議考慮做服務化,在中間加一個服務層,所有調用不允許直接連接底層庫。服務化還有一個很重要的特點就是數據庫私有化,任何人不能跨越服務程序,幹預數據庫。想調用要通過接口來實現,當數據庫性能變差,直接加一臺機器,把數據庫遷移,對調用方不會產生影響。


服務化解決了哪些問題


在 58 同城,用戶中心由專門的部門負責,是全公司、全業務依賴比較重的服務,它對代碼要求和穩定性要求比較高。整個 SQL 語句是服務層控制,向上提供有限的服務接口和無限的性能

工程師要保障雖然提供用戶基礎數據的接口數是有限的,但調用方不需要關心底層細節,可以認為性能是無限的。至於如何擴容,就是服務層的事情了。

下圖是互聯網典型的服務化架構。以用戶中心為例,用戶中心服務向上屏蔽底層技術的復雜性,上層通過 RPC 接口來調用服務,如同調用本地函數一樣,不需要關註分庫、分表、緩存。

技術分享

業務方需要數據,把數據拼裝出來返回 APP/PC 端即可,可以不關心數據存在哪裏,底層的復雜性也由用戶層來承擔。這樣一來,用戶庫只有用戶服務依賴,任何人不得跨越用戶服務來直接調用數據庫,就不會存在代碼拷貝、代碼庫、數據庫耦合的情況。

微服務架構的兩大解耦利器

微服務雖然看上去很好,但也給系統帶來很多問題,如部署方面,越來越復雜,分層越來越多,處理時間也隨之增加。如網絡交互方面,運維負載性、追查問題等等。那麽:

  • 面對架構的耦合及復雜性如何來優化

  • 結構如何配置

接下來,我們介紹配置中心最佳實踐與消息總線最佳實踐這兩大解耦利器


微服務架構解耦利器-配置中心最佳實踐


放棄 IP 連接服務,選擇內網域名。58 到家是創業公司,痛點和很多公司都很相似。其中一個場景是 IP 的變化。最初,IP 寫在配置文件中,通過某個 IP 或端口訪問數據與服務。當某臺機器出現問題,DB 同事會在新機器做部署,更換 IP。當某個服務或 IP 發生變化,就在配置文件中修改,重啟。

這裏的經驗分享是千萬不要用 IP 連接服務或數據庫,要選擇內網域名。這兩者的區別在於:

  • 使用 IP 連接服務或數據庫的方式,所有的庫都和一個表有關聯,一旦機器掛掉或升高配,幾乎所有的業務都需要修改 IP。即便只是升級一個業務,都會嚴重影響其他業務。

  • 選擇內網域名的方式後,如果換 IP,在運維層面可以進行統一切斷,自動向上鏈接,上遊的業務就不用動,也不受下層變動的影響。

配置私藏。如下圖是 58 到家早期改成內網域名之後的配置文件。底層用戶服務或數據庫,是個高可用集群,從 IP1 到 IP3。上遊有三個依賴,兩個服務器,一個 Web 調用這個高可用集群。Web 包含 WBE2.conf,調用 IP1,IP2,IP3。

技術分享

在實踐過程中,這種配置私藏的方式遇到兩個痛點:

技術分享

  1. 升級時不知道被那個服務調用。當遇到流量越來越大,需要添加服務器時,如上圖,把 IP1 去掉,增加 IP4 和 IP5 的時候,需要通知上遊。但問題在於流量不大時,因為對業務非常熟悉,工程師能夠準確的找到服務器對應的負責人。隨著業務越來越復雜,工程師遇到出現了問題,不知道模塊被誰依賴的情況。

  2. 升級時需要上遊配合重啟。當增加 IP 時,需要找到對應的上遊服務器負責人,通知他進行服務器重啟。公司成百上千的服務每天都有人在升級,當時的做法是采用建群,隨時做通知,但這樣很影響研發同事寫代碼的效率。

全局配置。最開始底層的通用基礎服務,配置是寫在每個站點;而且每個應用私藏在配置文件裏,在升級過程中,不知道誰私藏了這個配置。

面對這兩個痛點,58到家采用了下圖的解決方案:全局配置

技術分享

全局配置也就是升級,只需要做流程與規範上的優化,對原有系統架構不產生任何影響,成本低且可平滑的慢慢遷移。

下圖的實現原理是把最初放在每個服務器中的配置文件,抽取一個全局配置文件,做好目錄結構 global.conf。所有基礎服務配置如果由多個 global.conf 上遊來讀取,必須通過 global.conf 來讀取。這樣所有的業務都在 global.conf,就可以保障下一次升級可連接到最新。

技術分享

那麽,在做擴容的時候,能不能實現調用方不需要升級呢?當然可以,兩個小組件就可以實現:

  • 監控全局文件的變化情況,發生變化就進行回調,這樣用戶中心要配置修改的是全局配置。

  • 動態鏈接池組件。這是一個自身及調整流程成本都很低的組件,負載均衡也會在其中實現。

配置中心。全局配置對於服務提供方而言,問題依然沒有全部解決,擴容不需要重啟,卻仍不知道被誰依賴,不知道被誰訪問,就沒辦法做服務治理、限流等操作。這時,工程師就要引入配置中心,來解決這個問題。

技術分享

配置中心思路是部署用戶中心承載所有配置,取代所有全局配置文件。這樣一來,所有都依賴配置中心上遊,服務1,服務2,服務3,都不再訪問global.conf,而是通過配置中心來拉取相關配置,配置變更,配置中心反向回調,調用方也不要重啟。

技術分享

配置中心最佳實踐總結。配置中心是微服務架構中一個邏輯解耦但物理不解耦的利器。它原來在邏輯上依賴於自己的配置文件,依賴於下遊,現在不再向配置文件索要配置,而是所有調用方邏輯上只依賴於配置中心。物理上不解耦,是從配置文件拿到配置以後該連誰還是連誰。


微服務架構解耦利器-消息總線最佳實踐


消息總線(Message Queue),後文稱 MQ,是一種跨進程的通信機制,用於上下遊傳遞消息。它也是微服務架構中很常見的解耦利器之一,在數據驅動的任務依賴、調用方不關註處理結果、關註結果的長時間調回等場景下使用。

數據驅動的任務依賴。大部分公司都有 BI、數據部門,每天都會跑一些日誌、數據庫,多個任務之間往往存在依賴關系,任務1先執行,依次是任務 2、任務 3 輸入,最終得到結果。在沒有消息總線之前,大多公司和58到家的做法雷同,就是人工排班表。

技術分享

人工排班表的弊端如下

  1. 原本執行時間是40分鐘,但為保險,每個人都會多加時間,導致任務總執行時間延長。

  2. 萬一某一任務的執行時間超過預留時間,接下來的任務不知情,會導致整個業務失敗。

  3. 多個業務之間可能有多重依賴,特別是在數據統計、數據分析過程中,一些核心腳本執行完,後面一系列腳本才能執行。

如下圖,這種數據驅動的任務依賴非常適合使用MQ解耦。

技術分享

  • task1準時開始,結束後發一個“task1 done”的消息

  • task2訂閱“task1 done”的消息,收到消息後第一時間啟動執行,結束後發一個“task2 done”的消息

  • task3同理

采用 MQ 的優點是:

  • 不需要預留 buffer,上遊任務執行完,下遊任務總會在第一時間被執行

  • 依賴多個任務,被多個任務依賴都很好處理,只需要訂閱相關消息即可

  • 有任務執行時間變化,下遊任務都不需要調整執行時間

需要特別說明的是,MQ 只用來傳遞上遊任務執行完成的消息,並不用於傳遞真正的輸入輸出數據。

調用方不關註處理結果,這樣的情況也適合消息總線來做解耦。舉例,58 同城的很多下遊需要關註“用戶發布帖子”這個事件,比如招聘用戶發布帖子後,招聘業務要獎勵 58 豆;房產用戶發布帖子後,房產業務要送 2 個置頂;二手用戶發布帖子後,二手業務要修改用戶統計數據。

對於這類需求,常見的實現方式是使用調用關系:帖子發布服務執行完成之後,調用下遊招聘業務、房產業務、二手業務,來完成消息的通知,但事實上,這個通知是否正常、正確的執行,帖子發布服務根本不關註。

這種方法的痛點是:

  • 帖子發布流程的執行時間增加了

  • 下遊服務宕機,可能導致帖子發布服務受影響,上下遊邏輯+物理依賴嚴重

  • 每當增加一個需要知道“帖子發布成功”信息的下遊,修改代碼的是帖子發布服務,這一點是最惡心的,屬於架構設計中典型的依賴倒轉,誰用過誰痛誰知道(采用此法的請評論留言)

采用下圖的優化方案:MQ解耦

  • 帖子發布成功後,向MQ發一個消息

  • 哪個下遊關註“帖子發布成功”的消息,主動去MQ訂閱

技術分享

采用 MQ 的優點是:

  • 上遊執行時間短

  • 上下遊邏輯+物理解耦,除了與 MQ 有物理連接,模塊之間都不相互依賴

  • 新增一個下遊消息關註方,上遊不需要修改任何代碼

上遊關註執行結果,但執行時間很長。有時候上遊需要關註執行結果,但執行結果時間很長(典型的是調用離線處理,或者跨公網調用),也經常使用回調網關+MQ來解耦。

舉例:微信支付,跨公網調用微信的接口,執行時間會比較長,但調用方又非常關註執行結果,此時一般怎麽玩呢?

技術分享

一般采用“回調網關+MQ”方案來解耦,新增任何對微信支付的調用,都不需要修改代碼。

  • 調用方直接跨公網調用微信接口

  • 微信返回調用成功,此時並不代表返回成功

  • 微信執行完成後,回調統一網關

  • 網關將返回結果通知 MQ

  • 請求方收到結果通知

這裏需要註意的是,不應該由回調網關來調用上遊來通知結果,如果是這樣的話,每次新增調用方,回調網關都需要修改代碼,仍然會反向依賴,使用回調網關+ MQ 的方案。

綜上所述,兩個解耦利器的最佳實踐場景如下:

  • 配置中心是邏輯解耦,物理不解耦的微服務的利器。它可以解決配置導致的系統耦合,架構反向依賴的問題,配置中心的演進過程,配置私藏到全局配置文件,到配置中心。

  • 消息總線是邏輯上解耦,物理上也解耦的微服務架構利器。它非常適合數據驅動的任務依賴,調用方不關註處理結果,或者調用方關註處理結果,但是回調的時間很長的場景。不適合調用方強烈關註執行結果的場景。

以上內容根據沈劍老師在 WOTA2017 “微服務架構實踐”專場的演講內容整理。


技術分享

沈劍,現任58到家技術委員會主席,高級技術總監,負責企業、支付、營銷和客戶關系等多個後端業務部門。本質,技術人一枚。互聯網架構技術專家,“架構師之路”公眾號作者。曾任百度高級工程師,58同城高級架構師,58同城技術委員會主席,58同城C2C技術部負責人。技術分享


本文出自 “12562290” 博客,請務必保留此出處http://12572290.blog.51cto.com/12562290/1948156

微服務架構的兩大解耦利器與最佳實踐