Spring Cloud 快速上手之 Eureka 服務註冊
目錄
簡介
本文主要介紹 Spring Cloud 中的 Eureka 服務註冊中心。
手機用戶請
橫屏
獲取最佳閱讀體驗,REFERENCES
中是本文參考的鏈接,如需要鏈接和更多資源,可以掃碼加入『知識星球』(文末)獲取長期知識分享服務。
準備工作
版本
-
Spring Boot 2.1.5
-
MySQL
簡單的RestTemplate調用
消費端服務調用
@RestController
public class UserController {
@Autowired
private IUserService userService;
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
return userService.findById(id);
}
}
//---
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private RestTemplate restTemplate;
@Override
public User findById(Long id) {
return this.restTemplate.getForObject("http://localhost:8000/"+id,User.class);
}
}
@Configuration
public class RpcConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
返回結果
{
"id": 1,
"account": "account0",
"userName": "x_user_0",
"age": 18
}
Spring Boot Actuator
<!--狀態監控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
從日誌打印的端點信息進入,查看狀態監控返回信息
//獲取健康指標
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:53:14 GMT
{
"status": "UP"
}
//獲取應用信息
GET http://localhost:8000/actuator/info
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:54:41 GMT
{}
//查詢端點信息
GET http://localhost:8000/actuator
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:55:56 GMT
{
"_links": {
"self": {
"href": "http://localhost:8000/actuator",
"templated": false
},
"health": {
"href": "http://localhost:8000/actuator/health",
"templated": false
},
"info": {
"href": "http://localhost:8000/actuator/info",
"templated": false
}
}
}
Response code: 200; Time: 51ms; Content length: 227 bytes
可以通過在 yml 中補充 info 節點信息:
info:
app:
name: @project.artifactId@
encoding: @project.build.sourceEncoding@
java:
source: @java.version@
target: @java.version@
效果如下:
GET http://localhost:8000/actuator/info
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 14:01:48 GMT
{
"app": {
"name": "ms-provider-user-v1",
"encoding": "UTF-8",
"java": {
"source": "1.8.0_181",
"target": "1.8.0_181"
}
}
}
Response code: 200; Time: 182ms; Content length: 108 bytes
小結
我們通過RestTemplate
直接完成服務端的接口調用,但是對於遠端應用地址的硬編碼,往往會帶來很多問題:
- 無法解決 IP 地址或端口變更的場景。
- 無法進行動態伸縮,不支持多實例。
服務註冊與發現
Eureka Server
編寫單點服務註冊中心
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
/**
* 核心啓動類
*/
@EnableEurekaServer
@SpringBootApplication
public class MsDiscoveryEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(MsDiscoveryEurekaApplication.class, args);
}
}
server:
port: 8010
eureka:
client:
# 表示是否將自己註冊到 Eureka Server,默認爲 true
register-with-eureka: false
# 表示是否從 Eureka Server 獲取註冊信息,默認爲 true
fetch-registry: false
service-url:
defaultZone: http://localhost:8010/eureka/
spring:
application:
name: ms-discovery-eureka
訪問
http://localhost:8010/
此處配置的是一個單點的 Eureka Server,不需要同步其他的 Eureka Server 節點的數據,因而 fetch-registry: false
Eureka Client
註冊微服務
- 啓動類
@SpringBootApplication
public class MsProviderUserV2Application {
public static void main(String[] args) {
SpringApplication.run(MsProviderUserV2Application.class, args);
}
}
- 配置
server:
port: 8011
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/db_yier?characterEncoding=UTF-8&rewriteBatchedStatements=true
username: root
password: Abc123++
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5Dialect
application:
name: ms-provider-user-v2
eureka:
client:
service-url:
# 如果此處是註冊到 Eureka Server 集羣的話,建議多配幾個節點,以便適應某些極端場景
defaultZone: http://localhost:8010/eureka/
instance:
# 表示將自己的 IP 註冊到 Eureka Server,若不配置,默認爲 false,表示註冊微服務所在操作系統的 hostname 到 Eureka Server
prefer-ip-address: true
info:
app:
name: @project.artifactId@
encoding: @project.build.sourceEncoding@
java:
source: @java.version@
target: @java.version@
將項目ms-provider-user-v2
註冊到 Eureka Server
服務中心。
同理,將消費者註冊到服務中心
與Eureka Server
不同,Eureka Client
無需在在啓動類上加註解@EnableEurekaClient
註解1
Eureka Server 的高可用
構建雙節點集羣
- 修改 Hosts:Mac
vim /etc/hosts
- 修改配置
spring:
application:
name: ms-discovery-eureka-ha
---
spring:
profiles: peer1
server:
port: 8010
eureka:
instance:
hostname: peer1
client:
service-url:
defaultZone: http://peer2:8020/eureka/
---
spring:
profiles: peer2
server:
port: 8020
eureka:
instance:
hostname: peer2
client:
service-url:
defaultZone: http://peer1:8010/eureka/
- 啓動
profiles:peer1
和profiles:peer2
Eureka Server 集羣精簡配置
spring:
application:
name: ms-discovery-eureka-ha
eureka:
client:
service-url:
defaultZone: http://peer2:8020/eureka/,http://peer1:8010/eureka/
---
spring:
profiles: peer1
server:
port: 8010
eureka:
instance:
hostname: peer1
---
spring:
profiles: peer2
server:
port: 8020
eureka:
instance:
hostname: peer2
用戶認證
爲註冊中心的訪問增加權限認證控制
- 引入
Spring Security
<!--登錄認證-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 配置認證信息
server:
port: 8010
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://admin:Abc123++@localhost:8010/eureka/
spring:
application:
name: ms-discovery-eureka-authentication
security:
user:
name: admin
password: Abc123++
- 訪問
localhost:8010
,會跳轉到登錄界面
服務註冊到帶有安全認證的註冊中心
- Spring Boot 2.0 配置不兼容修改
/*
* @ProjectName: 編程學習
* @Copyright: 2019 HangZhou Helios Dev, Ltd. All Right Reserved.
* @address: 微信搜索公衆號「架構探險之道」獲取更多資源。
* @date: 2020/5/4 9:50 下午
* @description: 本內容僅限於編程技術學習使用,轉發請註明出處.
*/
package com.yido.ms.discovery.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
/**
* <p>
*
* </p>
*
* @author Helios
* @date 2020/5/4 9:50 下午
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 高版本的丟棄了
*
* security:
* basic:
* enabled: true
* 配置,應該使用以下方式開啓
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//方式1
// Configure HttpSecurity as needed (e.g. enable http basic).
//http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
//http.csrf().disable();
//注意:爲了可以使用 http://user:{user}:user:{password}@host:{host}:host:{port}/eureka/ 這種方式登錄,所以必須是httpBasic,
//如果是form方式,不能使用url格式登錄
//http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
//方式2
//默認情況下,將其添加到classpath後,會對每個請求進行CSRF檢查。Eureka並不會生成CSRF token,
// 所以需要關掉對/eureka/*路徑下的檢查:
// 關閉csrf
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
}
- YAML 配置
server:
port: 8010
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://admin:Abc123++@localhost:8010/eureka/
spring:
application:
name: ms-discovery-eureka-authentication
security:
user:
name: admin
password: Abc123++
- 註冊成功
Eureka 元數據
元數據配置
server:
port: 8012
spring:
application:
name: ms-consumer-user-v2-metadata
eureka:
client:
service-url:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
# 定義實例元數據信息
metadata-map:
my-metadata: 自定義信息
查詢接口
/**
* 查詢當前實例信息
* @param instanceId
* @return
*/
@GetMapping("/instances/{instanceId}")
public List<ServiceInstance> instances(@PathVariable String instanceId) {
//爲空,返回自身實例信息
if (StringUtils.isEmpty(instanceId)) {
return this.discoveryClient.getInstances("ms-consumer-user-v2-metadata");
}
return this.discoveryClient.getInstances(instanceId);
}
演示
端點信息
示例
http://localhost:8010/eureka/apps
用途
- 獲取微服務註冊信息
- 通過 xml 和 json 註冊(或註銷)非 jvm 微服務
自我保護模式
保護模式主要用於一組客戶端和Eureka Server之間存在網絡分區場景下的保護。一旦進入保護模式,Eureka Server將會嘗試保護其服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。
默認情況下,如果Eureka Server在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會註銷該實例(默認90秒)。但是當網絡分區故障發生時,微服務與Eureka Server之間無法正常通信,以上行爲可能變得非常危險了(因爲微服務本身其實是健康的,此時本不應該註銷這個微服務)。
Eureka通過“自我保護模式”來解決這個問題:當Eureka Server節點在短時間內丟失過多客戶端時(可能發生了網絡分區故障),那麼這個節點就會進入自我保護模式。一旦進入該模式,Eureka Server就會保護服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。當網絡故障恢復後,該Eureka Server節點會自動退出自我保護模式。
綜上,自我保護模式是一種應對網絡異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目註銷任何健康的微服務。使用自我保護模式,可以讓Eureka集羣更加的健壯、穩定。
自我保護的條件:
一般情況下,微服務在Eureka上註冊後,會30秒定期發送心跳,Eureka 通過心跳來判斷微服務是否健康,同時會定期刪除超過90秒沒有發送心跳的服務。
有2種情況會導致Eureka Server收不到微服務的心跳,
-
是微服務自身原因所致,比如故障或關閉;
-
是微服務與eureka之間的網絡出現故障。
通常(微服務自身的故障關閉)只會導致個別服務出現故障,一般不會出現大面積的故障,而(網絡故障)通常會導致Eureka Server在短時間內無法收到大批心跳。
考慮到這個區別,Eureka設定了一個閥值,當判斷掛掉的服務的數量超過閥值時,Eureka Server認爲很大程度上出現了網絡故障,將不再刪除心跳過期的服務。
那這個閥值是多少呢?
Eureka Server在運行期間,會統計心跳失敗的比例在15分鐘之內是否低於85%。換句話就是:默認情況下啓用自我保留,啓用自我保留的默認閾值大於當前註冊表大小的15%。
關閉自我保護模式(生產上不建議)
server:
port: 8010
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8010/eureka/
# 關閉自我保護模式
server:
enable-self-preservation: false
spring:
application:
name: ms-discovery-eureka
健康檢查
引入 spring-boot-starter-actuator
<!--狀態監控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
開啓健康檢查
server:
port: 8012
spring:
application:
name: ms-consumer-user-v2
eureka:
client:
# 健康檢查
healthcheck:
enabled: true
service-url:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
查詢狀態
在開啓健康檢查後,應用程序可以將自己的健康狀態傳播到 Eureka Server。
REFERENCES
獲取更多
掃碼關注
架構探險之道
,回覆"源碼",獲取本文相關源碼
掃碼加入知識星球,獲取更多珍貴筆記、視頻、電子書的等資源。
在 Spring Cloud Edgware 以及高版本中,只需要添加相關依賴即可。 ↩︎