微服務是傳統企業電商解決方案的銀彈嗎?

Java高階開發發表於2018-05-07

近幾年,微服務成為最流行的技術名詞之一,尤其受到亞馬遜、阿里等電商巨頭的影響,很多傳統企業在實施電商過程中也紛紛往微服務架構靠攏,相比單體架構,微服務確實有很多優點,就像 Sam Newman 在“Building Microservices”[1] 中所闡述的那樣:

  • 技術異構性
  • 彈性
  • 伸縮性
  • 容易部署

但是電腦科學作為一門平衡的科學,任何技術架構在帶來收益的同時也會有其侷限性,作為系統架構師或者決策人員,一定要對此有清醒的認識。本文將重點闡述成功實施微服務的先決條件,所面臨的主要挑戰和風險,傳統企業在實施電商過程中的決策要素以及正確的實施策略。BTW,作者本人對微服務沒有任何成見,我在 amazon 工作期間一直接觸的就是微服務架構,而且本人也是 Adrian Cockcroft 的超級粉絲。所以各位微服務控們千萬不要拍磚。

成功實施微服務的先決條件

一般而言,成功實施微服務的先決條件包括:

  • 匹配的組織架構
  • 實力雄厚的技術團隊(包括開發 / 測試 / 運維)
  • 清晰的業務邊界

其中第一條換個洋氣點的說法就是康維定律(Conway’s Law[2]),這是我最喜歡的定律之一,現實中接觸到的各個案例無一例外:

“organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”

康維定律簡單來說,就是任何軟體都反映出製造它的團隊的組織結構,這是因為人們會以反映他們組織形式的方式工作。 換句話說,採用微服務架構的組織結構也應該是分散的。看看現實中成功實施微服務的那些公司:Amazon、Netflix、阿里那個不是分散的組織結構。

至於後面兩條的原因我將在下面一節深入探討。

挑戰和風險

更長的學習曲線

主要包括:

除了需要了解業務邏輯外,也需要花大量精力去學習底層微服務框架提供的各種服務並遵從其契約,以下圖為例,為了實施一個基於微服務架構的電商,技術團隊需要掌握以下:

業務邏輯及其之間的介面

基於容器的部署和工具,比如 Docker、Kubernetes 等

微服務框架本身的學習,包括 API 閘道器、服務發現和序號產生器制、熔斷、分散式配置等等

甚至背後的理論 / 設計模式,諸如 CAP、BASE 等等
這裡寫圖片描述

更多的開發 / 測試工作

例如:

因為常見微服務架構都是每個服務擁有自己的資料庫,導致需要跨表實現統計報表等功能將變得很複雜

對於哪些需要依賴其他微服務的微服務開發及測試,你不得不在本地也安裝所有需要依賴的微服務,即使採用 Docker 容器,根本問題並沒有改變,與單體服務的開發相比較而言,開發測試變得很繁瑣

程式碼本身也要遵從微服務框架的各種契約,例如一個使用 Hystrix 熔斷機制的程式碼如下:

@Service

public  class  MyService {

@Autowired

RestTemplate restTemplate;

@HystrixCommand(fallbackMethod = "errorHandler")

public String myService(String name) {

return restTemplate.getForObject("http://MYSERVICE/myservie?name="+name,String.class);

}

public String errorHandler(String name) {

return  "There is an error for service "+name;

}

}

重構的代價

由於各種原因(特別是在對業務的理解不夠或者業務變動頻繁的情況下),已經上線的微服務發現並不合適從而需要重構,例如需要把計價服務重新合併回產品服務,至少遵循以下步驟(請參考下圖):
這裡寫圖片描述

首先在產品資料庫中建立與計價有關的表,建立匯入工具吧計價資料庫中的資料匯入到產品資料庫中,需要注意的是,如果產品服務和計價服務採用不同的資料庫,還需要額外的開發成本編寫匯入工具。在本步驟完成後,產品服務並不提供任何計價功能,只是所有計價服務中的資料會被不斷(同步或非同步)匯入到產品資料庫中。

在產品服務中引入計價功能並暴露相應介面,在充分測試後配置 API 閘道器(如 Zuul 或者 Istio)對計價功能呼叫進行分流,期間所有流入老的計價資料庫的資料依然會被匯入到產品資料庫中。

經過一段時間的金絲雀釋出後,最終所有的計價功能呼叫都進入產品 / 計價服務,老的計價服務和相應的資料庫被解除安裝。

當然這是在非常理想的情況下,現實情況比這個複雜的多,例如部分需要合併部分需要拆分,採用不同的程式語言,採用不同的資料庫技術,其它微服務對相關微服務的依賴等等。另外典型的微服務架構中不同的微服務由不同的組 / 部門去維護,相關的溝通協作也是一個不容忽視的成本,所以在業務不穩定或者理解不充分的情況下貿然實施微服務的代價是非常巨大的!

更嚴謹的設計

微服務架構比單體服務更容易發生問題,不但是因為分散式計算本身複雜性帶來的各種問題(如一致性問題),而且各種流行的微服務框架都有這樣那樣的坑,以電商業務為例,使用者 1 需要上架一批新產品,為了提高併發性以及降低服務之間的耦合度,當前的微服務架構採用訊息匯流排去通知計價服務 / 倉庫服務 / 產品服務進行相應處理,不幸的是,由於訊息的非同步性,很可能對於某個產品而言,產品服務最後被通知到,期間如果使用者 2 查詢到了對應的庫存但卻發現相關的產品不存在(如下圖所示),這顯然違反了因果一致性(casual consistency)!
這裡寫圖片描述

糾錯的難度

想象一下訂單服務的實現需要呼叫倉庫服務,計價服務,支付服務等多個服務,中間任何一個環節出錯都將導致訂單處理失敗,有時為了提高處理的併發量,往往採用基於訊息匯流排的非同步方式,這樣想做到快速定位到錯誤根源對開發人員是一個不小的挑戰,一般而言,我們不得不從兩個方面入手:

應用級別的關聯,所有非同步呼叫都必須引入訊息標識關聯

藉助於微服務框架的分散式追蹤機制,日誌聚合等功能(如 zipkin,CloudWatch 等)

即便這樣,出錯除錯的困難度和需要的時間也和單體服務不是一個量級的,而且大部分情況下,在單體服務中很容易重現並在本地通過單步跟蹤快速解決的問題,對於微服務而言就變得不那麼容易了。

依賴自動化的部署能力

在很多介紹微服務架構優點的文章中,常見的一條就是“易於部署”,實際上之所以“易於部署”,是拿單個“微服務“和單體服務相比較而言的,但是部署構成企業業務的幾十個甚至上百個微服務的總體複雜度絕對比單體服務大的多,這就是為什麼所有基於微服務架構的應用都必須依賴自動化的部署能力,這對體術團隊提出了兩方面要求:

掌握自動化運維工具(如 Ansible)和相關的設計模式 (如伺服器提供模式、伺服器模版管理模式、基礎架構定義模式等 [3])

微服務本身是快速部署匹配的,如果不是則需要進行重構 [4]。

業務方面的思考

從業務角度我們必須思考以下這些問題:

  • 你的業務體量到底有多大,會不會成長為類似於 / 接近於 Amazon/Netflix/Google/ 阿里 /
    騰訊這些巨頭體量的下一個巨頭?

  • 如果會,那麼多長時間,幾年還是幾十年?

  • 實施電商後的產品升級 / 運維 / 擴充套件誰來做,能否提供足夠的技術實力來應付微服務框架中的各種潛在風險

  • 對業務的理解是否非常深刻,還是隻停留在初級階段?

  • 公司組織結構是否有利於實施微服務架構?

  • 是否有其他更為簡單的解決方案

總之,作為系統架構師或者決策人員,我們要做的就是透過“絢麗包裝”的外表理解各種技術架構的本質從而避免過度設計給企業帶來巨大的風險,在這點上 Jeff Dean 在其穩重“challenges in building large-scale information retrieval systems”中的經典名言值得我們借鑑 [5]:

Design for ~10*growth, plan to rewrite before ~100*

演進路線

Martin Fowler 在其“MonolithFirst”一文 [5] 中明確指出:

幾乎所有成功的微服務案例全部來源於業務足夠複雜的單體服務

幾乎所有不成功的微服務案例都是直接從頭開發

實際上作為傳統行業實施電商一個穩妥的方案是從單體開始,隨著業務變得越來越複雜逐步慢慢演進到微服務,具體來說:
這裡寫圖片描述

單體服務的實施中需要採用良好的程式設計習慣,使得整個系統模組化而且業務邊界清晰,如果一開始對業務不太熟悉,這需要不斷的重構。

單體服務本身應該儘量遵循雲部署的那些基本原則,諸如無狀態、通過環境變數注入配置資訊等 [4]。

在電商業務變得足夠複雜的情況下,逐步對有關服務進行拆分,需要注意的是此處只是邏輯上的拆分

加強對自動化運維能力的建設。

最終隨著企業組織結構的逐步調整過渡到微服務架構。

結論

微服務的出現給傳統企業實施電商業提供了強大 / 靈活 / 敏捷的框架,但同時也對無論技術還是業務上都提出了更高 / 更嚴格的要求,不重視這些潛在風險將帶來巨大風險,所以微服務不是企業電商解決方案的銀彈,通常只有採取更為務實嚴謹的演進路線才能實現我們的目標。

我大概在 2006 年開始參與架構設計,原以為學習架構就像學習程式語言一樣,先了解基本的語法,再研究細節和原理,然後實踐一下就能夠快速掌握。 但真正深入後才發現,架構設計的難度和複雜度要高很多。

從最早開始接觸架構設計,到自我感覺徹底掌握架構設計的精髓,我至少花費了 8 年的時間。 我曾經以為是自己天資愚笨才會這樣,後來我帶了團隊,看到幾乎每個程式設計師在嘗試架構設計的時候,都面臨著我曾經遇到過的各種困惑和瓶頸。

今天,我想把我過去所有的經驗都分享在群697579751裡,裡面都是我精心錄製成視訊供大家免費下載,希望能幫你快速成為一名架構師。
這裡寫圖片描述

參考資料

Building Microservices: Designing Fine-Grained Systems, Publisher:
O’Reilly Media; 1 edition (February 20, 2015)

https://en.wikipedia.org/wiki/Conway%27s_law

Infrastructure as Code: Managing Servers in the Cloud, Publisher:
O’Reilly Media; 1 edition (June 27, 2016)

https://12factor.net

https://static.googleusercontent.com/media/research.google.com/en//people/jeff/WSDM09-keynote.pdf

https://martinfowler.com/bliki/MonolithFirst.html

歡迎關注我的公眾號:Java高階架構,分享技術乾貨

這裡寫圖片描述

相關文章