帶你入門SpringCloud服務發現 | Eurka搭建和使用

前言

服務註冊與發現是微服務中最爲基礎的環節,而 Eureka 就是一個能夠幫助你實現服務註冊與發現的選擇之一。若是你對 Eureka 和服務發現瞭解甚少,那麼該篇博客將會幫助到你。文中經過具體操做帶你瞭解以下內容:html

  1. 什麼是服務註冊與發現
  2. 什麼是 Eureka
  3. SpringCloud Eureka 單臺環境搭建
  4. SpringCloud Eureka 高可用環境搭建
  5. SpringCloud Eureka RestTemplate Ribbion 的使用
  6. SpringCloud Feign SpringCloud Eureka 的使用

閱讀本文須要你熟悉SpringBoot項目的基本使用便可,還有一點須要注意的是在操做過程當中儘可能和我本地環境一致,由於環境不一致可能會帶來一些問題。我本地環境以下:java

SpringBoot Version: 2.1.0.RELEASE
SpringCloud Version: Greenwich.RELEASE
Apache Maven Version: 3.6.0
Java Version: 1.8.0_144
IDEA:Spring Tools Suite (STS)git

服務註冊與發現介紹

上面講到服務發現是微服務中最爲基礎的環節,什麼是服務發現呢 ?咱們能夠從單體架構提及,單體架構各個服務都在一塊兒,是不須要被發現的。可是在微服務的架構中會出現不少的服務。服務與服務之間怎麼獲取調用地址URL 呢 ?例如 一個商城網站有商品服務和訂單服務。查詢訂單服務時須要從商品服務中獲取商品的信息。github

若是有1個訂單服務和1 個商品服務,訂單服務服務在配置文件中將商品服務的 URL 配置在配置文件中便可。若是出現 2個商品服務,你可能會想到將2個商品服務URL 配置到訂單服務中。若是出現上千個服務呢?你可能發現這種方式不是一個好的方案。同時還有一個問題就是:商品服務宕機後。如何將宕機的服務從配置文件中剔除。web

咱們能夠將商品服務的 URL 地址信息都註冊到統一的服務上,在調用時拉取全部商品服務的 URL 信息。訂單服務能夠自定義負載均衡策略來選取一個 URL 地址進行調用,若是註冊中心發現某個商品服務已經宕機,能夠將其從註冊中心剔除。而今天的主角 Eureka 就是經過這種機制來完成服務發現的。spring

接下來就正式開始今天的主角 Eureka 的詳細介紹!segmentfault

Eureka 是什麼 ?

在介紹操做前,首先來了解一下 Eureka 是什麼?Eureka 是 Netflix 公司開源的一個基於 REST 服務的服務發現框架,主要用於AWS雲,用於定位服務,以實現中間層服務器的負載平衡和故障轉移。SpringCloud 對 Netflix 衆多的開源框架都封裝到其子項目spring-cloud-netflix 中,而 Eureka 就是其中的一個。SpringCloud 能夠經過 Eureka 來完成微服務的服務註冊與發現,固然你也可使用其餘的服務發現框架在 SpringCloud 中。服務器

具體使用和介紹能夠訪問 Eureka 的 GitHub wiki 進行查看
https://github.com/Netflix/eureka/wiki/
https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance網絡

閒話少說,開始咱們的 Eureka 環境搭建!架構

SpringCloud Eureka 單臺環境搭建

Eureka Server 端搭建

按下圖所示打開SpringBoot Starter構建的窗口 File--New--Spring Starter Project

file

勾選 Eureka Server

file

若是不勾選 Eureka Server 也能夠在SpringBoot項目中引入 spring-cloud-starter-netflix-eureka-server 依賴便可。代碼以下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

在 SpringBoot Application上聲明 @EnableEurekaServer

file

在 application.properties 添加配置信息

server.port=8761
spring.application.name=EUREKASERVER
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone= http://localhost:8761/eureka/
eureka.server.enable-self-preservation=false

server.port: 配置服務端的端口號。
spring.application.name: 配置服務端應用名稱.。
eureka.client.register-with-eureka: 是否將本身註冊到服務端,Eureka 服務端須要配置成false 默認是 true
eureka.client.fetch-registry:是否從其餘Eureka服務端獲取註冊信息,默認爲true。如過是單臺服務器能夠設置爲false。

eureka.server.enable-self-preservation:開啓自我保護模式,默認爲 true 表示爲開啓。開發中爲了方即可以將其設置爲false。
eureka.client.service-url.defaultZone:設置 Eureka 服務端的地址,若是是單體服務就配置該 Eureka 單臺服務的 ip 端口號 /eureka。須要注意的是 /eureka 必定要加上。

自我保護模式介紹:

默認狀況下,若是Eureka Server在必定時間內(默認90秒)沒有接收到某個微服務實例的心跳,Eureka Server將會移除該實例。可是當網絡分區故障發生時,微服務與Eureka Server之間沒法正常通訊,而微服務自己是正常運行的,此時不該該移除這個微服務,因此引入了自我保護機制。

自我保護機制的工做機制是若是在15分鐘內超過85%的客戶端節點都沒有正常的心跳,那麼Eureka就認爲客戶端與註冊中心出現了網絡故障,Eureka Server自動進入自我保護機制,此時會出現如下幾種狀況:

一、Eureka Server再也不從註冊列表中移除由於長時間沒收到心跳而應該過時的服務。 二、Eureka Server仍然可以接受新服務的註冊和查詢請求,可是不會被同步到其它節點上,保證當前節點依然可用。 三、當網絡穩定時,當前Eureka Server新的註冊信息會被同步到其它節點中。

自我保護介紹內容摘抄自 —— Java技術棧的博客: Spring Cloud Eureka 自我保護機制 https://segmentfault.com/a/1190000015349644

若是 eureka.client.register-with-eureka=true 或者不配置該信息會,Eureka 服務端自己也註冊到服務端以下圖所示:

file

Eureka Client 端搭建

首先在 SpringBoot Starter 構建的窗口 勾選 Eureka Discovery ClientSpring Web Starter 以下圖所示:
file

須要注意的是若是沒有勾選 Spring Web Starter 客戶端註冊是註冊不到服務端的。

若是不勾選,也能夠直接在SpringBoot項目中引入下面2個依賴來完成。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

而後在 SpringBoot Application 上聲明 @EnableDiscoveryClient 以下圖所示:
file

最後在 application.properties 配置以下信息:

server.port=8760
spring.application.name=EUREKACLIENT
eureka.client.service-url.defaultZone= http://localhost:8762/eureka/

客戶端的 eureka.client.service-url.defaultZone 配置和Eureka Server(Eureka註冊中心)配置同樣。

訪問 Eureka Server(Eureka註冊中心)端以下圖所示中Instances currently registered With Eureka中查看註冊的客戶端。

file

若是你按照上述方式搭建並未成功,能夠請參考我在GitHub 項目 spring-cloud-get-started 倉庫中模塊名爲: spring-cloud-eureka-single-service(Eureka Server)和 spring-cloud-eureka-single-service-client( Eureka Client)進行對比查看是否配置有誤。

spring-cloud-get-started 項目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started

搭建高可用的 Eureka 服務端

在生產環境中爲保證 Eureka 服務的高可用,咱們須要搭建多臺 Eureka Server(Eureka註冊中心)。Eureka Server(Eureka註冊中心)搭建集羣仍是比較簡單的,只須要讓各個服務端互相註冊便可。官網搭建集羣框架圖以下:

file

我來舉個例子,假如你有2臺 Eureka Server 服務,名稱分別爲 Eureka一、Eureka2。

Eureka1的配置: 須要將 eureka.client.service-url.defaultZone 配置成 Eureka2 的服務地址。配置代碼以下:
eureka.client.service-url.defaultZone=http://eureka2:8762/eureka/

Eureka2 的配置 須要將 eureka.client.service-url.defaultZone 配置成 Eureka1 的服務地址。配置代碼以下:
eureka.client.service-url.defaultZone=http://eureka1:8761/eureka/

假如你有3臺 Eureka 服務名稱分別爲 Eureka一、Eureka二、Eureka3。
Eureka1的配置: 須要將 eureka.client.service-url.defaultZone 配置上 Eureka2 和 Eureka3的服務地址並用逗號分隔。
eureka.client.service-url.defaultZone=http://eureka2:8762/eureka/,http://eureka3:8763/eureka/
Eureka2的配置: 須要將 eureka.client.service-url.defaultZone 配置上 Eureka1 和 Eureka3的服務地址並用逗號分隔。
eureka.client.service-url.defaultZone=http://eureka1:8761/eureka/,http://eureka3:8763/eureka/
Eureka3的配置: 須要將 eureka.client.service-url.defaultZone 配置上 Eureka1 和 Eureka2的服務地址並用逗號分隔。
eureka.client.service-url.defaultZone=http://eureka1:8761/eureka/,http://eureka2:8762/eureka/

須要注意的是若是配置了 eureka.client.fetch-registry 須要將其改成 true,若是沒有配置能夠忽略。eureka.client.fetch-registry 表示能夠從其餘 Eureka Server 獲取註冊信息。
還有一點須要注意的是,eureka.client.serviceUrl.defaultZone 配置不能使用 localhost。
若是你使用的是Windows 系統,而且只有一臺機器的狀況下,須要在 HOSTS 中配置三個域名信息。
file
file

我本地代碼服務端和客戶端搭建具體配置:

客戶端和服務端引入依賴和添加@EnableXXX的註解比較簡單,我這裏就不在詳細說明了。能夠參考 SpringCloud Eureka 單臺環境搭建 中的介紹。

主要須要注意的是 application.properties 中的配置,如下是我本地服務端和客戶端配置詳細信息:

Eureka服務1的配置

server.port=8761
spring.application.name=MULTISERVICEEUREKASERVER1
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://MULTISERVICEEUREKASERVER2:8762/eureka/,http://MULTISERVICEEUREKASERVER3:8763/eureka/
eureka.server.enable-self-preservation=falses

Eureka服務2的配置

server.port=8762
spring.application.name=MULTISERVICEEUREKASERVER2
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://MULTISERVICEEUREKASERVER1:8761/eureka/,http://MULTISERVICEEUREKASERVER3:8763/eureka/
eureka.server.enable-self-preservation=false

Eureka服務3的配置

server.port=8763
spring.application.name=MULTISERVICEEUREKASERVER3
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://MULTISERVICEEUREKASERVER1:8761/eureka/,http://MULTISERVICEEUREKASERVER2:8762/eureka/
eureka.server.enable-self-preservation=false

客戶端的配置

server.port=8760
spring.application.name=MULTISERVICEEUREKACLIENT
eureka.client.service-url.defaultZone=http://MULTISERVICEEUREKASERVER1:8761/eureka/,http://MULTISERVICEEUREKASERVER2:8762/eureka/,http://MULTISERVICEEUREKASERVER3:8763/eureka/

Eureka服務1 控制檯界面信息:
file

Eureka服務2 控制檯界面信息:
file

Eureka服務3 控制檯界面信息:
file

若是你按照上述方式搭建並未成功,能夠參考我在 GitHub 項目 spring-cloud-get-started 倉庫中模塊名爲:
spring-cloud-eureka-multi-service-server1(MULTISERVICEEUREKASERVER1)
spring-cloud-eureka-multi-service-server2(MULTISERVICEEUREKASERVER2)
spring-cloud-eureka-multi-service-server3(MULTISERVICEEUREKASERVER3)
spring-cloud-eureka-multi-service-client(MULTISERVICEEUREKACLIENT)
進行對比查看是否配置有誤。

spring-cloud-get-started 項目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started

SpringCloud Eureka RestTemplate Ribbion 使用

上面咱們介紹如何搭建單機版和高可用版的 Eureka 環境,接下來咱們來介紹若是經過 RestTemplate Ribbion 從 Eureka Server 調用咱們的 Eureka 客戶端服務的 API 接口。

調用的流程是:消費端從 Eureka Server 獲取咱們要調用具體服務生產者(Eureka 客戶端)的全部 URL 地址信息,而後經過 Ribbion 的負載策略選取一個服務地址。最後經過RestTemplate 進行調用具體服務 API 接口。

我經過一臺 Eureka Server( Eureka註冊中心服務)端 和 2個商品服務(Eureka客戶端),外加一個服務消費者訂單服務(Eureka客戶端)。經過訂單服務從 Eureka 註冊中心服務獲取2個商品服務(Eureka客戶端)地址URL並經過 Ribbion 負載策略選取其中一個商品服務URL 進行服務的調用。

** Eureka Server 註冊中心服務的搭建:**

添加 spring-cloud-starter-netflix-eureka-server 依賴,而後再 SpringBoot Application 上聲明 @EnableEurekaServer,最後在 application.properties 中添加相關配置信息。

spring-cloud-starter-netflix-eureka-server 依賴配置以下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

application.properties 具體配置信息以下:

server.port=8761
spring.application.name=EUREKASERVER
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.server.enable-self-preservation=false

** 2個 商品服務 (Eureka 客戶端)搭建:**

添加 spring-cloud-starter-netflix-eureka-client 依賴,而後再 SpringBoot Application 上聲明 @EnableDiscoveryClient ,最後在 application.properties 中添加相關配置信息。

分別在商品服務1 和商品服務2 中定義同樣的 RestFul 接口,並經過返回不一樣的商品名稱以示區分。

spring-cloud-starter-netflix-eureka-client 依賴配置以下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

商品服務1 配置信息:

server.port=8760
spring.application.name=PRODUCTSERVER
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

商品服務1 API 接口代碼以下:

@RestController
public class ProductController {
    
    @GetMapping("/product/{id}")
    public Product productInfo(@PathVariable(name="id")Long productId) {
        Product product = new Product();
        product.setId(productId);
        product.setName("product 1:" "蘋果");
        product.setPrice(12d);
        return product;
    }
}

商品服務 2 配置信息:

server.port=8770
spring.application.name=PRODUCTSERVER
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

商品服務 2 API 接口代碼以下:

@RestController
public class ProductController {
    
    @GetMapping("/product/{id}")
    public Product productInfo(@PathVariable(name="id")Long productId) {
        Product product = new Product();
        product.setId(productId);
        product.setName("product 2:" "蘋果");
        product.setPrice(12d);
        return product;
    }
}

商品類的代碼以下

public class Product {
    
    private Long id;
    private String name;
    private Double price;
    //省略 getter 和 setter
}

訂單服務(Eureka客戶端)搭建:

添加 spring-cloud-starter-netflix-eureka-client 依賴,而後再 SpringBoot Application 上聲明 @EnableDiscoveryClient ,最後在 application.properties 中添加相關配置信息。

server.port=8762
spring.application.name=ORDERSERVICE
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

商品服務的調用須要使用到 RestTemplate,因此須要配置 RestTemplate 到Spring的上下文中。具體代碼以下:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate buildRestTemplate() {
        return new RestTemplate();
    }
}

經過 LoadBalancerClient 的 choose 方法來獲取 ServiceInstance,ServiceInstance 就是2個 商品服務(PRODUCTSERVER)其中一個服務信息,LoadBalancerClient 是 SpringCloud 獲取服務的抽象。具體實現是經過 spring-cloud-netflix-ribbon 項目中 RibbonLoadBalancerClient 來實現的。經過 ServiceInstance 獲取商品服務(PRODUCTSERVER)的服務地址 URL。而後經過 RestTemplate 調用 API 接口。具體代碼以下:

@RestController
public class ProductController {
    
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private RestTemplate restTemplate;
    
    @RequestMapping("/product/{id}")
    public String productInfo(@PathVariable(name="id")Long productId) {
        
        ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCTSERVER");
        URI uri = serviceInstance.getUri();
        String url = uri.toString() "/product/" productId;
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        String message = forEntity.getBody();
        
        return message;
    }
}

咱們也能夠經過使用 @LoadBalanced 註解來完成上述操做,使用@LoadBalanced註解的方式相對上面使用 LoadBalancerClient 代碼簡潔了很多。具體操做以下:

在 RestTemplateConfig 構建方法上添加 @LoadBalanced 註解。具體代碼以下:

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate buildRestTemplate() {
        return new RestTemplate();
    }
}

在ProductController 中無需在注入 LoadBalancerClient,直接使用 RestTemplate 調用便可。具體代碼以下:

@RestController
public class ProductController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @RequestMapping("/product/{id}")
    public String productInfo(@PathVariable(name="id")Long productId) {
        
        String url = "http://PRODUCTSERVER/product/" productId;
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        String message = forEntity.getBody();
        
        return message;
    }
}

測試:

整個測試過程須要啓動 一臺 註冊中心服務、2臺商品服務、1臺訂單服務,我的建議註冊中心服務和商品服務經過java -jar的方式啓動,而訂單服務經過 IDEA 來啓動。固然你能夠能夠都在IDEA 中進行啓動全部的服務。

啓動 Eureka 註冊中心服務:
進入 Eureka 註冊中心服務目錄執行打包命令 mvn clean package -Dmaven.test.skip=true。會生成一個可執行的 jar 包以下圖所示:
file
而後進入 target目錄 執行 java -jar jar包的名稱,以下圖所示:
file
以下圖所示:Eureka 註冊服務啓動成功!
file

啓動商品服務:
進入商品服務項目的目錄,打包而且經過 java -jar 啓動商品服務1項目。具體操做以下圖所示:
file
file
商品 2服務操做和上述一致,這裏就再也不進行演示

最後訪問服務註冊服務,查看商品1和商品2服務是否註冊到註冊中心服務中,以下圖所示表示註冊成功!
file
啓動訂單服務:
經過下圖的方式啓動訂單服務:
file
file
訪問 http://localhost:8762/product/1 從訂單服務中獲取商品服務的信息,以下圖所示它會以輪詢的方式調用商品服務1 和商品服務2。
file
file

若是你按照上述方式搭建並未成功,能夠參考我在GitHub 項目 spring-cloud-get-started 倉庫中模塊名爲:
spring-cloud-eureka-ribbion-service ( Eureka Server 服務註冊中心 EUREKASERVER )
spring-cloud-eureka-ribbion-product (商品服務1)
spring-cloud-eureka-ribbion-product2(商品服務2)
spring-cloud-eureka-ribbion-service-order-consume(訂單服務)
spring-cloud-eureka-ribbion-service-order-consume-annotation(訂單服務註解版)
進行對比查看是否配置有誤。

spring-cloud-get-started 項目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started

SpringCloud Feign SpringCloud Eureka 使用

調用 Eureka 客戶端服務還能夠經過 SpringCloud Feign 來進行操做。Feign的底層仍是使用Ribbion。

接下來咱們開始 SpringCloud Feign 是用操做流程介紹,看到這裏你有沒有發SpringCloud 使用的套路。這個套路攏共分三步:
1.引入組件 starter依賴。
2.Application 上添加@EnableXXX註解。
3.appcation.properties上進行添加相關配置信息。

SpringCloud Feign也繞不開這個套路,第一步及先在訂單服務添加 Feign starter。具體依賴代碼以下:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

第二步是在 SpringBoot Application上聲明 @EnableFeignClients 以下圖所示:

file

第三步是在application.properties中配置 Eureka客戶端的配置,具體配置信息以下:

server.port=8762
spring.application.name=ORDERSERVICE
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

第四步是在 RestTemplateConfig 構建方法上聲明 @LoadBalanced

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate buildRestTemplate() {
        return new RestTemplate();
    }
}

第五步是建立調用接口,並在接口上聲明 @FeignClient(name="PRODUCTSERVER") 其中name的值是調用服務的名稱。在聲明調用的方法 @RequestMapping()中配置 URL 和商品服務 API 接口同樣便可。

@FeignClient(name="PRODUCTSERVER")
public interface ProductClient {
    @GetMapping("/product/{id}")
    public Product productInfo(@PathVariable(name="id")Long productId);
}

第六步開始編寫調用的測試類,在ProductController 中引入 PersonClient 而後調用ProductClient 調用方法便可。

@RestController
public class ProductController {
    
    @Autowired
    private ProductClient personClient;
    
    @RequestMapping("/product/{id}")
    public Product productInfo(@PathVariable(name="id")Long productId) {
        Product product = personClient.productInfo(productId);
        return product;
    }
}

測試:

Feign 使用 和 Ribbion 使用是同樣的服務註冊中心和商品服務,啓動方式請參考上面Feign 使用操做介紹。

訪問 http://localhost:8762/product/1 調用訂單服務,和使用Ribbion方式效果一致。具體訪問結果以下:

file

file

SpringCloud Feign SpringCloud Eureka 使用SpringCloud Eureka RestTemplate Ribbion 使用 共用 Eureka 服務端和服務生產者的項目,若是搭建過程當中遇到問題能夠參考我在GitHub 項目 spring-cloud-get-started 倉庫中模塊名爲: spring-cloud-eureka-feign-service-order-consume 進行對比便可。

spring-cloud-get-started 項目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started

小結

SpringCloud Eureka 搭建和使用只要你掌握了搭建三步法:1.引入組件 starter依賴、2.Application 上添加@EnableXXX註解、3.appcation.properties上進行添加相關配置信息。關於具體的配置能夠結合 Spring 官網文檔進行查閱。

參考文獻

https://spring.io/guides/gs/service-registration-and-discovery/

https://cloud.spring.io/spring-cloud-netflix/reference/html/

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

http://seymours.cn/articles/2018/09/19/1537338458105.html

相關文章
相關標籤/搜索