服務註冊與發現是微服務中最爲基礎的環節,而 Eureka 就是一個能夠幫助你實現服務註冊與發現的選擇之一。若是你對 Eureka 和服務發現瞭解甚少,那麼該篇博客將會幫助到你。文中經過具體操做帶你瞭解以下內容:html
閱讀本文須要你熟悉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 是 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 環境搭建!架構
按下圖所示打開SpringBoot Starter構建的窗口 File--New--Spring Starter Project
勾選 Eureka Server
若是不勾選 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
在 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 服務端自己也註冊到服務端以下圖所示:
首先在 SpringBoot Starter 構建的窗口 勾選 Eureka Discovery Client 和 Spring Web Starter 以下圖所示:
須要注意的是若是沒有勾選 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 以下圖所示:
最後在 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中查看註冊的客戶端。
若是你按照上述方式搭建並未成功,能夠請參考我在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 Server(Eureka註冊中心)。Eureka Server(Eureka註冊中心)搭建集羣仍是比較簡單的,只須要讓各個服務端互相註冊便可。官網搭建集羣框架圖以下:
我來舉個例子,假如你有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 中配置三個域名信息。
我本地代碼服務端和客戶端搭建具體配置:
客戶端和服務端引入依賴和添加@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 控制檯界面信息:
Eureka服務2 控制檯界面信息:
Eureka服務3 控制檯界面信息:
若是你按照上述方式搭建並未成功,能夠參考我在 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
上面咱們介紹如何搭建單機版和高可用版的 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 包以下圖所示:
而後進入 target目錄 執行 java -jar jar包的名稱,以下圖所示:
以下圖所示:Eureka 註冊服務啓動成功!
啓動商品服務:
進入商品服務項目的目錄,打包而且經過 java -jar 啓動商品服務1項目。具體操做以下圖所示:
商品 2服務操做和上述一致,這裏就再也不進行演示
最後訪問服務註冊服務,查看商品1和商品2服務是否註冊到註冊中心服務中,以下圖所示表示註冊成功!
啓動訂單服務:
經過下圖的方式啓動訂單服務:
訪問 http://localhost:8762/product/1 從訂單服務中獲取商品服務的信息,以下圖所示它會以輪詢的方式調用商品服務1 和商品服務2。
若是你按照上述方式搭建並未成功,能夠參考我在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
調用 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 以下圖所示:
第三步是在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方式效果一致。具體訪問結果以下:
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