微服務架構一條龍:DevOps+資料庫+Service Mesh+容器+雲

微服務架構思想經由 Martin Fowler 闡述後,在近幾年持續受到重視。微服務架構的優點很多,比如它解耦業務,提供更高的靈活性,允許在服務頻繁發版的同時保持系統其它部分的可用性與穩定性;解耦編程語言,針對不同業務可以使用更加合適的語言進行開發;解耦開發團隊,不同團隊各自負責一個微服務,互不影響,加速交付。

人們之所以推崇微服務架構,一方面是看上了它的優勢,必然地,另一方面也是因為在業務快速迭代、集成,系統不斷變得更加複雜的過程中,其原先的基於單體架構或 SOA 架構模式那一套理論在實踐中出現了各種各樣的問題,使得無法滿足業務發展快速變化的需求。

在大家爆發式地談論微服務架構的時候,技術理論上,容器、敏捷、DevOps 與雲等相關領域在不斷髮展,相關思想、方法論與經驗之談也經由各社區得到一步步傳播;落地過程中,以業務量大而雜的公司為主,各個組織在實踐中紛紛採用微服務架構,中小型公司、團隊也或轉型,或從零開始去部署微服務;具體到相關技術實現上,諸如 Spring Cloud、Kubernetes、Eureka、Dubbo、Envoy 與 Istio 等各種微服務架構框架與組件在開源中不斷得到完善。各方面的成熟使得微服務架構變得人人觸手可即,並逐漸形成了一個健全穩定的架構生態,目前其已然成為當下最流行的架構模式。

然而,對於非架構師的大多數還未體驗微服務架構的開發者來說,除了微服務架構本身跟 SOA 能找到一些相似這點認知外,對於其相關細節概念,比如“為何微服務跟容器就扯上了關係?”、“Service Mesh 是怎麼來的?”卻不甚瞭解。

另一方面,在實踐微服務架構的過程中,有一些細節是值得考究的,比如“數據庫隨著業務拆分而拆分嗎?”、“業務拆分又應該拆到什麼程度?”、“微服務架構中的反模式如何避免?”……

因此我們邀請了具有 13 年研發經驗的架構師張鋒針對這一系列問題進行分享,從微服務架構講起,談一圈與之相關的 DevOps、數據庫、Service Mesh、容器和雲,希望給到讀者一個微服務架構生態整體的概念。

  • 很多人覺得微服務架構的要點是業務拆分,並認為微服務架構相較於 SOA 的最大區別就在於對服務的拆分粒度,那麼在您看來服務的粒度細到什麼樣才叫微呢?實際架構實踐中您又是怎麼去衡量的?具體又有哪些拆分依據呢?

業務拆分是微服務中非常重要的一點,如果拆分不基於業務,可能導致後期對於需求的變化響應非常慢,不合理的拆分有可能導致指定的微服務模塊不能夠響應業務需求,當需求發生變化時,不能夠靈活應對,甚至會導致整個微服務模塊重構。這也是產生微服務反模式“沙粒陷阱”的關鍵。

關於拆分粒度的問題,可能回答會虛一些,一直有一句話叫做適合的就是最好的,因為每個公司的業務不同,服務的規模不同,無法使用統一的標準來約定,而且這個還跟團隊的默契程度、穩定性等都有關係,不是單純的一個技術問題。

我覺得一個可以遵循的原則就是在業務拆分完成後能夠快速響應需求變化、滿足併發、能夠快速迭代、支持複用。可以從分析服務的範圍和功能、分析數據庫事務、分析服務調用順序入手去考慮。

首先前後端分離是必要的,因為現在的系統不單單是一個端,可以是網頁、手機或者客戶端,所以前端和後端分離是非常必要的。AKF 擴展立方體是一個非常不錯的拆分方法,它講的是通過三個維度上的擴展,可以快速提高產品的擴展能力,適應不同場景下產品的快速增長。同時,服務就儘量設計成無狀態的,方便橫向擴展。

而具體到我們現有的系統的經驗來看,首先是根據業務部門提供的業務需求,利用

領域驅動設計的思想,將業務進行領域劃分,然後提煉出公共模塊。

這些公共模塊一般複用性都比較高,由專門的團隊進行維護,關於實際的業務模塊,我們公司使用統一的開發框架,各層分層都有嚴格的約定,相當於每個業務只需要按照需求方提出的業務需求進行開發,然後將服務暴露在註冊中心。

關於接口文檔,開始的時候我們使用 WIKI 整理文檔的方式,後來順應潮流,統一使用 Swagger,這樣接口完成就能夠自測,發佈到測試或者線上都能夠第一時間發現問題,並且有效地降低了溝通成本。

  • 在整個微服務架構過程中,包含了多個環節、多個功能模塊的參與,拆分業務、網關、部署、數據庫、文檔、上線……這些環節和功能模塊具體是如何協調起來的?

其實不管是 SOA 還是微服務都是軟件工程中的一部分,都需要包含需求分析、概要設計、詳細設計、編碼、測試、交付這樣的過程,可能針對不同的行業會有所增減,而針對開發人員來說,最關注的是從產品團隊收集需求後,將其實現並且最終上線的過程。

具體到微服務架構上來說,首先,所有的業務會首先經過網關進行調度,網關的調度有專門的操作界面,請求發送到網關後,由調度模塊發送到指定的微服務上。

因為微服務的數量龐大,不可能運用同步的方式來處理,所以,微服務模塊也是按照小組的單位來進行的,每個組都設有組長進行相應的協調和調度,在工期能夠保證的情況下,組長一般是不參與到開發過程的。

當某些微服務完成後,由組長負責發起申請,向測試團隊申請資源,進行微服務模塊的測試,測試完成後,由開發團隊通過自動發佈將服務推到線上。只有在發佈過程中出現問題不能解決的時候,才會向運維團隊申請資源。

數據庫建議在資源允許的情況下,儘量由專業的 DBA 團隊進行處理,比如:數據腳本的審核、數據結構設計的合理性、數據遷移以及基礎的數據分析等。我們的團隊對於數據庫部分,要求是必須通過 PowerDesigner 進行建模,當數據結構有任何變化時,必須由相關團隊負責人進行確認,確認無誤後以郵件方式通知相關模塊負責人版本升級結果。

關於數據庫這一塊可能採用了

不敏捷的方式,但是這是必需的,因為數據是公司的重要資產。

  • DevOps 這兩年變得很火,聯合國 ITU 也在最近正式立項 DevOps 國際標準。上一個問題可能是涉及到了團隊協作模式和軟件工程相關的內容,那麼作為一種與微服務緊密聯繫在一起的敏捷方式 DevOps 在微服務架構實施中具體是怎樣執行的呢?

DevOps 為什麼受到重視,這其實是一個必然的結果,軟件發展這麼多年,無論是 BOSS、管理人員還是使用方,都會對開發的速度和質量提出更高的要求,而自動化可以說是一個有效的提高團隊協作的方式。DevOps 就是擁有這種能力的自動化,可以把它看作開發、技術運營和質量保障三者的交集。

而微服務架構作為一種新興架構模式,正好處在 DevOps 必然發展起來的這個時間節點上,兩相一拍即合。具體到它在微服務架構中有別於其它架構模式的特別之處,應該是它有針對容器進行一些相應的處理。

在很多企業中,應用程序發佈是一項涉及多個團隊、壓力很大、風險很高的活動。然而在具備 DevOps 能力的組織中,應用程序發佈的風險很低,因為當發現問題時,能夠快速回滾。

DevOps 標準強調實踐和技術對 DevOps 的關鍵作用,主要是Management、Practice 和 Technology,並進一步突出容器與微服務對 DevOps 的重要性。

DevOps 不是一個一蹴而就的事情,需要對整個架構以及人員進行調整,以適應新的工作方式。

在我們的實踐當中,首先需要理解 DevOps,並且讓團隊中能夠影響到決策的人理解它的好處,並且意識到這個不是一個簡單的過程,可能需要變革。越是大的團隊,這種變革的作用越明顯。所以實踐中,我們首先是通過自動化部署、自動化測試和自動化質量檢查進行 DevOps 的實踐。

自動化部署的過程還包括持續部署、高可用保障以及成本優化等多個方面。

在我們團隊中,自動化部署是首先被運用到團隊中的。

  1. 開發人員完成需求的功能後,提交代碼到代碼倉庫(SVN 或者 Git),Jenkins 從代碼倉庫拉取項目分支代碼。
  2. 執行構建,一般使用 Maven 進行項目的構建,當然也可以採用其他的構建工具。Maven 從 Nexux 私服摘取需要的 jar 包信息,完成編譯。
  3. 編譯完成後會自動觸發單元測試,測試所有應用的單元測試代碼。
  4. 單元測試通過後,觸發 sonarcube 客戶端執行靜態代碼檢查,並且生成檢查報告。
  5. 編譯和構建完成後,需要生成 Docker 鏡像。
  6. 將鏡像發送到測試環境進行發佈,觸發自動化測試流程。
  7. 如果測試不通過,則觸發迴歸流程,測試通過,將已經打包好的鏡像推送到預發佈環境。
  8. 預發佈環境測試沒有問題後,就可以進行灰度發佈,將系統發佈到線上環境。

在持續構建的過程中,能實時查看構建進度、構建狀態、構建結果等詳細信息。

  • 微服務架構有一些反模式,在實際操作中,比較普遍的反模式有哪些呢?如何避免?

數據驅動的反模式

單體應用遷移到微服務架構有兩個主要目標:

  • 第一個目標是單體應用程序的功能分割成小的、單一用途的服務。
  • 第二個目標是單體應用的數據遷移到每個服務自己獨佔的小數據庫。

第二種很容易導致的一個問題就是數據庫的拆分不明確,可能粒度過粗,也可能粒度過細;還有一個問題就是數據的遷移。所以在微服務拆分的時候,功能分割優先,數據遷移最後。

超時反模式

分佈式應用的挑戰之一就是如何管理遠程服務的可用性和它們的響應。一般情況下服務消費者可以選擇

無限期等待或者設置超時時間,使用超時時間看起來是個好辦法,但是它會導致超時反模式。

所以一般使用斷路器模式來處理,這種設計模式就像家裡電器的保險絲一樣,當負載過大,或者電路發生故障或異常時,電流會不斷升高,為防止升高的電流損壞電路中的某些重要器件或貴重器件,燒燬電路甚至造成火災,保險絲會在電流異常升高到一定的高度和熱度的時候,自身熔斷切斷電流,從而起到保護電路安全運行的作用。

斷路器模式相比設置超時的優點是,使用者可以立即知道服務已變得不響應,而不必等待超時,使用者將在毫秒內服務不響應。

另外斷路器可以通過幾種方式進行監控,最簡單的方法是對遠程服務進行簡單的心跳檢查,這種方式只是告訴斷路器服務是活的,但是要想獲取服務存活的詳細信息,就需要定期(比如 10 秒)獲取一次服務的詳細信息。還有一種方式是實時用戶監控,這種方式可以動態調整,一旦達到閾值,斷路器可以進入半開放狀態,可以設置一定數量的請求時通過。

共享反模式

微服務是一種無共享的架構,但因為總有一些代碼會在微服務之間共享,這種共享不僅破壞了每個服務的限界上下文 (Bounded Context),而且還引入了幾個問題,包括整體可靠性、更改控制、可測試性和部署能力。

代碼的共享通常會帶來很多問題,微服務架構的主要目標就是共享要儘可能地少,這有助於維護服務的限界上下文,使我們能夠快速的測試和佈署。服務之間依賴越強,服務隔離也就越困難,因此也就越難單獨進行測試和佈署。

解決方法是在需要共享的部分通過複製和服務合併的方式來處理。

報表處理中的反模式

其實微服務中有 4 種方式處理報表類業務,分別是:

  • database pull model,從數據庫中直接拉取
  • HTTP pull model,HTTP 拉取
  • batch pull model,批量拉取
  • event-based push model,基於事件推送

前三種是從服務的數據庫中拉取數據,第 4 種方式是通過事件的方式生成數據。

database pull model 就是從數據庫中直接拉取,雖然這看似乎是個好主意,但它導致了服務之間的明顯依賴關係,會帶來數據庫的非獨立性

HTTP pull model 是 HTTP 拉取模型,使用此模型不需要直接訪問每個服務的數據庫,使用者只需要對每個服務發出一個 REST HTTP 調用就可以訪問其數據。但是這種方式又太慢,無法滿足複雜以及數據量較大數據獲取需求。

batch pull model 是批量拉取模式,這種方式是獨立出一個報表數據庫或者數據倉庫,通過批處理作業將不同服務數據庫的數據拉取這個新獨立的數據庫中,這種模型的問題在於依然是強依賴數據庫,如果拉取服務的數據庫進行了更新,那麼這個批量數據拉取過程也必將修改。

event-based push model 是避免報表處理反模式的一種有可取模式。當各微服務所擁有的數據庫發生變更時,便會產生一個事件,此事件會使得生成報表的服務去處理此事件,到發生數據庫變更的微服務中獲取所變更的數據,並寫入其所擁有的數據庫或數據倉儲中。

此設計方案不僅維持了各微服務的界限上下文,更使得生成報表的服務所擁有的數據庫或數據倉儲,獲得實時的各微服務所擁有的數據庫中的數據。

沙粒陷阱

架構師和開發人員在採用微服務架構的時候最大的挑戰之一就是服務粒度的問題。服務粒度至關重要,它會影響應用的性能、健壯性、可靠性、可測性、設置發佈模型。

這種陷阱的主要原因之一是開發人員常常將服務與類混淆,往往一個類就是一個服務,在這種情況下會很容易遇到沙粒陷阱。

服務應該被看成是一個服務組件,服務組件應該有一個清晰簡明的角色和責任定義,並有一組明確的操作。由開發人員決定服務組件應該如何實現以及服務需要多少個實現類。

要避免沙粒陷阱,主要就是看如何衡量微服務的粒度,像前邊說的,可以從這幾個角度來考慮:

  • 分析服務的範圍和功能
  • 分析數據庫事務
  • 分析服務調用順序

所以建議服務粒度拆分的時候,將團隊中架構以及相關人員聚集到一起,來平衡各個服務拆分的粒度,以最終確認服務拆分的合理性。

  • 在微服務架構中,數據庫可以是分佈式的,每個服務帶一個庫,也可以是集中式地只有一個,現在通用的模式是哪種呢?具體是怎麼樣的?分別有什麼優劣?與 Database Mesh 又有什麼關係?

就我們的業務而言,鼓勵在不拆分能夠滿足業務的情況下,就不進行拆分,當無法支撐業務併發時,才進行拆分。

我們直接看微服務的設計模式,從中可以得到關於數據庫設計的一些相關信息。

微服務的設計模式主要有以下幾種:

鏈式設計模式

鏈式設計模式是常見的一種設計模式,用於微服務之間的調用,應用請求通過網關到達第一個微服務,微服務經過基礎業務處理,發現不能滿足要求,則繼續調用第二個服務,然後將多個服務的結果統一返回到請求中。這是一服一庫的設計。

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

聚合器設計模式

聚合器設計模式是將請求統一由網關路由到聚合器,聚合器向下路由到指定的微服務中獲取結果,並且完成聚合。首頁展現、分類搜索和個人中心等通常都使用這種設計。這是一服一庫的設計。

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

數據共享模式

數據共享模式也是微服務設計模式的一種。應用通過網關調用多個微服務,微服務之間的數據共享通過同一個數據庫,這樣能夠有效地減少請求次數,並且對於某些數據量小的情況非常適合。很顯然,這是多服一庫的模式。

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

異步消息設計模式

異步消息設計模式乍看起來跟聚合器的設計方式很像,唯一的區別就是網關和微服務之間的通信是通過消息隊列而不是通過聚合器的方式來進行的,採用的是異步交互的方式。這也是一服一庫的模式。

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

微服務架構一條龍:DevOps+數據庫+Service Mesh+容器+雲

Database Mesh 的關注重點在於如何將分佈式的數據訪問應用與數據庫有機串聯起來,它更加關注的是交互,是將雜亂無章的應用與數據庫之間的交互有效地梳理。其實在這個概念沒提出之前,一直都存在數據治理,而 Database Mesh 目前來看,更多的還是在概念階段。

  • 講完微服務架構,我們來講講它的延申。講微服務離不開容器(容器技術和容器編排)與雲(函數計算、無服務架構、雲原生等),從微服務到容器,又再聯繫到雲,似乎它們就是一體的,那具體它們是什麼關係,怎麼聯繫起來的?

容器技術可以說是微服務和雲的最佳結合。國外的 Google,國內的京東都已經高調地宣稱其業務在容器內完成。而提到這個,就一定要說一下 Kubernetes。以前的虛擬化技術更多是使用 OpenStack,而目前更多使用基於 Kubernetes 的容器取代 OpenStack。

我們知道,雲從概念上來說可以分為 IaaS、PaaS 和 SaaS,有關雲計算“水煤電”的比喻似乎預示了 IaaS 的未來。換句話說,電廠賺錢嗎?答案是肯定的,但前提是壟斷。

另一方面,對於很多中小企業來說,相比於 IaaS 的部署複雜性和不可避免的運維成本,基於 IaaS 的 PaaS 和 SaaS 似乎更符合自己的胃口。而從歷年的調研數據來看,IaaS 的同比增長呈現出不斷下滑的趨勢,而 SaaS 和 PaaS 的增長態勢要更加良性。

在這場關乎 IaaS 市場地位的爭奪中,兩個比較出眾的技術就是微服務架構和 Docker。而以 Docker 為技術又兼顧微服務優勢的容器雲,開始被稱之為新一代雲計算模式。

IaaS 的建立可以看作是從 0 到 1,而容器的出現則是從 1 到 10 的結果。

舉一個電商的例子來說,電商業務中購物車、訂單、用戶信息、配送、庫存都能夠提取成獨立服務,研發團隊可高頻度獨立更新各個微服務,從而能夠控制變更範圍,極大加速產品的迭代。

按照這個思路,IaaS 提升了資源的交付形式,容器則改變了產品的迭代方式,提高了產品迭代的速度,在這個唯快不破的時代,這一特性的顛覆意義不言而喻。

在 2014 年之前,我們公司的應用程序都部署在物理機器上,這有許多問題:在物理機器時代,為了給即將上線的應用程序分配物理機器,我們平均需要等上一週的時間;由於缺乏隔離機制,應用程序會彼此影響,導致了許多潛在風險;那時候,每個物理機器上的 Tomcat 實例的平均數量至多 9 個;物理機器的資源嚴重浪費,而且調度缺乏靈活性;由於物理機器的故障,應用程序遷移的時間要花數小時;無法實現自動擴展。

為了提高應用程序部署的效率,我們開發了編譯-包裝、自動化部署、日誌收集、資源監控及其他一些系統。

2014 年,我們開始關注 Docker,最開始的時候是將容器當成虛擬機來使用。所有應用程序在容器裡面運行,而不是在物理機器裡面運行。開發人員在生產環境請求計算資源所花的時間由原來的一週縮短到了短短几分鐘

之後隨著 Kubernetes 的開源,我們在其基礎之上進行定製化開發,提供了一站式服務,比如日誌、監控、故障排除、終端和編排。

  • 再來看看另外一個相關的東西:Service Mesh。現在談微服務架構是無法不談及 Service Mesh 的,作為服務通信流量的調控層,Service Mesh 帶來了極大的好處。能否講一講,在最開始沒有 Service Mesh 的情況下,服務間是如何通信,又如何被管理的呢?

Service Mesh 是一個專用的軟件基礎設施層,用於控制和監控微服務應用中服務之間的內部通信,讓服務相互間通信變得快速、安全和可靠。它通常表現為“數據平面”和“控制平面”。

作為 Sidecar 運行,Service Mesh 對應用程序來說是透明,所有應用程序間的流量都會通過它,所以對應用程序流量的控制都可以在 Serivce Mesh 中實現,這樣也就無需關注服務之間的那些原來是通過應用程序或者其它框架實現的事情,比如 Spring Cloud、OSS,現在只要交給 Service Mesh 就可以了。

Service Mesh 的來龍去脈:

  1. 從最原始的主機之間直接使用網線相連
  2. 網絡層的出現
  3. 集成到應用程序內部的控制流
  4. 分解到應用程序外部的控制流
  5. 應用程序的中集成服務發現和斷路器
  6. 出現了專門用於服務發現和斷路器的軟件包/庫,如 Twitter 的 Finagle 和 Facebook 的 Proxygen,這時候還是集成在應用程序內部
  7. 出現了專門用於服務發現和斷路器的開源軟件,如 Netflix OSS、Airbnb 的 synapse 和 nerve
  8. 像上邊的專用於服務發現和斷路器的軟件等往往是各公司基於自己的基礎設施開發的,沒有通用性,這就促使了最後作為微服務的通用中間層的 Service Mesh 的出現

具體到我們自己的實踐中,經歷了這麼一個過程。在最開始,我們做服務化的時候,那個時候還沒有微服務的概念,更多的談及的是 SOA,還主要停留在 Web Service 和 ESB 總線等技術和規範上。

而在開源的領域,可選的方案並不多,所以服務間的通信什麼的我們是直接選擇的阿里開源的 Dubbo。Dubbo 提供高性能和透明化的 RPC 遠程服務調用方案,以及 SOA 服務治理方案,使得應用可通過高性能 RPC 實現服務的輸出和輸入功能,和 Spring 框架可以無縫集成。

Dubbo 包含遠程通訊、集群容錯和自動發現三個核心部分。提供透明化的遠程方法調用,實現像調用本地方法一樣調用遠程方法,只需簡單配置,沒有任何 API 侵入。同時具備軟負載均衡及容錯機制,可在內網替代F5等硬件負載均衡器,降低成本,減少單點。可以實現服務自動註冊與發現,不再需要寫死服務提供方地址,註冊中心基於接口名查詢服務提供者的 IP 地址,並且能夠平滑添加或刪除服務提供者。

之後我們使用的是微服務套件 Spring cloud 來進行整體的微服務管理。Spring Cloud 作為一個微服務的開發框架,包括了很多組件,包括:Spring Cloud Netflix(Eureka、Hystrix、Zuul、Archaius)、Spring Cloud Config、Spring Cloud Cluster、Spring Cloud Consul、Spring Cloud Sleuth 等。


分享到:


相關文章: