Spring Cloud與Docker微服務架構實戰觀後感

最近部署項目時接觸了一個新東西:Docker。在後續的查找中發現了周立《Spring Cloud與Docker微服務架構實戰》一書,接觸後感覺很好,又是一套新東西(笑哭)。。如今,自我總結下從書中得到的東西。

首先,自我感覺這本書講的是實貨,對於一個沒接觸過Spring Cloud的人來說,簡直太棒了。示例細節可算是面面俱到,還有對應的demo可下載,邊看邊感覺激情澎湃(笑)。

目前,通過閱讀已知:

  • Spring Cloud 框架開發微服務;
  • Eureka 實現微服務的註冊和發現;
  • Ribbon 實現了客戶端的負載均衡;
  • Feign 實現了聲明式的API調用;
  • Hystrix 實現微服務的容錯(可監控單個實例數據,使用 Turbine 可聚合監控數據,若微服務與 Turbine 不通,使用消息中間件收集數據,如 RabbitMQ);
  • Zuul 建造微服務網關;
  • Spring Cloud Config 管理配置信息(JCE加密,Spring Cloud Bus實現配置的自動刷新);
  • Spring Cloud Sleuth 實現微服務跟蹤(ELK日誌分析,Zipkin收集系統的時序數據);
  • Docker 來部署項目,使用 Docker Compose 來管理Docker容器。

                                                                           以下大部分摘取至書中內容                                                                                    

單體應用架構與微服務架構

本人目前工作一年有餘,平時用spring boot開發接口滿足Web或App項目的使用,看書後,明白了以下概念:

寫過的項目都是單體應用架構:一個歸檔包(例如war包)包含所有功能的應用程序。這種架構有以下缺點:

  • 複雜性高:以百萬行級別的單體應用爲例,整個項目可能包含的模塊非常多、模塊的邊界模糊、依賴關係不清晰、代碼質量參差不齊、胡亂地堆砌在一起。。。使得整個項目非常複雜,每次修改代碼都要膽戰心驚,甚至添加一個簡單的功能,或修改一個 Bug 都會帶來隱患。
  • 技術債務:隨着時間推移、需求變更及人員迭代,會逐漸形成應用程序的技術債務,並且越積越多。“不壞不修”,這是在軟件開發中常見的思想,單體應用更甚。已使用的系統設計或代碼難以被修改,因爲應用程序中國的其他模塊可能會以意料之外的方式使用它。
  • 部署頻率低:隨着代碼的增多,構建和部署的時間也會增加,而單體應用中,每次功能變更或缺陷的修復都會導致需要重新部署整個應用項目。全量部署的方式耗時長、影響範圍大、風險高,使得單體應用項目上線部署的頻率比較低。而這種情況又會導致兩次發佈之間會有大量的功能變更和缺陷修復,出錯的概率較高。
  • 可靠性差:某個應用 Bug,例如死循環、OOM等,可能會導致整個應用崩潰。
  • 擴展能力受限:單體應用只能作爲一個整體進行擴展,無法根據業務模塊的需要進行伸縮。比如應用中有的模塊是計算密集型的,它需要強勁的CPU;有的模塊是IO密集型的,它需要更大的內存。由於這些模塊部署在一起,不得不在硬件的選擇上做出妥協。
  • 阻礙新技術創新:單體應用通常使用統一的技術平臺或方案解決所有問題,團隊中每個成員都必須使用相同的開發語音和框架,要引入新框架或者新技術平臺會非常困難。例如一個使用Struts2構建的、有100萬行代碼的單體應用,如果想要更新Spring MVC,成本毫無疑問是非常高的。

微服務架構恰好能解決上述問題,微服務架構的特性如下:

  • 每個微服務可獨立運行在自己的進程裏。
  • 一系列獨立運行的微服務共同構建起整個系統。
  • 每個服務爲獨立開發,一個微服務只關注某個特定的功能。
  • 微服務之間通過輕量的通信機制進行通信。
  • 可以使用不同的語言與數據存儲技術。
  • 全自動的部署機制。

將整個應用分解爲多個微服務,各個微服務獨立運行在自己的進程中,並分別有自己的數據庫,微服務之間使用REST或者其他協議通信。微服務的優點如下:

  • 易於開發和維護:一個微服務只會關注一個特定的業務功能,所以它業務清晰,代碼量少。
  • 單個微服務啓動較快:代碼少,啓動快。
  • 局部修改容易部署:單體應用只要有修改,就得重新部署整個應用,微服務只需重新部署這個服務即可。
  • 技術棧不受限:在微服務架構中,可結合項目業務及團隊的特點,合理地選擇技術棧。
  • 按需伸縮:可格局需求,實現細粒度的拓展。

當讓,微服務架構也不是十全十美,選擇使用它時,會面臨如下挑戰:

  • 運維要求高:更多的服務意味着更多的運維投入。
  • 分佈式固有的複雜性:使用微服務構建的是分佈式系統。對於一個分佈式系統,系統容錯、網絡延遲、分佈式事務等都會帶來巨大的挑戰。
  • 接口調整成本高:微服務之間通過接口進行通信。
  • 重複勞動:很多服務可能都會使用到相同的功能,而這個功能沒有達到分解爲一俄方微服務的程度,這個時候,可能各個服務都會開發這一功能,從而導致代碼重複。儘管可以使用共享庫來解決這個問題,但共享庫在多語言環境下就不一定行得通了。

微服務設計原則如下:

  • 單一職責原則:一個單元只應關注整個系統功能中單獨、有界限的一部分。
  • 服務自治原則:每個微服務應具備獨立的業務能力、依賴與運行環境。
  • 輕量級通信機制:微服務之間應該通過輕量級的通信機制進行交互。
  • 微服務力度:微服務的力度時難點,也常常時爭論的焦點。應使用合理的粒度劃分微服務,而不是一味的把服務做小。代碼量的多少不能作爲微服務劃分的依據,因爲不同的微服務本身的業務複雜性不同,代碼量也不同。

微服務架構的演進是一個循序漸進的過程。在演進過程中,常常會根據業務的變化,對微服務進行重構,甚至是重新劃分,從而讓架構更加合理。最終,當微服務的開發、部署、測試以及運維的效率很高,並且成本很低時,一個好的微服務架構就形成了。相對單體應用的交付,微服務應用的交付要複雜的多,不僅需要開發框架的支持,還需要一些自動化的部署工具,以及Iaas、PaaS或CaaS的支持。

Spring Cloud中碰到的問題

使用Spring Cloud的過程中,會遇到一些問題,如下:

  • Spring Cloud的依賴,dependencyManagement 標籤確定版本感覺很重要,直接用版本號依賴的話有時會衝突報錯:
<!-- 引入spring boot依賴 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
</parent>
<!-- 所有其他依賴都寫在這裏,下方爲示例 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <!--eureka服務器的如下,客戶端的不加-server-->
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>
</dependencies>

<!-- spring cloud版本 -->
<!-- 通過它元素來管理jar包的版本,讓子項目中引用一個依賴而不用顯示的列出版本號 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Camden.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
  • 項目打JAR包需要如下依賴:

<!-- spring-boot的Maven依賴 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  • 在Spring Cloud中,大部分問題都可使用配置屬性來解決,在Spirng Cloud進入Camden時代後,已經比較穩定。一般來說,問題都不是Spring Cloud本身的Bug導致。因此,排查思路可以按以下步驟展開:

  1. 排查配置問題:

    1. YAML縮進是否正確。

    2. 配置屬性是否正確。

    3. 配置屬性的位置是否正確。

  2. 排查環境問題:

    1. 環境變量。

    2. 依賴下載是否完整。

    3. 網絡問題。

  3. 排查代碼問題。

  4. 排查Spring Cloud自身的問題。

  • Eureka註冊服務慢,一般情況下,服務註冊到Eureka Server的過程較慢。在開發或測試時,常常希望能夠加速這一過程,從而提升工作效率。這個問題的原因如下:服務的註冊涉及到週期性心跳,默認30秒一次。只有當實例、服務器端和客戶端的本地緩存中的元數據都相同時,服務才能被其他客戶端發現(所以可能需要三次心跳)。更改配置可解決,但在生產環境中,建議堅持使用默認值。
  • 已停止的微服務節點註銷慢或不註銷。在開發環境下,常常希望Eureka Server能迅速有效地註銷已停止的微服務實例。然而,由於Eureka Server清理無效節點週期長(默認90秒),以及自我保護模式等原因,可能會遇到微服務註銷慢甚至不註銷的問題。解決方案如下(這種方式僅建議在開發或測試中使用,生產環境建議堅持使用默認值):

    • Eureka Server端配置關閉自我保護,並按需配置Eureka Server清理無效節點的時間間隔。

    • Eureka Client端配置開啓健康檢查,並按需配置續約更新時間和到期時間。

  • 某些情況下,Feign或Ribbon整合Hystrix後,會出現首次調用失敗的問題。Hystrix默認的超時時間是1秒,如果在1秒內得不到響應,就會進入fallback邏輯。由於Spring的懶加載機制,首次請求往往會比較慢,因此在某些機器(特別是配置低的機器)上,首次請求需要的時間可能大於1秒。解決方案如下:

    1. 更改配置,延長Hystrix的超時時間。

    2. 更改配置,禁用Hystrix的超時。

    3. 升級到Spring Cloud到Camden或更新版本。當然,也可單獨升級Spring Cloud Netflix到1.2.0或更新版本,一般不建議單獨升級,因爲可能會跟Spirng Cloud 其他組件衝突。老版本turbine.combine-host-port默認值是false,新版本中已將默認值改爲true。

先記錄這些,詳細的話可以從書中找答案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章