天天看點

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

前一篇文章中,我們定義了微服務使用的操作模型。這篇文章中,我們将開始使用Spring Cloud和Netflix OSS實作這一模型,包含核心部分:服務發現(Service Discovery)、動态路由(Dynamic Routing)、負載均衡(Load Balancing),和邊緣伺服器(Edge Server),其他部分在後面的文章中介紹。

我們将使用來自Spring Cloud和Netflix OSS的一些核心元件,實作在已部署的微服務互動,不必手動管理配置,如每一個微服務的端口或者手工配置路由規則等等。為了避免端口沖突,我們的微服務在啟動時,将從端口段中動态擷取可用的端口。為了友善通路微服務,我們将使用Edge Server提供一個微服務的通路入口點。

前一篇文章《微服務操作模型》中,我們定義了微服務使用的操作模型。這篇文章中,我們将開始使用Spring Cloud和Netflix OSS實作這一模型,包含核心部分:服務發現(Service Discovery)、動态路由(Dynamic Routing)、負載均衡(Load Balancing),和邊緣伺服器(Edge Server),其他部分在後面的文章中介紹。

在簡要介紹Spring Cloud和Netflix OSS元件之後,我們将描述本系列文章使用的系統,以及如何通路源代碼,并編譯。同時,也會簡要指出源代碼中的最重要部分。最後,我們将運作一些通路服務的測試代碼,也會示範如何簡單地建立一個新的服務執行個體,擷取并使用負載均衡,所有這一些都不必手工配置。

1. Spring Cloud和Netflix OSS

Spring Cloud是spring.io家庭的一個新項目,包含一系列元件,可用來實作我們的操作模型。很大程度上而言,Spring Cloud 1.0 是基于Netflix OSS元件。在Spring環境中,Spring Cloud 非常友好地內建了Netflix 元件,使用了和Spring Boot相似的自動配置和慣例優于配置。

下表映射了操作模式中介紹的元件和我們将要使用的實際元件:

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

本文将包含Eureka、Ribbon和Zuul:

1/Netflix Eureka – Service Discover Server服務發現

Netflix Eureka允許微服務在運作時自我注冊

2/Netflix Ribbon-Dynamic Routing and Load Balancer動态路由和負載均衡

Netflix Ribbon可以在服務消費方運作時查詢微服務。Ribbon使用Eureka中的資訊定位合适的服務執行個體。如果發現了多個服務執行個體,Ribbon将應用負載均衡來轉發請求到可用的微服務執行個體。Ribbon 不作為一個單獨的服務運作,而是嵌入在每一個服務消費方中。

3/Netflix Zuul – Edge Server邊緣伺服器

Zuul是我們對外部世界的守門員,禁止任一未授權的外部請求進入。Zuul在系統内部也提供了友善的進入入口點。通過使用動态配置設定的端口,可以避免端口沖突,以及最小化管理成本,但是也導緻服務消費方更難接入。Zuul 使用Ribbon來查詢可用的服務,并路由外部的請求到合适的服務執行個體。在本文中,我們将僅僅使用Zuul提供了便利的通路入口點,安全部分在下一篇文章中讨論。

備注:通過邊緣伺服器(Edge Server),可被外部通路的微服務,在系統中可稱為API。

2. 系統架構

為了測試這些元件,我們需要一個可實施的業務系統。本文章的目标是開發實作如下系統:

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

上圖包含4個業務服務(綠色文本框):

1/ 三個核心服務負責處理資訊:産品、推薦和評論;

2/ 一個組合服務 product-composite,用來聚合3個核心服務的資訊,組合包含評論和推薦的産品資訊視圖;

為了支援業務服務,我們使用了如下基礎設施服務群組件(藍色文本框):

1/ 服務發現伺服器(Service Discovery Server – Netflix Eureka)

2/ 動态路由和負載均衡(Netflix Ribbon)

3/ 邊緣伺服器(Edge Server – Netflix Zuul)

為了強調微服務和單體應用的差異,我們将每一個服務運作在單獨的微服務程序中。在一個大系統中,如此細粒度的微服務可能并不友善。相應地,一組相關的微服務可能合并為一組,保持微服務的數量在可管理的水準,但這并不是退回到巨大的單體應用。

3. 擷取源代碼并編譯

擷取源代碼,并進行測試,需要已安裝Java SE8和Git,接着執行如下操作:

$ git clone https://github.com/callistaenterprise/blog-microservices.git

$ cd blog-microservices

$ git checkout -b B1 M1.1

将生成如下的目錄結構:

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

每一個元件獨立編譯(記住我們不再編譯單體應用),是以每一個元件都有自己的build檔案。我們使用Gradle編譯系統,如果你沒有安裝Gradle,build檔案将自動下載下傳。為了簡化編譯過程,我們提供了一個小的shell腳本,可用來編譯元件:

$ ./build-all.sh

如果在Windows環境下,你可以執行相應的bat檔案 build-all.bat。

将顯示6個log消息,并顯示:BUILD SUCCESSFUL

4. 閱讀源代碼

快速看看關鍵的源代碼,每一個微服務開發為一個獨立的Spring Boot應用,并使用Undertow(一個輕量級的Servlet 3.1容器)作為web server。Spring MVC用來實作 REST-based服務,Spring RestTemplate 用來執行外部調用。如果你想更多地了解這些核心技術,你可以檢視相關的文章。

這裡,我們關注如何使用Spring Cloud和Netflix OSS功能。

備注:為了讓源碼易于了解,我們特意讓實作盡量簡單。

4.1  Gradle依賴

本着Spring Boot的精髓,Spring Cloud定義了一組starter 依賴,便于引入需要的特定依賴。為了在微服務中使用Eureka和Ribbon,以及友善調用其他微服務,在build檔案中添加如下:

    compile("org.springframework.cloud:spring-cloud-starter-eureka:1.0.0.RELEASE")

可以檢視product-service/build.gradle 擷取完整的例子。

為了搭建Eureka 伺服器,添加如下依賴:

    compile('org.springframework.cloud:spring-cloud-starter-eureka-server:1.0.0.RELEASE')

完整的例子,可以檢視discovery-server/build.gradle。

4.2 基礎設施伺服器

基于Spring Cloud和Netflix OSS搭建基礎設施伺服器相當友善。例如,在一個标準的Spring Boot應用中,添加@EnableEurekaServer标注來搭建Eureka 伺服器。

@SpringBootApplication

@EnableEurekaServer

public class EurekaApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaApplication.class, args);

    }

}

完整的執行個體,可以檢視EurekaApplication.java代碼。

搭建Zuul 伺服器,可以添加@EnableZuulProxy标注。完整的執行個體,可以檢視ZuulApplication.java代碼。

通過這些簡單的标注,可以搭建一個預設的伺服器配置。根據需要,也可以通過特定的設定覆寫預設配置。例如,我們可以通過覆寫預設的配置,限制邊緣伺服器允許路由調用的微服務。預設情況下,Zuul搭建了Eureka中可以發現的每一個微服務的路由。通過如下的application.yml配置,限制了隻允許通路組合服務-product service的路由。

zuul:

  ignoredServices: "*"

  routes:

    productcomposite:

      path: /productcomposite/**

檢視edge-server/application.yml擷取完整的例子。

4.3 業務服務

通過在Spring Boot應用中,添加@EnableDiscoveryClient标注,自動注冊微服務到Eureka Server中。

完整的例子,可以檢視ProductServiceApplication.java。

為了查詢和調用微服務執行個體,可以使用Ribbon和Spring RestTemplate,如下所示:

服務消費方隻需要知道服務的名字,如上述例子中的review,Ribbon(LoadBalancerClient類)将發現服務執行個體,并傳回URI給服務消費方。

5. 啟動系統

在本文中,我們将在本地開發環境中作為一個java程序來啟動微服務。在接下來的文章中,我們将描述如何部署微服務到雲環境和Docker容器中。

為了運作下面的一些指令,需要安裝curl和jq工具。

每一個微服務使用指令 ./gradlew bootRun 來啟動。

首先,啟動微服務基礎設施,如:

$ cd .../blog-microservices/microservices

$ cd support/discovery-server;  ./gradlew bootRun

$ cd support/edge-server;       ./gradlew bootRun

一旦啟動了上述基礎設施微服務,接着啟動業務微服務:

$ cd core/product-service;                ./gradlew bootRun

$ cd core/recommendation-service;         ./gradlew bootRun

$ cd core/review-service;                 ./gradlew bootRun

$ cd composite/product-composite-service; ./gradlew bootRun

如果在Windows環境下,可以運作相應的bat檔案,start-all.bat檔案。

一旦微服務啟動了,将自注冊到服務發現伺服器(Service Discovery Server - Eureka)中去,并輸出如下日志:

DiscoveryClient ... - registration status: 204

在服務發現web 應用中,可以看到如下4個業務服務,和邊緣伺服器(Edge Server)(http://localhost:8761):

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

為了了解上述服務的更多資訊,如使用的ip位址和端口,可使用Eureka REST API:

現在,我們已經準備好進行測試了。首先,驗證可以到達我們的微服務,接着,我們建立一個新的微服務執行個體,并通過Ribbon在多個服務執行個體上實施負載均衡。

備注:在接下來的文章中,我們也會嘗試失敗的場景,示範電路斷路器(Circuit Breaker)是如何工作的。

5.1 開始測試

通過邊緣伺服器來調用組合服務,邊緣伺服器在端口8765(檢視application.yml檔案)。我們通過邊緣伺服器,以及路徑/productcomposite/** 可到達 productcomposite 服務。傳回的組合響應如下:

如果在微服務内部,我們實際上可以直接調用微服務,不必通過邊緣伺服器。當然,問題是我們不知道服務運作在什麼端口,因為服務是動态配置設定的。但是,我們可以檢視調用Eureka REST API 的輸出,就知道服務監聽的端口了。我們可以使用如下的指令調用3個核心服務(端口号采用Eureka REST API輸出的端口資訊):

在自己的環境中,使用相應的端口号。

5.2 動态負載均衡

為了避免服務故障或者臨時的網絡問題,通常需要多個服務執行個體,通過負載均衡分發請求。因為我們使用動态配置設定的端口和服務發現Server,可以非常容易添加新的服務執行個體。例如,可以簡單啟動一個新的review服務,動态配置設定一個新的端口,并自我注冊到服務發現伺服器(Service Discovery Server)中。

$ cd .../blog-microservices/microservices/core/review-service

$ ./gradlew bootRun

稍等片刻,第二個服務執行個體出現在服務發現web應用中(http://localhost:8761):

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

如果你運作之前的curl指令多次(curl -s localhost:8765/productcomposite/product/1 | jq .),檢視2個review執行個體的log日志,可以發現負載均衡在2個執行個體之間自動處理調用請求,不必手工配置。

基于Spring Cloud和Netflix OSS 建構微服務-Part 1

6. 總結

我們已經了解到Spring Cloud和Netflix OSS 元件是如何用來簡化獨立部署微服務協同工作的,不必人工管理每一個微服務的端口,或者人工配置路由規則。當新的執行個體啟動之後,它們會自動被服務發現Server監測到,并通過負載均衡來接收請求。通過使用邊緣伺服器(Edge Server),我們可以控制什麼微服務暴露給外部消費方,建立系統的API。

7. 下一步

OK,完成測試之後。接下來還有一些問題沒有回答,例如:

1/ 發生故障将如何處理,如出現一個失敗的微服務;

2/ 如何阻止對API的未授權通路;

3/ 如何獲知微服務内部的運作圖,例如為什麼訂單#123456沒有傳遞?

在接下來的文章中,我們将了解如何使用電路斷路器(Circuit Breaker)來提升服務彈性,使用OAuth 2 限制外部通路等等。也将了解如何使用ELK技術棧來收集所有微服務的日志,并呈現日志資訊。

原文英文連結:Building microservices with Spring Cloud and Netflix OSS, part 1

譯者:Rickie(RickieChina#hotmail*com)

繼續閱讀