【SpringCloud】Eureka服務註冊與發現
Eureka服務註冊與發現
Eureka基礎知識
什麼是服務治理
Spring Cloud封裝了Netlix公司開發的Eureka模組來實現服務治理
在傳統的rpc遠端呼叫框架中,管理每個服務與服務之間依賴關係比較複雜,管理比較複雜,所以需要使用服務治理,管理服務於服務之間依賴關係,可以實現服務呼叫、負載均衡、容錯等,實現服務發現與註冊。
什麼是服務註冊與發現
Eureka採用了CS的設計架構,Eureka Server作為服務註冊功能的伺服器,它是服務註冊中心。而系統中的其他微服務,使用Eureka的客戶端連線到Eureka Server並維持心跳連線。這樣系統的維護人員就可以通過Eureka Server來監控系統中各個微服務是否正常執行。
Eureka兩元件
Eureka包含兩個元件: Eureka Server和Eureka Client
- Eureka Server提供服務註冊服務
各個微服務節點通過配置啟動後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務登錄檔中將會儲存所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀看到。 - EurekaClient通過註冊中心進行訪問
是一個Java客戶端,用於簡化Eureka Server的互動,客戶端同時也具備-個內建的、 使用輪詢(round-robin)負載演算法的負載均衡器。在應用啟動後,將會向Eureka Server傳送心跳(預設週期為30秒)。 如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將 會從服務登錄檔中把這個服務節點移除(預設90秒)
單機Eureka構建步驟
IDEA生成EurekaServer端服務註冊中心# 類似物業公司
建Module
cloud-eureka-server7001
改POM
<dependencies> <!--eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-common</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--一般為通用配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
1.x和2.x的對比說明
寫YML
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服務端的例項名稱
client:
# false表示不向註冊中心註冊自己
register-with-eureka: false
# false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要檢索服務
fetch-registry: false
service-url:
# 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
# 單機 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 相互註冊
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
主啟動
@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
測試
http://localhost:7001/
結果頁面
No application available沒有服務被發現
因為沒有註冊服務進來當前不可能有服務被發現
EurekaClient端cloud-provider-payment8001 將註冊進EurekaServer成為服務提供者provider,類似於尚矽谷學校對外提供授課服務
建Module
cloud-provider-payment8001
改POM
新增該eureka-client元件
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
寫YML
新增
eureka:
client:
#表示是否將自己註冊進EurekaServer預設為true
register-with-eureka: true
#是否從EurekaServer抓取已有的註冊訊息,預設為true,單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
主啟動
@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
測試
先要啟動EurekaServer
http://localhost:7001/
微服務註冊名配置說明
自我保護機制
EurekaClient端cloud-consumer-order80 將註冊進EurekaServer成為服務消費者consumer,類似於尚矽谷學校上課消費的各位同學
建Module
cloud-consumer-order80
改POM
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
寫YML
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
#表示是否將自己註冊進EurekaServer預設為true
register-with-eureka: true
#是否從EurekaServer抓取已有的註冊訊息,預設為true,單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
主啟動
@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
測試
先要啟動EurekaServer 7001服務
再啟動服務提供者provider 8001服務
eureka伺服器
http://localhost/consumer/payment/get/31
bug
failed to bind properties under 'eureka.client.service-url' to java.util.Map
叢集Eureka構建步驟
Eureka叢集原理說明
解決辦法: 搭建Eureka註冊中心叢集,實現負載均衡+故障容錯
Eureka叢集環境構建步驟
參考cloud-eureka-server7001
新建cloud-eureka-server7002
改POM
修改對映配置
找到C:\Windows\System32\drivers\etc路徑下的hosts檔案
修改對映配置新增hosts檔案
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
修改原因:主機名一個名字(127.0.0.1)還能叫叢集嗎。
重新整理hosts檔案
ipconfig /flushdns
寫YMl(以前單機)
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服務端的例項名稱
client:
# false表示不向註冊中心註冊自己
register-with-eureka: false
# false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要檢索服務
fetch-registry: false
service-url:
# 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
# 單機 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 相互註冊
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
7001
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服務端的例項名稱
client:
# false表示不向註冊中心註冊自己
register-with-eureka: false
# false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要檢索服務
fetch-registry: false
service-url:
# 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
# 單機 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 相互註冊
defaultZone: http://eureka7002.com:7002/eureka/
7002
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服務端的例項名稱
client:
# false表示不向註冊中心註冊自己
register-with-eureka: false
# false表示自己端就是註冊中心,我的職責就是維護服務例項,並不需要檢索服務
fetch-registry: false
service-url:
# 設定與Eureka Server互動的地址查詢服務和註冊服務都需要依賴這個地址
# 單機 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 相互註冊
defaultZone: http://eureka7001.com:7001/eureka/
主啟動
將支付服務8001微服務釋出到上面2臺Eureka叢集配置中
YAML
eureka:
client:
#表示是否將自己註冊進EurekaServer預設為true
register-with-eureka: true
#是否從EurekaServer抓取已有的註冊訊息,預設為true,單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
fetch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
將訂單服務80微服務釋出到上面2臺Eureka叢集配置中
YML,一樣的修改
測試01
先要啟動EurekaServer,7001/7002服務
再要啟動服務提供者provider,8001
再要啟動消費者,80
http://localhost/consumer/payment/get/31
支付服務提供者8001叢集環境搭建
參考cloud-provider-payment8001
新建cloud-provider-payment8002
改POM
YAML
server:
port: 8002
spring:
application:
name: cloud-payment-service8002
datasource:
# 當前資料來源操作型別
type: com.alibaba.druid.pool.DruidDataSource
# mysql驅動類
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com/eureka,http://eureka7002.com/eureka
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities
主啟動
業務類
直接從8001粘
修改8001/8002的controller
8001
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@PostMapping(value="/payment/create")
public CommonResult create(@RequestBody Payment payment) {
int result = paymentService.create(payment);
log.info("****插入結果:" + result);
if(result > 0){
return new CommonResult(200,"插入資料庫成功,serverPort: " + serverPort,result);
} else {
return new CommonResult(444,"插入資料庫失敗",null);
}
}
@GetMapping(value="/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
Payment payment = paymentService.getPaymentById(id);
log.info("****插入結果:" + payment);
if(payment != null){
return new CommonResult(200,"查詢成功,serverPort: " + serverPort,payment);
} else {
return new CommonResult(444,"沒有對應記錄,查詢ID: " + id,null);
}
}
}
8002
主要是在log.info中列印埠號,驗證負載均衡
取消IDEA中重複程式碼提示
File -> Setting -> Inspections -> General -> Duplicated Code 設定為不打勾√即可。
負載均衡
bug
訂單服務訪問地址不能寫死
使用服務名訪問http://CLOUD-PAYMENT-SERVICE
public class OrderController {
// public static final String PAYMENT_URL = "http://localhost:8001";
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
使用@LoadBalanced註解賦予RestTemplate負載均衡的能力
ApplicationContextBean
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
測試02
先要啟動EurekaServer,7001/7002服務
再要啟動服務提供者provider,8001/8002服務
http://localhost/consumer/payment/get/31
結果
- 負載均衡效果達到
- 8001/8002埠交替出現
Ribbon和Eureka整合後Consumer可以直接呼叫服務而不用再關心地址和埠號,且該服務還有負載功能了。
actuator微服務資訊完善
主機名稱:服務名稱修改
當前問題
修改cloud-provoder-payment8001
yaml
效果
訪問資訊有IP資訊提示
當前問題
沒有IP提示
修改cloud-provoder-payment8001
YAML
效果圖
服務發現Discovery
對於註冊eureka裡面的微服務,可以通過服務發現來獲得該服務的資訊
修改cloud-provider-payment8001的Controller
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/payment/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("*****element:" + service);
}
List< ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info(instance.getServiceId()+"\t" + instance.getHost() +
"\t" + instance.getPort() +"\t" + instance.getUri());
}
return this.discoveryClient;
}
8001的啟動類
@EnableDiscoveryClient
自測
先要啟動EurekaServer
再啟動8001主啟動類,需要稍等一會
http://localhost:8001/payment/discovery
效果圖
eureka自我保護
故障現象
概述
保護模式主要用於一組客戶端和Eureka Server之間存在網路分割槽場景下的保護。一旦進入保護模式。
Eureka Server將會嘗試保護其服務登錄檔中的資訊,不再刪除服務登錄檔中的資料,也就是不會登出任何微服務。
如果在Eureka Server的首頁看到以下這段提示,則說明Eureka進入了保護模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.
RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
導致原因
為什麼會產生Eureka自我保護機制?
為了防止EurekaClient可以正常執行,但是與EurekaServer網路不通情況下,EurekaServer不會立刻將EurekaClient服務剔除
什麼是自我保護模式?
預設情況下,如果EurekaServer在一定時間內沒有 接收到某個微服務例項的心跳, EurekaServer將 會登出該例項(預設90秒)。但是當網路分割槽故障發生(延時、卡頓、擁擠)時,微服務與EurekaServer之間無法正常通訊,以上行為可能變得非常危險了一因為微服務本身其實是健康的,此時本不應該登出這個微服務。Eureka通過“自我保護模式”來解決這個問題——當EurekaServer節點在短時間內丟失過多客戶端時(可能發生了網路分割槽故障),那麼這個節點就會講入自我保護模式。
一句話:某時刻一個微服務不可用了,Eureka不會立刻清理,依舊會對該服務的資訊進行儲存
屬於CAP裡面的AP分支
怎麼禁止自我保護
註冊中心eurekaServer端7001
出產預設,自我保護機制是開啟的
eureka.server.enable-self-preservation=true
使用eureka.server.enable-self-preservation=false 可以禁用自我保護模式
關閉效果
在eurekaServer端7001處設定關閉自我保護機制
生產者客戶端eurekaClient端8001
預設
eureka.instance.lease-renewal-interval-in-seconds=30
Eureka客戶端向服務端傳送心跳的時間間隔,單位為秒(預設是30秒)
eureka.instance.lease-expiration-duration-in-seconds=90
Eureka服務端在收到最後一次心跳後等待時間上限 ,單位為秒(預設是90秒),超時剔除服務
配置
Eureka服務端
eureka:
server:
#關閉自我保護模式,保證不可用服務被及時刪除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
服務消費者 Payment
eureka:
client:
#表示是否將自己註冊進EurekaServer預設為true
register-with-eureka: true
#是否從EurekaServer抓取已有的註冊訊息,預設為true,單節點無所謂,叢集必須設定為true才能配合ribbon使用負載均衡
fetch-registry: true
service-url:
#叢集版
#defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
#單機版
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: payment8001
prefer-ip-address: true #訪問路徑可以顯示ip
#Eureka客戶端向服務端傳送心跳的實際間隔,單位為秒(預設為30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服務端收到最後一次心跳後等待時間上線,單位為秒(預設為90秒) 超時將剔除服務
lease-expiration-duration-in-seconds: 2
測試
7001和8001都配置成功
先啟動7001再啟動8001
先關閉8001
馬上被刪除了