簡單聊聊SOA和微服務

Alchemist發表於2017-06-01

簡單聊聊SOA和微服務
架構設計中的樸素主義

前兩天和一個朋友聊天,他向我諮詢如何從零開始構建一個健壯、強大的軟體系統,聊著聊著他忽然問我,「聽大家都在說微服務(下文中有的地方會使用MSA),還有人會提到SOA,那麼他們的區別到底在哪裡?」。我想了想,一時也列不出來一個詳細的列表,只能跟他講說其實他們在概念上是相似的。

關於軟體系統的架構設計,是一個太多人喜歡討論的問題,尤其是對軟體開發不瞭解的人士來說,總是被各種各樣的概念繞來繞去。從更高的層次,更大的視野研究架構設計的一些專家(如Martin Fowler、Chris Richardson)能夠很清晰的列出這些眾多概念的區別,而身在開發一線的我們更多的是對這些概念有一些感性的、樸素的認識。將之內化到自己的工作中去,才能更好的發揮架構的優勢。

本文將簡單談談SOA和MSA的概念,並簡單列舉一下如果使用Java來構建一個微服務系統時所會遇到的一些概念。本文只是「Yet Another」敘述微服務的文章,而且觀點並沒有很嚴謹,希望能讓讀者對微服務和SOA留下一個感性的認識,如果有什麼不對的地方,還請輕拍。

微服務和SOA的區別

所以,到底SOA和微服務有什麼區別?

短答案:微服務是SOA發展出來的產物,它是一種比較現代化的細粒度的SOA實現方式。

微服務就是這樣的一個「概念」,說白了,它不過就是近些年火起來的有一個名詞而已,一時間彷彿整個行業都在討論它,彷彿終於找到了銀彈。這個時候SOA看待微服務大概就如同當年的Friendster和Myspace看待Facebook一樣——大家都忘了社交網路這個東西並不是Facebook發明的。你再談如何使用SOA去構建一個系統,就像是在談一個過氣的明星,人們會認為你已經落伍了。但真的是這樣的嗎?

MSA is a SOA

較早實踐微服務的公司Netflix就曾經稱他們構建的架構是「細粒度的SOA」

討論「微服務和SOA的差別」的意義遠不如討論「微服務和單體系統的差別」更大,因為他們的區別實在有點微妙。此外,網際網路近些年的發展,越來越朝去中心化的方向前進了,就像今天的IT工程師不需要像律師、教師那樣,需要得到某些機構的認可才能更好的開展工作,這一方面意味著門檻的降低,另一方面也意味著更多的概念沒有一個權威的聲音來對它進行定義,使得每個人可以根據自己的需求做出不同的調整。

微服務和SOA都是這樣背景下的產物,並沒有一個權威的定義,來說明它們各自包含了什麼東西,使用什麼的方法進行系統的構建。但是,還是可以從最大的範圍來對比它們的不同,當我們今天說出這兩個概念時,其區別往往沒有那麼大,但SOA是有一定的歷史了,在歷史上的SOA往往意味著更多的東西,而這些是現在很多人在做架構設計時不會採用的。

MSA vs SOA

1. 最多被人談起的,應該算是ESB了

簡單聊聊SOA和微服務
萬能的ESB(圖片來自Wikipedia)

ESB(enterprise service bus)曾經著實跟隨著SOA火了一陣子,第一次知道它是一個朋友在一家物流公司工作,說他們用了一個很高階的玩意兒,叫企業服務匯流排,接著給我灌輸了一堆ESB的理念。當時感覺這玩意兒太牛了,設計理念也很厲害。

從名稱就能知道,它的概念借鑑了計算機組成原理中的通訊模型——匯流排,所有需要和外部系統通訊的系統,統統接入ESB,豈不是完美地相容了現有的互相隔離的異構系統,可以利用現有的系統構建一個全新的鬆耦合的異構的分散式系統。

但,實際使用中,它還是會有很多的缺點,首先就是ESB的本身就很複雜,大大增加了系統的複雜性和可維護性。其次就是由於ESB想要做到所有服務都通過一個通路通訊,直接降低了通訊速度。

而在現代的微服務中,往往是一個「富終端、瘦通訊」(Smart endpoints and dumb pipes),使用輕量級的通訊機制,而每個終端(服務)有自己的處理邏輯,它知道它要找的服務在哪裡,不需要在通訊的鏈路上做什麼事情。

然而,ESB是一個歷史產物,用今天的眼光看待它,並且將之當做SOA的一個標籤是不合理不公平的。

2. 服務化的概念和服務的尺寸

如前所述,SOA的出現其實是為了解決歷史問題:企業在資訊化的過程中會有各種各樣互相隔離的系統,需要有一種機制將他們整合起來,所以才會有上邊所述的ESB的出現。同樣的,也造成了SOA初期的服務是很大的概念,通常指定的一個可以獨立運作的系統(這樣看,好像服務間天然的鬆耦合)。這種做法相當於是「把子系統服務化」。

而微服務沒有歷史包袱,輕裝上陣,服務的尺寸通常不會太大,關於服務的尺寸,在實際情況中往往是一個服務應該能夠代表「實際業務場景中的一塊不可分割或不易分割的業務實體」。將服務的尺寸控制在一個較小的體量可以帶來很多的好處:

  1. 更易於實現低耦合、高內聚
  2. 更易於維護
  3. 更易於擴充套件
  4. 更易於關注實際業務場景
3. 通訊協議(好吧,我實在編不下去了)

如今越來越多的工程開始使用RESTful來作為API的設計的基礎,但僅僅幾年前還有大把的API使用SOAP、WSDL等基於XML的重量級協議的Web Service。

這點和上文說到的2點其實大同小異,仔細想想,它們都是由於歷史原因造成的,同樣的,通訊協議經過這些年的發展,現在主流的基本上了兩種:

  1. 文字協議
    使用最廣泛的多是基於HTTP的RESTful規範
  2. 輕量級二進位制協議
    Thrift、Protobuf,或者任何自定義的輕量級協議

要解決的問題

大家都在討論微服務,造成了當有人要構建一個系統,往往會第一時間想到使用它,較少有人會去想為什麼要用微服務,是不是有更好的選擇。

沒有銀彈

軟體工程是一個處處有坑的事情,但MSA不是銀彈,並不是所有的軟體系統都適合。它有自己適應的場景和不足之處,下面根據自己的理解列出一些系統的需求,如果你的系統有這方面的需求,那麼可以考慮使用微服務來構建你的系統。

複雜性

顧名思義,微服務首先強調的是服務粒度比較小,這就帶來了一個直接好處:實現簡單。

如果你判斷你的系統需要有很多截然不同的功能模組,複雜的業務邏輯,業務目標多種多樣,那麼你可以開始考慮使用MSA將你的系統分解成概念上獨立的服務,這樣一來開發工作的難度可以直接的降低了。當然,與此同時你要面對的是另外一種複雜性挑戰——從概念上分解和管理這些服務本身就是一件十分複雜的工作。好在現在開源社群有很多較完善的服務治理的框架和解決方案,正可以用來解決這方面的複雜性問題。

相反,假如你要做一個論壇系統,或者一個簡單的電商網站,並沒有進行大面積推廣的計劃,預計使用者規模在可預見的範圍內不會超過10萬。那麼你需要的不是微服務,而是可以快速開發並上線的架構,這種情況單體應用最合適,也有很多的開源解決方案可以用來開發MVP。

可維護性

微服務的細粒度服務和分散式部署的特點,帶來的一個好處是:可獨立維護。

如果你的系統需要持續的改進,以配合業務的不斷髮展,那麼可以考慮使用MSA來做系統的架構。例如,你們正在做一個電商網站,經常要做各種各樣的活動,優惠條件、優惠力度、甚至優惠的計算方式都經常在變,這所有的變化不可能在系統設計的時候完全考慮到,當需要開發介入時,MSA的優點就體現出來了。

服務的分離所遵循的很多原則(如SRP、開閉原則)正是為這種改變所提出的,根據這些原則,你的系統裡可能有一個服務叫「訂單服務」,所有的改動都只需要在這個服務內進行,或者更進一步,你有一個專門處理活動的服務,只需要很少的開發和測試的工作量就可以實現。

C10K、C100K。。。

高併發這個概念快變得爛大街了,不同的高併發場景需要的解決方案千差萬別,同時它也是一個系統工程,而不是通過某一個方面就能解決的。如對於一個做內容的網站,高併發帶來的直接挑戰是大量資料(圖片、文字)的獲取,而對於寫的需求相對而言並不會很高,所以CDN、快取、網頁靜態化等都是可以採用的軟硬體解決方案;而對於電商類的交易系統,更重要的是保證系統的快速響應、持續可用、最終一致、和水平擴充套件,所以NIO、分庫分表、快取、API升降級、負載均衡都是可以採用的方案。

當然,本文的重點是MSA,所以這裡只從架構的角度講一下MSA對於解決高併發問題的優勢。由於MSA通常是分散式部署,通過服務註冊中心實現服務的發現,服務具體部署的機器對於服務的呼叫方來說是透明的,然後通過客戶端或者服務端的軟負載均衡,可以在某個服務的壓力大的時候直接新增機器實現水平擴充套件,對於效能的提示在某個範圍內可以認為是線性的。從架構的角度,微服務是解決某一類高併發的較好的解決方案。

同時,高層的架構設計只能從大局上解決這個問題,比如你設計了一個很完善的分散式系統,但好多的服務經常出現記憶體洩漏,動不動機器就當掉,那多好的架構都於事無補。

框架選擇的玄學

雖然Java的框架還沒有多到JS那麼離譜,但相同或相似的功能通常都會有兩個或兩個以上的選擇,有的需要多選其一,有的可能要組合使用。如何在這些名目繁多的框架中選擇出來適合自己的框架十分困難,每個人心中都有自己的一套的價值觀,快變成了玄學了。

簡單聊聊SOA和微服務
在github搜尋「framework」的結果

有一派的存在主義哲學認為,人是自由的,這體現在人有選擇的自由,一個人做的每一個選擇都成為他未來的自己的一個組成部分。放在架構設計上也適用,你在做各種各樣的選擇時,也一步步地成就了你要構建的那個系統的樣子。

Java中的微服務

雖然MSA其本身不排斥多語言的異構系統,實際場景中也會有多語言開發的例子,但多數情況下,很多人還是習慣於系統中大多數的服務都是用相同的語言進行開發。在Java的生態中,已經有很多十分成熟的,可以拿來實現MSA的中介軟體,比較出名的有:Spring全家桶(基於Netflix)、Dubbo(國內十分流行)、Thrift(需要自己實現一些基礎的東西)。
通常,MSA的實現通常要滿足下面幾個條件:

  1. 服務足夠的小,需要根據自己的實際需求決定服務的大小。
  2. 服務可以獨立開發、部署、測試。
  3. 使用輕量級通訊方式。
  4. 資料分離

實際場景中的選擇

在實際的MSA的實踐中,會遇到各種各樣的選擇,To be or not to be,被這個問句困擾著的不止哈姆雷特,還有很多開發者。實際場景中會遇到的選擇包括但不限於以下幾點,可以拿來作為一個checklist。
這並不是一個完整的列表

  • 具體細節的實現方式
    從程式碼級的角度看,主要是具體細節的實現方案,程式碼的好與壞很難用一個定量的標準去衡量,但GOF的設計模式是一個很好的開始,「重構」那本書中也講到了很多「程式碼中的壞味道」。多數情況下,這裡講到的壞程式碼並不是指的效能,而是指其可讀性與可擴充套件性。

  • 基礎設施
    任何軟體系統都是要部署到具體的基礎設施上去的,關於基礎設施的部署也有很多的選擇,如:PC vs Docker、Apache vs Nginx、Tomcat vs Jetty。

  • 微服務框架

    1. Spring全家桶
      用起來很舒服,只有你想不到,沒有它做不到。
    2. Dubbox
      很多國內的企業還在用,可以支援RESTful風格的API,但更多的還是會使用Dubbox的預設的基於RPC的API,呼叫遠端API像呼叫本地API一樣。這樣做無疑帶來了很多優勢,但同時其基於介面的方式增加了服務間的耦合,怎麼說呢,各有利弊。
    3. Thrift
      如果你比較高冷,完全可以基於Thrift自己搞一套抽象的自定義框架。
  • 同步vs非同步
    在跨服務的業務邏輯的實現上,使用基於訊息的非同步呼叫,還是使用保證結果的同步方案。

  • 資料服務
    記憶體資料庫 vs 持久化資料庫(Redis vs MySQL)
    關係型資料庫 vs 非關係型資料庫(MySQL vs Mongo)
    傳統資料庫 vs 分散式資料庫(MySQL vs F1)
    非關係型資料庫又有如KV資料庫,文件資料庫,圖資料庫等。
    由於MSA提倡服務間的資料隔離,往往不同的服務使用不同的資料來源,這就會直接導致資料聚合查詢比較困難的問題。進行資料聚合又有幾種不同的方案(如CQRS)。

  • 日誌分析
    日誌分析也是有很多的成熟解決方案(如ELK)。

相關文章