SpringCloud系列第02節之註冊中心Eureka
簡介
Eureka 是 Netflix 開發的,一個基於 REST 服務的,服務註冊與發現的元件
它主要包括兩個元件:Eureka Server 和 Eureka Client
- Eureka Client:一個Java客戶端,用於簡化與 Eureka Server 的互動(通常就是微服務中的客戶端和服務端)
- Eureka Server:提供服務註冊和發現的能力(通常就是微服務中的註冊中心)
各個微服務啟動時,會通過 Eureka Client 向 Eureka Server 註冊自己,Eureka Server 會儲存該服務的資訊
也就是說,每個微服務的客戶端和服務端,都會註冊到 Eureka Server,這就衍生出了微服務相互識別的話題
- 同步:每個 Eureka Server 同時也是 Eureka Client(邏輯上的)
多個 Eureka Server 之間通過複製的方式完成服務登錄檔的同步,形成 Eureka 的高可用 - 識別:Eureka Client 會快取 Eureka Server 中的資訊
即使所有 Eureka Server 節點都宕掉,服務消費者仍可使用快取中的資訊找到服務提供者(筆者已親測) - 續約:微服務會週期性(預設30s)地向 Eureka Server 傳送心跳以Renew(續約)自己的資訊(類似於heartbeat)
- 續期:Eureka Server 會定期(預設60s)執行一次失效服務檢測功能
它會檢查超過一定時間(預設90s)沒有Renew的微服務,發現則會登出該微服務節點
Spring Cloud 已經把 Eureka 整合在其子專案 Spring Cloud Netflix 裡面
關於 Eureka 配置的最佳實踐,可參考:https://github.com/spring-cloud/spring-cloud-netflix/issues/203
更多介紹,可參考:
示例程式碼
本文的例子只能用來嚐嚐鮮,更豐富的配置詳見 Eureka 進階篇:https://jadyer.cn/2017/01/17/springcloud-eureka-advance/
這是演示的是一個由三個模組組成的 Maven 工程,其中包含一個註冊中心和兩個服務提供者
如下圖所示
這是公共的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jadyer.demo</groupId>
<artifactId>demo-cloud-02</artifactId>
<version>1.1</version>
<packaging>pom</packaging>
<modules>
<module>service-discovery</module>
<module>service-server-01</module>
<module>service-server-02</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<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>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
註冊中心
總體思路如下
- SpringBoot啟動類標註
@EnableEurekaServer
註解 - 設定自己本身不註冊到註冊中心
ok,let`s drink code …
這是註冊中心的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jadyer.demo</groupId>
<artifactId>demo-cloud-02</artifactId>
<version>1.1</version>
</parent>
<artifactId>service-discovery</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
這是註冊中心的 SpringBoot 啟動類 ServiceDiscoveryBootStrap.java
package com.jadyer.demo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//建立服務註冊中心
@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscoveryBootStrap {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceDiscoveryBootStrap.class).run(args);
}
}
這是註冊中心的配置檔案 /src/main/resources/application.yml
server:
port: 1100
eureka:
client:
# 設定是否從註冊中心獲取註冊資訊(預設true)
# 因為這是一個單點的EurekaServer,不需要同步其它EurekaServer節點的資料,故設為false
fetch-registry: false
# 設定是否將自己作為客戶端註冊到註冊中心(預設true)
# 這裡為不需要(檢視@EnableEurekaServer註解的原始碼,會發現它間接用到了@EnableDiscoveryClient)
register-with-eureka: false
# 在未設定defaultZone的情況下,註冊中心在本例中的預設地址就是http://127.0.0.1:1100/eureka/
# 但奇怪的是,啟動註冊中心時,控制檯還是會列印這個地址的節點:http://localhost:8761/eureka/
# 而實際服務端註冊時,要使用1100埠的才能註冊成功,8761埠的會註冊失敗並報告異常
serviceUrl:
# 實際測試:若修改尾部的eureka為其它的,比如/myeureka,註冊中心啟動沒問題,但服務端在註冊時會失敗
# 報告異常:com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
defaultZone: http://127.0.0.1:${server.port}/eureka/
服務提供方01
總體思路如下
- SpringBoot啟動類標註
@EnableEurekaClient
或者@EnableDiscoveryClient
註解 - 配置註冊中心地址
ok,let`s drink code …
這是服務提供方的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jadyer.demo</groupId>
<artifactId>demo-cloud-02</artifactId>
<version>1.1</version>
</parent>
<artifactId>service-server-01</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
</project>
這是服務提供方的 SpringBoot 啟動類 ServiceServer01BootStarp.java
package com.jadyer.demo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* 通過 @EnableEurekaClient 註解,為服務提供方賦予註冊和發現服務的能力
* ------------------------------------------------------------------------------------------------------------------
* 也可以使用org.springframework.cloud.client.discovery.@EnableDiscoveryClient註解
* 詳見以下兩篇文章的介紹
* http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_registering_with_eureka
* https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka
* ------------------------------------------------------------------------------------------------------------------
* Created by 玄玉<https://jadyer.cn/> on 2017/1/9 16:00.
*/
@EnableEurekaClient
@SpringBootApplication
public class ServiceServer01BootStarp {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceServer01BootStarp.class).run(args);
}
}
這是服務提供方的配置檔案 /src/main/resources/application.yml
server:
port: 2100
spring:
application:
name: CalculatorServer # 指定釋出的微服務名(以後呼叫時,只需該名稱即可訪問該服務)
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:1100/eureka/ # 指定服務註冊中心的地址
這是服務提供方暴露的數學運算服務 CalculatorController.java
package com.jadyer.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 服務提供方暴露的數學運算服務
* Created by 玄玉<https://jadyer.cn/> on 2017/1/9 16:00.
*/
@RestController
public class CalculatorController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private DiscoveryClient client;
@RequestMapping("/add")
public int add(int a, int b){
//加運算
int result = a + b;
//輸出服務資訊
ServiceInstance instance = client.getLocalServiceInstance();
logger.info("uri={},serviceId={},result={}", instance.getUri(), instance.getServiceId(), result);
//返回結果
return result;
}
}
服務提供方02
除了啟動埠為2200外,其程式碼與服務提供方01的完全相同
驗證
先看一下注冊中心的 Eureka 首頁效果圖
可以看到:兩個服務相同,啟動埠不同的 CalculatorServer 已經註冊進來了
由於釋出的微服務所暴露出去的都是 HTTP 的介面,所以驗證的話,我們可以瀏覽器直接訪問下面的兩個地址
http://127.0.0.1:2100/add?a=3&b=13
http://127.0.0.1:2200/add?a=3&b=13
目前為止,我們完成了 Spring Cloud Netflix Eureka 搭建註冊中心的基本示例,不過也只是嚐嚐鮮
因為它還存在著很多問題,比如
- 什麼是自我保護模式
- 服務提供方關閉之後,在註冊中心看到的狀態還是 UP
- 註冊中心的服務提供方顯示的名字,是不是可以自定義
- …
- …
等等吧,這些問題,請參見 Eureka 進階篇:https://jadyer.cn/2017/01/17/springclou