前言
Eureka:服務(wù)注冊與發(fā)現(xiàn)組件,用于實(shí)現(xiàn)服務(wù)的自動注冊與發(fā)現(xiàn),Spring Cloud Eureka 是對Netflix公司的Eureka的二次封裝,它實(shí)現(xiàn)了服務(wù)治理的功能,Spring Cloud Eureka提供服務(wù)端與客戶端,服務(wù)端即是Eureka服務(wù)注冊中心,客戶端完成微服務(wù)向Eureka服務(wù)的注冊與發(fā)現(xiàn)。服務(wù)端和客戶端均采用Java語言編寫。
Eureka作為初代的服務(wù)注冊和發(fā)現(xiàn)組件,其基本思想和原理對于后來的Nacos有深遠(yuǎn)的影響,在nacos中也能隱約看到其身影。
本篇博客介紹Eureka的簡介和原理,結(jié)合實(shí)際使用闡述Eureka的使用并進(jìn)行分析,此外,介紹了心跳續(xù)約策略,服務(wù)的下線和剔除以及自我保護(hù),還有Eureka集群的搭建方式。
git代碼倉庫:https://gitee.com/pet365/spring-cloud-eureka
引出
1.Eureka的簡介和原理;
2.結(jié)合實(shí)際使用闡述Eureka的使用并進(jìn)行分析;
3.介紹了心跳續(xù)約策略,服務(wù)的下線和剔除以及自我保護(hù);
4.Eureka集群的搭建方式,高可用;文章來源地址http://www.zghlxwxcb.cn/news/detail-752787.html
Eureka初識
Eureka架構(gòu)中的三個(gè)核心角色:
-
服務(wù)注冊中心
Eureka的服務(wù)端應(yīng)用,提供服務(wù)注冊和發(fā)現(xiàn)功能,就是剛剛我們建立的eureka-server。 -
服務(wù)提供者
提供服務(wù)的應(yīng)用,可以是SpringBoot應(yīng)用,也可以是其它任意技術(shù)實(shí)現(xiàn),只要對外提供的是Rest風(fēng)格服務(wù)即可。本例中就是我們實(shí)現(xiàn)的spring-provider。 -
服務(wù)消費(fèi)者
消費(fèi)應(yīng)用從注冊中心獲取服務(wù)列表,從而得知每個(gè)服務(wù)方的信息,知道去哪里調(diào)用服務(wù)方。本例中
就是我們實(shí)現(xiàn)的spring-consumer。
有趣故事
Eureka的故事來源于人人追求真善美的古希臘,“Eureka”是希臘語,意思是“我發(fā)現(xiàn)了!”
這個(gè)有魔力的單詞是來源于阿基米德。在公元前200多年,他在洗澡時(shí)發(fā)現(xiàn)了證明王冠是否純金的方法(黃金密度),他激動地一邊大喊“Eureka!”一邊跳出澡盆奔去王宮,連衣服都忘了穿。后來人們用Eureka這個(gè)詞來形容洞察浮現(xiàn)的瞬間。
SMS、庫存、積分服務(wù)器,服務(wù)遷移變更等需要修改相應(yīng)的URL地址,怎么不修改URL地址?
在微服務(wù)中,spring-provider對外提供服務(wù),需要對外暴露自己的地址。而consumer(調(diào)用者)需要記錄服務(wù)提供者的地址。將來地址出現(xiàn)變更,還需要及時(shí)更新。這在服務(wù)較少的時(shí)候并不覺得有什么,但是在現(xiàn)在日益復(fù)雜的互聯(lián)網(wǎng)環(huán)境,一個(gè)項(xiàng)目肯定會拆分出十幾,甚至數(shù)十個(gè)微服務(wù)。此時(shí)如果還人為管理地址,不僅開發(fā)困難,將來測試、發(fā)布上線都會非常麻煩
這就好比是 網(wǎng)約車出現(xiàn)以前,人們出門叫車只能叫出租車。一些私家車想做出租卻沒有資格,被稱為黑車。而很多人想要約車,但是無奈出租車太少,不方便。私家車很多卻不敢攔(沒有人告訴哪些車私家車可以拉人),而且滿大街的車,誰知道哪個(gè)才是愿意載人的。一個(gè)想要,一個(gè)愿意給,就是缺少引子,缺乏管理啊。
此時(shí)滴滴這樣的網(wǎng)約車平臺出現(xiàn)了,所有想載客的私家車全部到滴滴注冊,記錄你的車型(服務(wù)類型),身份信息(聯(lián)系方式)。這樣提供服務(wù)的私家車,在滴滴那里都能找到,一目了然。
此時(shí)要叫車的人,只需要打開APP,輸入你的目的地,選擇車型(服務(wù)類型),滴滴自動安排一個(gè)符合需求的車到你面前,為你服務(wù),完美!
Eureka做什么?
Eureka就好比是滴滴中心,負(fù)責(zé)管理、記錄服務(wù)提供者的信息。服務(wù)調(diào)用者無需自己尋找服務(wù),而是把自己的需求告訴Eureka,然后Eureka會把符合你需求的服務(wù)告訴你。
同時(shí),服務(wù)提供方與Eureka之間通過“心跳” 機(jī)制進(jìn)行監(jiān)控,當(dāng)某個(gè)服務(wù)提供方出現(xiàn)問題,Eureka自然會把它從服務(wù)列表中剔除。
這就實(shí)現(xiàn)了服務(wù)的自動注冊、發(fā)現(xiàn)、狀態(tài)監(jiān)控。
Eureka是啥?
Eureka簡介
Spring Cloud Eureka 是對Netflix公司的Eureka的二次封裝,它實(shí)現(xiàn)了服務(wù)治理的功能,Spring Cloud Eureka提供服務(wù)端與客戶端,服務(wù)端即是Eureka服務(wù)注冊中心,客戶端完成微服務(wù)向Eureka服務(wù)的注冊與發(fā)現(xiàn)。服務(wù)端和客戶端均采用Java語言編寫。
一個(gè)消費(fèi)者和一個(gè)生產(chǎn)者
多個(gè)消費(fèi)者與多個(gè)生產(chǎn)者
下圖顯示了Eureka Server與Eureka Client的關(guān)系
- Eureka Server是服務(wù)端,負(fù)責(zé)管理各個(gè)微服務(wù)結(jié)點(diǎn)的信息和狀態(tài)。
- 在微服務(wù)上部署Eureka Client程序,遠(yuǎn)程訪問Eureka Server將自己注冊在Eureka Server。
- 微服務(wù)需要調(diào)用另一個(gè)微服務(wù)時(shí)從Eureka Server中獲取服務(wù)調(diào)用地址,進(jìn)行遠(yuǎn)程調(diào)用。
原理
- 服務(wù)提供方啟動后將注冊到注冊中心,提供IP, 名字,什么服務(wù)等信息,
- 服務(wù)調(diào)用方作為客戶端注冊到注冊中心后,拉取注冊中心的服務(wù)列表,在通過負(fù)載均衡調(diào)用對應(yīng)的服務(wù)提供方。
- 注冊中心可以建立集群,生成多臺eureka,注冊中心為了監(jiān)測各個(gè)服務(wù)的心跳,將在每30S 向所注冊的服務(wù)發(fā)起請求判斷
- 服務(wù)是否掛掉,如果掛掉90S后將會將服務(wù)從注冊中心剔除。
- 一個(gè)服務(wù)可以監(jiān)測多臺服務(wù)實(shí)例,從而可實(shí)現(xiàn)均衡負(fù)載。
Eureka使用Hello案例
注冊中心Eureka
引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
eureka的配置文件
server:
port: 9001 # eureka默認(rèn)端口號為8761
eureka:
client:
# EurekaServer的地址,現(xiàn)在是自己的地址,如果是集群,需要加上其它Server的地址
service-url:
defaultZone: http://127.0.0.1:${server.port}/eureka
# 不把自己注冊到eureka服務(wù)列表
register-with-eureka: false
# 拉取eureka服務(wù)信息
fetch-registry: false #false表示自己就是注冊中心,不需要從注冊中心獲取注冊列表信息
instance:
#客戶端在注冊時(shí)使用自己的IP而不是主機(jī)名
prefer-ip-address: true
# 實(shí)例id
instance-id: ${spring.cloud.ip-address}:${spring.application.name}:${server.port}
logging:
level:
root: debug
配置說明:
register-with-eureka: false false表示不向注冊中心注冊自己
fetch-registry: false false表示自己就是注冊中心,不需要從注冊中心獲取注冊列表信息
service-url 設(shè)置eureka server交互的地址查詢服務(wù)和注冊服務(wù)都需要用到這個(gè)地址(單機(jī)用)
主啟動類
在eureka-server的主啟動類上開啟eureka服務(wù)**@EnableEurekaServer**
package com.tianju.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 聲明當(dāng)前springboot應(yīng)用是一個(gè)eureka服務(wù)中心
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class);
}
}
瀏覽器訪問
啟動eureka-server子項(xiàng)目,在瀏覽器上訪問localhost:9001
查看日志
搭建生產(chǎn)者Provider
引入依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 在provider的pom文件中添加監(jiān)控依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
配置yml文件
server:
port: 10010
eureka:
client: #客戶端注冊到eureka列表中
service-url:
defaultZone: http://127.0.0.1:9001/eureka
instance:
prefer-ip-address: true #顯示訪問url 客戶端在注冊時(shí)使用自己的IP而不是主機(jī)名
# # 實(shí)例id
# instance-id: ${spring.cloud.ip-address}:${spring.application.name}:${server.port}
instance-id: provider-10010 #注冊中心顯示出來的微服務(wù)名稱
# 應(yīng)用名稱
spring:
application:
name: springCloud-provider
info:
app.name: SpringCloud
company.name: tianju
build.artifactId: $project.artifactId$
build.version: $project.version$
主啟動類
package com.tianju.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient // 或 @EnableDiscoveryClient
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class);
}
}
@EnableEurekaClient和@EnableDiscoveryClient區(qū)別
在使用Spring Cloud feign使用中在使用服務(wù)發(fā)現(xiàn)的時(shí)候提到了兩種注解:
一種為@EnableDiscoveryClient;
一種為@EnableEurekaClient,用法上基本一致
spring cloud中discovery service有許多種實(shí)現(xiàn)(eureka、consul、zookeeper等等),
@EnableDiscoveryClient基于spring-cloud-commons;
@EnableEurekaClient基于spring-cloud-netflix。
其實(shí)用更簡單的話來說,就是如果選用的注冊中心是eureka,那么就推薦@EnableEurekaClient, 如果是其他的注冊中心,那么推薦使用@EnableDiscoveryClient。
注解@EnableEurekaClient上有@EnableDiscoveryClient注解,可以說基本就是EnableEurekaClient有@EnableDiscoveryClient的功能,另外上面的注釋中提到,其實(shí)@EnableEurekaClient注解就是一種方便使用eureka的注解而已,可以說使用其他的注冊中心后,都可以使用@EnableDiscoveryClient注解,但是使用@EnableEurekaClient的情景,就是在服務(wù)采用eureka作為注冊中心的時(shí)候,使用場景較為單一。
查看日志
修改配置信息,變成了20s
lease-renewal-interval-in-seconds: 20 #心跳時(shí)間
server:
port: 10010
eureka:
client: #客戶端注冊到eureka列表中
service-url:
defaultZone: http://127.0.0.1:9001/eureka
instance:
prefer-ip-address: true #顯示訪問url 客戶端在注冊時(shí)使用自己的IP而不是主機(jī)名
# # 實(shí)例id
# instance-id: ${spring.cloud.ip-address}:${spring.application.name}:${server.port}
instance-id: provider-10010 #注冊中心顯示出來的微服務(wù)名稱
lease-renewal-interval-in-seconds: 20 #心跳時(shí)間
lease-expiration-duration-in-seconds: 60 #下線時(shí)間
# 應(yīng)用名稱
spring:
application:
name: springCloud-provider
info:
app.name: SpringCloud
company.name: tianju
build.artifactId: $project.artifactId$
build.version: $project.version$
搭建消費(fèi)者consumer
引入依賴配置等雷同
注冊到eureka
主啟動類
package com.tianju.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
在生產(chǎn)端提供controller
在消費(fèi)端調(diào)用生產(chǎn)者
package com.tianju.consumer.controller;
import com.netflix.appinfo.InstanceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerController {
@Resource
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/getId/{id}")
public String getMsg(@PathVariable("id") String id) {
List<ServiceInstance> instances = discoveryClient.getInstances("springCloud-provider");
ServiceInstance instance = instances.get(0);
String host = instance.getHost();
int port = instance.getPort();
log.debug("消費(fèi)者拼出路徑+端口:"+ host+":"+port);
// 獲取ip和端口信息,拼接成服務(wù)地址
String baseUrl = "http://" + instance.getHost() + ":" +
instance.getPort() + "/provider/get/" + id;
String consumer = restTemplate.getForObject(baseUrl, String.class);
log.debug("采用restTemplate調(diào)用生產(chǎn)者:"+baseUrl);
return "消費(fèi)者調(diào)用生產(chǎn)者獲得消息:"+consumer;
}
}
心跳和續(xù)約策略
Eureka:就是服務(wù)注冊中心(可以是一個(gè)集群),對外暴露自己的地址
- 提供者:啟動后向Eureka注冊自己信息(地址,提供什么服務(wù))
- 消費(fèi)者:向Eureka訂閱服務(wù),Eureka會將對應(yīng)服務(wù)的所有提供者地址列表發(fā)送給消費(fèi)者,并且定期更新
- 心跳(續(xù)約):提供者定期通過http方式向Eureka刷新自己的狀態(tài)
常見概念
Register 服務(wù)注冊
當(dāng)Eureka客戶端向Eureka Server注冊時(shí),它提供自身的元數(shù)據(jù),比如IP地址、端口,運(yùn)行狀況指示符URL,主頁等。
Renew 服務(wù)續(xù)約(心跳機(jī)制)
Eureka客戶會每隔30秒發(fā)送一次心跳來續(xù)約。通過續(xù)約來告知Eureka Server該Eureka客戶仍然存在,沒有出現(xiàn)問題。正常情況下,如果Eureka Server在90秒沒有收到Eureka客戶的續(xù)約,它會將實(shí)例從其注冊表中刪除。建議不要更改續(xù)約間隔。
- 心跳機(jī)制是每隔30秒發(fā)送一個(gè)自定義的結(jié)構(gòu)體(心跳包),讓對方知道自己還活著,以確保連接的有效性的機(jī)制。
- 心跳機(jī)制是每隔30秒發(fā)送一個(gè)固定信息給服務(wù)端,服務(wù)端收到后回復(fù)一個(gè)固定的信息。如果服務(wù)端90秒內(nèi)沒有收到客戶端消息則視客戶端斷開。
- 發(fā)送方可以是客戶端或服務(wù)端,根據(jù)實(shí)際情況,一般是客戶端;因?yàn)橐粋€(gè)服務(wù)端可能有很多客戶端,服務(wù)端作為發(fā)送方的比較耗費(fèi)性能。
Fetch Registries 獲取注冊列表信息
Eureka客戶端從服務(wù)器獲取注冊表信息,并將其緩存在本地。客戶端會使用該信息查找其他服務(wù),從而進(jìn)行遠(yuǎn)程調(diào)用。該注冊列表信息定期(每30秒鐘)更新一次。每次返回注冊列表信息可能與Eureka客戶端的緩存信息不同, Eureka客戶端自動處理。如果由于某種原因?qū)е伦粤斜硇畔⒉荒芗皶r(shí)匹配,Eureka客戶端則會重新獲取整個(gè)注冊表信息。 Eureka服務(wù)器緩存注冊列表信息,整個(gè)注冊表以及每個(gè)應(yīng)用程序的信息進(jìn)行了壓縮,壓縮內(nèi)容和沒有壓縮的內(nèi)容完全相同。Eureka客戶端和Eureka 服務(wù)器可以使用JSON / XML格式進(jìn)行通訊。在默認(rèn)的情況下Eureka客戶端使用壓縮JSON格式來獲取注冊列表的信息。
服務(wù)的下線和剔除
Cancel 服務(wù)下線
Eureka客戶端在程序關(guān)閉時(shí)向Eureka服務(wù)器發(fā)送取消請求,發(fā)送請求后,該客戶端實(shí)例信息將從服務(wù)器的實(shí)例注冊表中刪除,該下線請求不會自動完成,它需要調(diào)用以下內(nèi)容:
DiscoveryManager.getInstance().shutdownComponent();
服務(wù)進(jìn)行正常關(guān)閉操作,會觸發(fā)一個(gè)服務(wù)下線的REST請求給Eureka Server,告訴服務(wù)注冊中心:“我要下線了”。服務(wù)中心接受到請求之后,將該服務(wù)置為下線狀態(tài)。
Eviction 服務(wù)剔除
在默認(rèn)的情況下,當(dāng)Eureka客戶端連續(xù)90秒沒有向Eureka服務(wù)器發(fā)送服務(wù)續(xù)約(心跳),Eureka服務(wù)器會將該服務(wù)實(shí)例從服務(wù)注冊列表刪除,即服務(wù)剔除。
有些時(shí)候,我們的服務(wù)提供方并不一定會正常下線,可能因?yàn)閮?nèi)存溢出、網(wǎng)絡(luò)故障等原因?qū)е路?wù)無法正常工作。Eureka Server需要將這樣的服務(wù)剔除出服務(wù)列表。因此它會開啟一個(gè)定時(shí)任務(wù),每隔60秒對所有失效的服務(wù)(超過90秒未響應(yīng))進(jìn)行剔除。
可以通過eureka.server.eviction-interval-timer-in-ms 參數(shù)對其進(jìn)行修改,單位是毫秒。
eureka:
server:
# 每隔多久(ms)觸發(fā)一次服務(wù)剔除
eviction-interval-timer-in-ms: 10000
自我保護(hù)
我們關(guān)停一個(gè)服務(wù),就會在Eureka面板看到一條警告:
這是觸發(fā)了Eureka的自我保護(hù)機(jī)制。當(dāng)一個(gè)服務(wù)未按時(shí)進(jìn)行心跳續(xù)約時(shí),Eureka會統(tǒng)計(jì)最近15分鐘心跳失敗的服務(wù)實(shí)例的比例是否超過了85%。在生產(chǎn)環(huán)境下,因?yàn)榫W(wǎng)絡(luò)延遲等原因,心跳失敗實(shí)例的比例很有可能超標(biāo),但是此時(shí)就把服務(wù)剔除列表并不妥當(dāng),因?yàn)榉?wù)可能沒有宕機(jī)。
Eureka就會把當(dāng)前實(shí)例的注冊信息保護(hù)起來,不予剔除。生產(chǎn)環(huán)境下這很有效,保證了大多數(shù)服務(wù)依然可用。
但是這給我們的開發(fā)帶來了麻煩, 因此開發(fā)階段我們都會關(guān)閉自我保護(hù)模式:(eureka-server)
eureka:
server:
enable-self-preservation: false # 如果為true,表示要保護(hù)實(shí)例,不被剔除,false關(guān)閉自我保護(hù)模式,剔除實(shí)例
eviction-interval-timer-in-ms: 10000 # 掃描失效服務(wù)的間隔時(shí)間(缺省為60*1000ms)
如果保護(hù)實(shí)例不被剔除,而且配置了 eviction-interval-timer-in-ms: 10000,則eviction-intervaltimer-in-ms參數(shù)為準(zhǔn),實(shí)例還是會被剔除
eureka:
server:
enable-self-preservation: true # 如果為true,表示要保護(hù)實(shí)例,不被剔除,false關(guān)閉自我保護(hù)模式,剔除實(shí)例
#eviction-interval-timer-in-ms: 10000 # 掃描失效服務(wù)的間隔時(shí)間(缺省為60*1000ms)
Eureka集群搭建
Eureka Server即服務(wù)的注冊中心,在剛才的案例中,我們只有一個(gè)EurekaServer,事實(shí)上EurekaServer也可以是一個(gè)集群,形成高可用的Eureka中心。
多個(gè)Eureka Server之間也會互相注冊為服務(wù),當(dāng)服務(wù)提供者注冊到Eureka Server集群中的某個(gè)節(jié)點(diǎn)時(shí),該節(jié)點(diǎn)會把服務(wù)的信息同步給集群中的每個(gè)節(jié)點(diǎn),從而實(shí)現(xiàn)數(shù)據(jù)同步。
因此,無論客戶端訪問到Eureka Server集群中的任意一個(gè)節(jié)點(diǎn),都可以獲取到完整的服務(wù)列表信息。
允許多個(gè)實(shí)例
1.啟動第一個(gè)
所謂的高可用注冊中心,其實(shí)就是把EurekaServer自己也作為一個(gè)服務(wù)進(jìn)行注冊,這樣多個(gè)EurekaServer之間就能互相發(fā)現(xiàn)對方,從而形成集群。因此我們做了以下修改:把service-url的值改成了另外一臺EurekaServer的地址,而不是自己。
先啟動一個(gè)
啟動報(bào)錯(cuò),很正常。因?yàn)榱硪粋€(gè)服務(wù)沒有啟動
2.再啟動一個(gè)
啟動第二個(gè)eurekaServer,再次修改eureka-server的配置
再啟動一個(gè)
3.訪問集群
集群效果
4.客戶端注冊
因?yàn)镋urekaServer不止一個(gè),因此注冊服務(wù)的時(shí)候,service-url參數(shù)需要變化:
5.注冊效果
文章來源:http://www.zghlxwxcb.cn/news/detail-752787.html
總結(jié)
1.Eureka的簡介和原理;
2.結(jié)合實(shí)際使用闡述Eureka的使用并進(jìn)行分析;
3.介紹了心跳續(xù)約策略,服務(wù)的下線和剔除以及自我保護(hù);
4.Eureka集群的搭建方式,高可用;
到了這里,關(guān)于Eureka(服務(wù)注冊和發(fā)現(xiàn))——Eureka的簡介和原理 & Eureka的使用和分析 & 心跳續(xù)約策略,服務(wù)的下線和剔除,自我保護(hù) & Eureka集群的搭建的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!