SpringCloud 學習筆記之注冊與發現
基礎架構
- 服務注冊中心:Eureka 提供的服務端,提供服務注冊與發現的功能
- 服務提供者:提供服務的應用
- 服務消費者:消費者應用從服務注冊中心擷取服務清單,進而使消費者可以知道去何處調用其所需要的服務。
服務治理機制
服務提供者
服務注冊
服務提供者在啟動的時候會通過發送 REST 請求的方式将自己注冊到 Eureka Server 上,同時帶上了自身服務的一些中繼資料資訊。Eureka Server 接收到這個 REST 請求之後,将中繼資料資訊存儲在一個雙層結構 Map,其中第一層的 key 是服務名,第二層的 key 是具體服務的執行個體名。
在服務注冊時,需要确認 eureka.client.register-with-eureka=false,預設為 true。
服務同步
由于服務注冊中心之間互為注冊為服務,當服務提供者發送注冊請求到一個服務注冊中心時,它會将該請求轉發給叢集中相連的其他注冊中心,進而實作注冊中心之間的服務同步。通過服務同步,兩個服務提供者的服務資訊就可以通過這兩台服務注冊中心中的任意一台擷取到。
服務續約
注冊完服務之後,服務提供者會維護一個心跳用于來持續告訴 Eureka Server:“我還活着”,以防止 Eureka Server 的 “剔除任務” 将該服務從服務清單中排除出去,稱之為服務續約.
服務續約關注兩個重要屬性
# 定義服務續約任務的調用間隔時間
eureka.instance.lease-renewal-interval-in-seconds=30
# 定義服務時效的時間
eureka.instance.lease-expiration-duration-in-seconds=90
服務消費者
擷取服務
消費者啟動時,會發送 REST 請求給服務注冊中心,來擷取上面注冊的服務清單。為了性能考慮,Eureka Server 會維護一份隻讀的服務清單來傳回用戶端,通過該緩存清單會每隔 30 秒更新一次。
擷取服務是服務消費者的基礎,必須確定 eureka.client.fetch-registry=true 參數值為 true
服務調用
服務消費者在擷取消費者清單後,通過服務名可以擷取具體服務的執行個體名和該執行個體的中繼資料資訊。擷取服務執行個體的詳細資訊後,用戶端可以根據自己的需要決定具體調用哪個執行個體,在 Ribbon 中會預設采用輪詢的方式調用,進而實作用戶端的負載均衡。
對于通路執行個體的選擇,Eureka 中有 Region 和 Zone 的概念,一個 Region 中可以包含多個 Zone,每個服務用戶端需要被注冊到一個 Zone 中,是以每個用戶端對應一個 Region 和一個 Zone。在進行服務調用的時候,優先通路同處一個 Zone 中的服務提供方。在進行服務調用的時候,優先通路同處一個 Zone 中的服務提供方,若通路不到,就通路其他的Zone。
服務下線
在系統運作過程中必然會面試關閉或者重新開機的某個執行個體的情況,在服務關閉期間,我們不希望是用戶端能繼續調用關閉的執行個體。是以當服務執行個體進行正常的關閉操作時,它會觸發一個服務下線的 REST 請求給 Eureka Server,告訴服務注冊中心:“我要下線了”。服務端接收到請求之後,該服務于狀态之為下線(DOWN),并把該下線事件傳播出去。
服務注冊中心
失效剔除
服務執行個體并不一定會正常下線,可能由于記憶體溢出、網絡故障等原因使服務不能正常工作,而服務注冊中心并未收到“服務下線”的請求。為了從服務清單從将這些無法提供服務的執行個體剔除,Eureka Server 在啟動的時候會建立一個定時任務,預設每隔60秒将目前清單中逾時(預設 90 秒)沒有續約的服務剔除。
自我保護
服務注冊中心面闆出現紅色警告,該警告實際觸發了 Eureka Server 的自我保護機制。
Eureka Server 在運作期間,會統計心跳失敗的比例在 15 分鐘之内是否低于 85%,如果出現低于的情況(生産上通常是由于網絡不穩定導緻),Eureka Server 會将目前的執行個體注冊資訊保護起來,讓這些執行個體不會過期,盡可能保護這些注冊資訊。但是,在這段保護期間執行個體若出現問題,那麼用戶端很容易拿到執行個體不存在的服務執行個體,會出現調用失敗的情況,所有用戶端必須要有容錯機制,比如可以使用請求重試、斷路器等機制。
單體注冊中心
注冊中心
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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>top.simba1949</groupId>
<artifactId>spring-cloud-eureka-single-server</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring boot starter : Core starter, including auto-configuration support, logging and YAML-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--spring boot starter test : Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--spring boot starter actuator:
Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- eureka 注冊中心依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--編譯插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 配置使用的 jdk 版本 -->
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
<!--springboot-maven打包插件 和 熱部署配置-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
<executable>true</executable><!--将項目注冊到linux服務上,可以通過指令開啟、關閉以及伴随開機啟動等功能-->
</configuration>
</plugin>
<!--資源拷貝插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<!--IDEA是不會編譯src的java目錄的xml檔案,如果需要讀取,則需要手動指定哪些配置檔案需要讀取-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</project>
application.properties
server.port=8081
spring.application.name=spring-cloud-eureka-single-server
eureka.instance.hostname=localhost
# 由于該應用為單機注冊中心,設定為false,表示不向注冊中心注冊自己
eureka.client.register-with-eureka=false
# 由于注冊中心的職責是維護服務執行個體,不需要檢索服務,單機注冊中心不需要檢索
eureka.client.fetch-registry=false
# eureka 位址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
啟動類
package top.simba1949;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @EnableEurekaServer 啟動 eureka 注冊中心服務
*
* @author SIMBA1949
* @date 2019/7/12 9:33
*/
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
通路測試
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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>top.simba1949</groupId>
<artifactId>spring-cloud-eureka-single-service-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring boot starter : Core starter, including auto-configuration support, logging and YAML-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--spring boot starter test : Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--spring boot starter actuator:
Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka client,用于注冊與發現 -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--編譯插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 配置使用的 jdk 版本 -->
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
<!--springboot-maven打包插件 和 熱部署配置-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
<executable>true</executable><!--将項目注冊到linux服務上,可以通過指令開啟、關閉以及伴随開機啟動等功能-->
</configuration>
</plugin>
<!--資源拷貝插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<!--IDEA是不會編譯src的java目錄的xml檔案,如果需要讀取,則需要手動指定哪些配置檔案需要讀取-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</project>
server.port=7000
spring.application.name=spring-cloud-eureka-single-service-provider
# eureka 執行個體位址
eureka.instance.hostname=localhost
# eureka 注冊中心端口
eureka.client.eureka-server-port=8081
# eureka 預設位址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${eureka.client.eureka-server-port}/eureka
Controller
package top.simba1949.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author SIMBA1949
* @date 2019/7/12 10:06
*/
@RestController
@RequestMapping("hello")
public class HelloController {
private Logger logger = LoggerFactory.getLogger(HelloController.class);
@GetMapping
public String say(String name){
logger.info("name=" + name);
return "Hello " + name;
}
}
package top.simba1949;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @EnableDiscoveryClient 将服務注冊到 eureka 中
*
* @author SIMBA1949
* @date 2019/7/12 9:54
*/
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
高可用注冊中心
在 Eureka 服務治理設計中,所有節點即是服務提供方,也是服務消費者,服務注冊注冊中心也不例外。
統一的 pom.xml 檔案
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring boot starter : Core starter, including auto-configuration support, logging and YAML-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--spring boot starter test : Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--spring boot starter actuator:
Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- eureka 注冊中心依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--編譯插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 配置使用的 jdk 版本 -->
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
<!--springboot-maven打包插件 和 熱部署配置-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
<executable>true</executable><!--将項目注冊到linux服務上,可以通過指令開啟、關閉以及伴随開機啟動等功能-->
</configuration>
</plugin>
<!--資源拷貝插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<!--IDEA是不會編譯src的java目錄的xml檔案,如果需要讀取,則需要手動指定哪些配置檔案需要讀取-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
統一的啟動類
package top.simba1949;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @EnableEurekaServer 啟動 eureka 注冊中心服務
*
* @author SIMBA1949
* @date 2019/7/12 9:33
*/
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
注冊中心1——配置檔案
server.port=8081
spring.application.name=spring-cloud-eureka-multi-server-one
# 該 eureka 執行個體位址
eureka.instance.hostname=eureka.one.com
# 該注冊中心将自己注冊到其他注冊中心上實作高可用
eureka.client.register-with-eureka=true
# 該注冊中心擷取其他注冊中心上服務,實作高可用
eureka.client.fetch-registry=true
# eureka 位址,多個位址使用英文逗号隔開
eureka.client.service-url.defaultZone=http://eureka.two.com:8082/eureka,http://eureka.three.com:8083/eureka;
注冊中心2——配置檔案
server.port=8082
spring.application.name=spring-cloud-eureka-multi-server-two
# 該 eureka 執行個體位址
eureka.instance.hostname=eureka.two.com
# 該注冊中心将自己注冊到其他注冊中心上實作高可用
eureka.client.register-with-eureka=true
# 該注冊中心擷取其他注冊中心上服務,實作高可用
eureka.client.fetch-registry=true
# eureka 位址,多個位址使用英文逗号隔開
eureka.client.service-url.defaultZone=http://eureka.one.com:8081/eureka,http://eureka.three.com:8083/eureka;
注冊中心3——配置檔案
server.port=8083
spring.application.name=spring-cloud-eureka-multi-server-three
# 該 eureka 執行個體位址
eureka.instance.hostname=eureka.three.com
# 該注冊中心将自己注冊到其他注冊中心上實作高可用
eureka.client.register-with-eureka=true
# 該注冊中心擷取其他注冊中心上服務,實作高可用
eureka.client.fetch-registry=true
# eureka 位址,多個位址使用英文逗号隔開
eureka.client.service-url.defaultZone=http://eureka.one.com:8081/eureka,http://eureka.two.com:8082/eureka;
注冊中心1
注冊中心2
注冊中心3