前言
服務治理
隨着業務的發展,微服務應用也隨之增加,這些服務的管理和治理會越來越難,並且集群規模、服務位置、服務命名都會發生變化,手動維護的方式極易發生錯誤或是命名沖突等問題。而服務治理正是為了解決這個問題,服務治理是微服務架構中最為核心和基礎的模塊,它主要實現各個微服務實例的自動化注冊和發現。
服務注冊
在服務治理框架中,都會構建一個或多個服務注冊中心。
每個服務模塊向注冊中心登記自己所提供的服務,將主機host、端口號、版本號、通信協議等一些附加信息告知注冊中心,注冊中心按服務名分類組織服務清單。
服務注冊中心還需要以心跳的方式去監測清單中的服務是否可用,若不可用需要從服務清單中剔除,達到排除故障服務的效果。
服務發現
服務間調用不再通過指定具體實例地址來實現,而是通過向服務名發起請求調用實現。
服務調用方需要先從服務注冊中心獲取所有服務的實例清單,才能實現對具體服務實例的訪問。
服務調用方在發起調用時,會以某種策略取出一個具體的服務實例進行服務調用(客戶端負載均衡)。
在生產環境中為了考慮性能等因素,不會采用每次都向服務注冊中心獲取服務的方式,並且不同的應用場景在緩存和服務剔除等機制上也會采用不同的實現策略。
Spring Cloud Eureka
Spring Cloud Eureka 是基於 Netflix Eureka 來實現服務注冊和發現的。它主要包括兩個組件:
- Eureka Server(服務端):服務注冊中心,支持高可用配置,依托於強一致性提供良好的服務實例可用性,服務注冊中心之間可以通過異步模式互相復制各自的狀態。
- Eureka Client(客戶端):處理服務的注冊與發現,客戶端可以通過注解和參數配置的方式實現注冊與發現,客戶端向注冊中心注冊自身提供的服務並周期性地發送心跳來更新它的服務租約,Eureka客戶端從服務端查詢當前注冊的服務信息並把它們緩存到本地並周期性的刷新服務狀態。
Eureka 基礎架構
- 服務注冊中心(Eureka Server):服務端,提供服務注冊和發現功能。
- 服務提供者(Service Provider):提供服務的應用,將自己提供的服務注冊到 Eureka Server,供其他應用發現。
- 服務消費者(Service Consumer):消費者應用從 Eureka Server 獲取服務列表,從而調用對應的服務(ribbon或者feign)。
基礎架構圖
快速搭建服務注冊中心(Eureka Server)
1. 創建 Spring Boot 項目,添加依賴
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. @EnableEurekaServer 注解啟動服務注冊中心
@SpringBootApplication
@EnableEurekaServer
public class SpringCloudEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
}
}
3. 配置文件 application.properties
server.port=9999
#eureka
eureka.instance.hostname=127.0.0.1
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
- eureka.client.register-with-eureka:當前應用為服務注冊中心,所以設置為false,代表不向注冊中心注冊自己。
- eureka.client.fetch-registry:注冊中心的職責主要是維護服務實例,所以設置為false,代表不去檢索當前應用的服務。
- eureka.client.serviceUrl.defaultZone:用於與 Eureka Server 交互的地址,注冊服務和發現服務都需要依賴這個地址。
4.啟動應用,訪問:http://127.0.0.1:9999/
可以看到 Eureka 的信息面板,其中 Instances currently registered with Eureka 中列表顯示 No instances available,說明該注冊中心還沒有注冊任何服務。
服務提供者(Service Provider)
1. 創建 Spring Boot 項目,添加依賴
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. @EnableDiscoveryClient 注解啟動 Eureka 客戶端
@SpringBootApplication
//@EnableEurekaClient 該注解在采用eureka作為注冊中心時使用,場景較為單一
@EnableDiscoveryClient //場景更為廣泛
public class SpringCloudEurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaServiceApplication.class, args);
}
}
@EnableEurekaClient
和 @EnableDiscoveryClient
在當前示例中使用效果好是一樣的,@EnableEurekaClient
注解在采用eureka作為注冊中心時使用,場景較為單一,@EnableDiscoveryClient
場景更為廣泛。
3. 配置文件 application.properties
server.port=8888
spring.application.name=spring-cloud-eureka-service
#info 應用信息
info.app.name=spring-cloud-eureka-service
info.app.version=v1.0.0
info.app.description=spring-cloud-eureka-service
#eureka
eureka.instance.hostname=127.0.0.1
#每隔5s心跳一次,證明本服務還活着
eureka.instance.lease-renewal-interval-in-seconds=5
#本服務10s內沒有心跳,就將該服務從服務端剔除
eureka.instance.lease-expiration-duration-in-seconds=10
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9999/eureka/
- eureka.instance.lease-renewal-interval-in-seconds:設置心跳間隔秒數
- eureka.instance.lease-expiration-duration-in-seconds:設置秒數內無心跳,則剔除服務
4. 啟動應用,訪問:http://127.0.0.1:9999/
在服務注冊中心的控制台中我們可以看到如下輸出,說明服務被注冊成功了。
c.n.e.registry.AbstractInstanceRegistry : Registered instance SPRING-CLOUD-EUREKA-SERVICE/192.168.101.201:spring-cloud-eureka-service:8888 with status UP (replication=false)
而在 Eureka 的信息面板上,在 Instances currently registered with Eureka 列表中同樣可以看到服務的注冊信息。如下圖:
高可用注冊中心(集群)
上面介紹了單節點模式的服務注冊中心,不過在實際生產環境中,通常不會采用這種模式。在分布式系統中,服務注冊中心是非常重要的組成部分,如果是單節點模式,發生故障的話將會是毀滅性的災害。所以為了維護服務的高可用性,通常采用集群的解決方案。
Eureka 的服務治理設計中,所有的節點既是服務提供方,也是服務消費方,服務注冊中心也不例外。Eureka 通過互相注冊服務的方式,以實現服務清單的互相同步,達到高可用的效果。
雙節點注冊中心
- 搭建服務注冊中心 A,配置文件如下:
server.port=9991
spring.application.name=eureka-server
spring.profiles.active=nodea
#eureka
eureka.instance.hostname=nodea
#設置微服務調用地址為IP優先(缺省為false)
#eureka.instance.prefer-ip-address=true
eureka.client.serviceUrl.defaultZone=http://nodeb:9992/eureka/
- 搭建服務注冊中心 B,配置文件如下:
server.port=9992
spring.application.name=eureka-server
spring.profiles.active=nodeb
#eureka
eureka.instance.hostname=nodeb
#設置微服務調用地址為IP優先(缺省為false)
#eureka.instance.prefer-ip-address=true
eureka.client.serviceUrl.defaultZone=http://nodea:9991/eureka/
- 在 /etc/hosts(windows系統路徑為 C:\Windows\System32\drivers\etc\hosts) 文件中添加 nodea 和 nodeb 的轉換,如下:
127.0.0.1 nodea
127.0.0.1 nodeb
- 啟動兩個項目,分別訪問
http://nodea:9991/
和http://nodeb:9992/
,我們可以看到兩個節點都已經被注冊,如下圖所示:
5. 搭建完多節點服務注冊中心之后,服務提供者也需要做一些簡單的配置,以上面的服務提供者為例,修改如下:
eureka.client.serviceUrl.defaultZone=http://nodea:9991/eureka/,http://nodeb:9992/eureka/
啟動項目后,訪問兩個服務注冊中心,我們看到服務被注冊到這兩個節點內。
6. 這時我們關閉服務注冊中心節點 A,我們可以看到服務注冊中心節點 B 依然可以提供服務,而節點 A 從 available-replicas(可以分片) 變為 unavailable-replicas(不可用分片)。
服務消費者(Service Consumer)
使用 Ribbon 調用服務
1. pom 相關依賴配置
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. 配置文件 application.properties
spring.application.name=spring-cloud-ribbon-consumer
server.port=8081
eureka.client.serviceUrl.defaultZone=http://nodea:9991/eureka/,http://nodeb:9992/eureka/
3. 啟動類配置
通過 @EnableDiscoveryClient
注解將應用注冊為 Eureka 客戶端,獲得服務發現能力。
創建 RestTemplate 的 Spring Bean 實例用來調用服務。
通過 @LoadBalanced
注解來開啟客戶端的負載均衡。
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudRibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(SpringCloudRibbonConsumerApplication.class, args);
}
}
4. ConsumerController 來實現服務調用
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping("/test")
public String test() {
return restTemplate.getForEntity("http://spring-cloud-eureka-service/test", String.class).getBody();
}
}
spring-cloud-eureka-service 為服務注冊中心的應用名稱,大小寫均可。
使用 Feign 調用服務
1. pom 相關依賴配置
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. 配置文件 application.properties
spring.application.name=spring-cloud-feign-consumer
server.port=8080
eureka.client.serviceUrl.defaultZone=http://nodea:9991/eureka/,http://nodeb:9992/eureka/
3. 啟動類配置
通過 @EnableDiscoveryClient
注解將應用注冊為 Eureka 客戶端,獲得服務發現能力。
通過 @EnableFeignClients
注解來啟用feign進行遠程調用。
@SpringBootApplication
@EnableDiscoveryClient//啟用服務注冊與發現
@EnableFeignClients//啟用feign進行遠程調用
public class SpringCloudFeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFeignConsumerApplication.class, args);
}
}
4. 實現服務調用接口
@FeignClient(name = "spring-cloud-eureka-service")
public interface TestService {
@RequestMapping("/test")
public String test();
}
spring-cloud-eureka-service 為服務注冊中心的應用名稱,大小寫均可。
此接口中的方法和遠程服務中contoller中的方法名和參數需保持一致。
5. ConsumerController 來實現服務調用
@RestController
public class ConsumerController {
@Autowired
private TestService testService;
@RequestMapping("/test")
public String test() {
return testService.test();
}
}
示例代碼
非特殊說明,本文版權歸 朝霧輕寒 所有,轉載請注明出處.
原文標題:Spring Cloud(二):Eureka 服務注冊中心
如果文章有不足的地方,歡迎提點建議,后續會完善~
如果文章對您有幫助,請給我點個贊哦~
關注下我的公眾號,文章持續更新中...