從 Spring Cloud 看一個微服務框架的「五臟六腑」

Spring Cloud 是一個基於 Spring Boot 實現的微服務框架,它包含了實現微服務架構所需的各類組件。前端

注:Spring Boot 簡單理解就是簡化 Spring 項目的搭建、配置、組合的框架。由於與構建微服務自己沒有直接關係,因此本文不對 Spring Boot 進行展開。另外本文有一些例子涉及到 Spring 和 Spring Boot,建議先了解一下 Spring 和 Spring Boot 再閱讀本文。
本文的閱讀對象主要是沒有接觸過服務架構,想對其有一個宏觀的瞭解的同窗。java

本文將從 Spring Cloud 出發,分兩小節講述微服務框架的「五臟六腑」:spring

  • 第一小節「服務架構」旨在說明的包括兩點,一服務架構是什麼及其必要性;二是服務架構的基本組成。爲何第一節寫服務架構而不是微服務架構呢?緣由主要是微服務架構自己與服務架構有着千絲萬縷的關係,服務架構是微服務架構的根基。
  • 第二小節「五臟六腑」則將結合 Spring Cloud 這個特例來介紹一個完整的微服務框架的組成。

「服務架構」

爲了方便理解,我先講一個小故事:(改編自一知乎答主)安全

Martin(微服務提出者也叫 Martin)剛來到公司時是一個基層員工,它上面有經理、老闆,那個時候全部人都聽老闆的指揮。網絡

可是過了兩年,公司的人愈來愈多,原來的模式下整個公司的運做效率過低,管理也很混亂。架構

因而已經踏上中層崗位的 Martin 建議老闆進行部門劃分(服務化),專門的部門只作專門的事情(單一職責)。例如研發部門只作研發,人事部門只作招聘。app

老闆聽取了 Martin 的意見,對公司的組織架構進行了調整。負載均衡

有一天,Martin 發現公司的部門愈來愈多,各個部門並不能徹底知道對方所作的事情,這對跨部門協做(服務調用)帶來了困難。框架

行政部門會(註冊中心)來記錄全部的部門,每當有新的部門行政都會記錄下來(服務註冊),而後公佈出來讓全部部門知道(服務發現)。分佈式

在新的組織架構下,公司的效率逐步提升。老闆也給 Martin 發了大量獎金做爲獎勵,Martin 今後贏取白富美走向了人生巔峯。

這是一個公司組織架構演變的故事,主要講的是隨着公司規模的擴大,組織從集中化管理到分佈化管理的過程。

映射到咱們的信息系統裏來也是同樣的,隨着咱們的系統愈來愈複雜,變得難以管理,也有人想到去拆分而後治理。在解決複雜問題上,分治能夠說是一個屢試不爽的辦法。

服務化便是拆解的一種手段。而上面圓括號裏面的內容其實就對應了一個服務化架構的最小組成元素,分別是服務、服務調用、註冊中心、服務註冊、服務發現。有了這些基本的組成要素,就能夠實現一個最簡單的服務架構。

面向服務的架構和微服務架構

面向服務的架構(SOA)和微服務架構是目前兩種主流的服務化架構,都符合上面的例子,也有上面提到的全部組件。這兩種服務架構有不少能夠講的,可是與本文的相關性不大,本文不作會過多展開,只簡單介紹一下二者的區別。

準確地說微服務是去 ESB(企業服務總線)的 SOA。ESB 借鑑了計算機組成原理中的通訊模型 —— 總線,全部須要和外部系統通訊的系統,經過 ESB 進行標準化地轉換從而消除協議、異構系統之間的差別,這樣就能夠利用現有的系統構建一個全新的鬆耦合的異構的分佈式系統。微服務架構去掉 ESB,本質上是一種去中心化的思想。

「五臟六腑」

「心臟」

順着上一節的思路,從最簡單、最核心的問題出發,假設服務 A 要調用服務 B,會有什麼問題?

  • 服務在哪?(服務治理問題)
  • 怎麼調用?(服務調用問題)

這兩個是最核心的問題,也是任何微服務框架首要解決的兩個問題。

爲了解決第一個問題 Spring Cloud 提供了 Eureka、Zookeeper、Cloud Foundry、Consul 等服務治理框架的集成。它們的工做模式是將全部的微服務註冊到一個 Server 上,而後經過心跳進行服務健康監測。這樣服務 A 調用 B 時能夠從註冊中心拿到可用的服務 B 的地址、端口進行調用。

第二個服務調用有人可能認爲就是一個簡單的 HTTP 或者 RPC 調用,不是什麼問題。可是在分佈式的場景下,服務調用須要考慮的因素會更多。好比一個服務有多個實例,此時請求進來了交給誰處理,請求的負載怎麼平衡到各個實例,都是比較棘手的問題。Spring Cloud 提供了兩種服務調用的方式:一種是 Ribbon + restTemplate,另外一種是 Feign。

其中 Ribbon 是基於 HTTP 和 TCP 客戶端的負載均衡器,restTemplate 是 Spring 提供的 Restful 遠程調用的模板,二者結合就能夠達到遠程調用的負載均衡。

而 Feign 是一個更加聲明式的 HTTP 客戶端,開發者能夠像調用本地方法同樣調用它,徹底感受不到是遠程調用,結合 Ribbon 也能夠作負載均衡。

既然兩個問題都獲得瞭解決,咱們就用一個例子來進一步說明一下,例子包含了微服務中最基本的三個角色(註冊中心、服務提供者、服務消費者):

註冊中心

註解 @EnableEurekaServer 表示該 Spring Boot 應用是一個註冊中心。

1

2

3

4

5

6

7

@EnableEurekaServer

@SpringBootApplication

public class EurekaserverApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaserverApplication.class, args);

    }

}

eureka.client.registerWithEureka: false 和fetchRegistry: false 來代表本身是一個 eureka server。

1

2

3

4

5

6

7

8

9

10

11

server:

  port: 8080

 

eureka:

  instance:

    hostname: localhost

  client:

    registerWithEureka: false

    fetchRegistry: false

    serviceUrl:

      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

service-hello 服務

註解 @EnableEurekaClient 表示他是一個 Eureka 客戶端,它會在註冊中心註冊本身。

註解 @RestController 表示這是一個控制器,@RequestMapping("/hello") 表示匹配到請求 '/hello' 時會調用該方法進行響應。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@SpringBootApplication

@EnableEurekaClient

@RestController

public class ServiceHelloApplication {

 

    public static void main(String[] args) {

        SpringApplication.run(ServiceHelloApplication.class, args);

    }

 

    @Value("${server.port}")

    String port;

    @RequestMapping("/hello")

    public String home(@RequestParam String name) {

        return "hello "+name+",i am from port:" +port;

    }

 

}

註冊中心的地址爲 http://localhost:8080/eureka/,也就是上面咱們定義的。服務名爲 service-hello,將會被調用者使用。

1

2

3

4

5

6

7

8

9

eureka:

  client:

    serviceUrl:

      defaultZone: http://localhost:8080/eureka/

server:

  port: 8081

spring:

  application:

    name: service-hello

服務消費者 service-ribbon

假設 service-ribbon 端口爲 8082,當咱們訪問 http://localhost:8080/hello 時,HelloControler 接收到請求,並調用 HelloService 中的 helloService 方法,HelloService 中經過定義的 restTemplate 去調用 http://service-hello/hello。此處要注意的是 @LoadBalanced 註解,它表示啓用負載均衡。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

@SpringBootApplication

@EnableDiscoveryClient

public class ServiceRibbonApplication {

 

    public static void main(String[] args) {

        SpringApplication.run(ServiceRibbonApplication.class, args);

    }

         

    @Bean

    @LoadBalanced

    RestTemplate restTemplate() {

        return new RestTemplate();

    }

 

}

 

@Service

public class HelloService {

 

    @Autowired

    RestTemplate restTemplate;

 

    public String helloService(String name) {

        return restTemplate.getForObject("http://service-hello/hello?name="+name,String.class);

    }

 

}

 

@RestController

public class HelloControler {

 

    @Autowired

    HelloService helloService;

     

    @RequestMapping(value = "/hello")

    public String hello(@RequestParam String name){

        return helloService.helloService(name);

    }

 

}

至此其實一個微服務應用的雛形已經搭建出來了,服務治理、服務調用能夠說是「五臟六腑」中的「心臟」。

「心臟」的依託

接下來咱們要進一步思考的是「五臟六腑」中其他的部分,由於少了它們人也是活不久的。下面經過一個問題或需求對應一個組件的方式進行介紹。

服務「雪崩」與斷路器

因爲網絡等緣由,服務並不能保證 100% 可用,若是單個服務出現問題,調用這個服務就會出現線程阻塞,此時如有大量的請求涌入,Servlet 容器的線程資源會被消耗殆盡,致使服務癱瘓。

因爲服務與服務之間存在依賴,故障會在調用鏈路上傳播,致使整個微服務系統崩潰,這就是服務故障的「雪崩」效應。

爲了解決這個問題,Spring Cloud 提供了對 Hystrix 斷路器的集成,當服務調用失敗的頻次達到必定閾值,斷路器將被開啓,降級的策略能夠開發者制定,通常是返回一個固定值。這樣就可以避免連鎖故障。

此外 Spring Cloud 還提供 Hystrix Dashboard 和 Hystrix Turbine,幫助咱們進行監控和聚合監控。

服務暴露與路由網關

微服務中的服務不少,直接暴露給用戶一是不安全,二是對用戶不友好。所以在微服務和麪向服務的架構中,一般會有一個路由網關的角色,來負責路由轉發和過濾。對應到 Spring Cloud 中有 Zuul 和 Gateway 兩個組件可用。

路由網關接收了全部的用戶請求,有着很高的負載,所以它一般是一個集羣。用戶的請求會先通過一層負載均衡被髮到路由網關。

服務配置與配置中心

在微服務應用中,服務數量巨多,而每一個服務不一樣環境都有着不一樣的配置,爲了方便服務配置文件統一管理,實時更新,因此須要分佈式配置中心組件。須要注意的是此處的配置與註冊中心註冊的配置信息是兩個概念,此處的配置是服務自己的一些配置信息,以下圖:

b6e1ba88-36a7-4fa6-ba93-2b0e501e6c1b

Spring Cloud 提供了 Spring Cloud Config 組件,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程 Git 倉庫中,幫助咱們管理服務的配置信息。

信息同步與消息總線

前一個問題講到了每一個服務都有一些配置信息,那麼配置信息更新了咱們該怎麼辦,手動一個個去更新?固然不是,Spring Cloud 提供了 Spring Cloud Bus 組件,它經過輕量消息代理鏈接各個分佈的節點。當配置信息更新的時候,咱們只要更新一個節點的配置,這個更新就會被廣播到這個分佈式系統中。

問題定位與鏈路追蹤

在微服務系統中,服務之間能夠相互調用,所以咱們一個請求可能會一條調用鏈,而整個系統會存在一張調用網,其中任意一個服務調用失敗或網絡超時均可能致使整個請求失敗。由於調用關係的複雜,這給問題的定位形成了極大的困難,這也是必須提供服務鏈路追蹤的緣由。

Spring Cloud 爲咱們提供了 Spring Cloud Sleuth 組件,它可以跟進一個請求到底有哪些服務參與,參與的順序是怎樣的,從而達到每一個請求的步驟清晰可見。藉助服務鏈路追蹤,咱們能夠快速定位問題。

至此,Spring Cloud 的全部基礎組件都介紹完了。可是目前全部的組件介紹都是分散的,它們組合起來,完整的樣子是什麼樣的?以下圖:

偷懶偷了張圖,圖中漏掉了 Config Server 和鏈路追蹤組件。可是結合上文的介紹,咱們大體能夠腦補出這兩個東西在圖中的位置。Config Server 是一個與全部服務相連的服務集羣,鏈路追蹤組件則集成在每一個服務中。

小結

服務治理爲心臟,路由網關、消息中心、斷路器、鏈路追蹤、配置中心等爲依託,構造了整個微服務框架的「五臟六腑」。固然,一個微服務系統遠比本文所寫的複雜得多,尤爲是在不一樣的業務場景之下,所以想要更深刻地瞭解它就須要咱們不斷地去實踐。而做爲前端,我瞭解這些內容一是爲了更好地瞭解整個請求的流程,二是爲了後續在 SOA 中接入 Node 子服務積累相關知識。

最後分享一句有趣的調侃 Spring 的話:在 Spring 中沒有什麼是一個註解解決不了的,若是有,那麼就用兩個註解

歡迎學Java和大數據的朋友們加入java架構交流: 855835163

加羣連接:https://jq.qq.com/?_wv=1027&k=5dPqXGI

羣內提供免費的架構資料還有:Java工程化、高性能及分佈式、高性能、深刻淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的免費直播講解  能夠進來一塊兒學習交流哦

相關文章
相關標籤/搜索