1. 概念
注冊中心:
- 需求:當(dāng)一個(gè)服務(wù)提供者 Service 部署了多個(gè)實(shí)例交給 User 遠(yuǎn)程調(diào)用時(shí):
- 服務(wù)消費(fèi)者 User 應(yīng)該調(diào)用哪個(gè)實(shí)例,如何獲取其對應(yīng)地址和端口?
- User 如何獲知實(shí)例是否健康?
- 注冊中心作用:
- 幫助管理服務(wù),并幫助服務(wù)調(diào)用者選擇并調(diào)用服務(wù)
- 實(shí)時(shí)監(jiān)測服務(wù)實(shí)例是否健康
Eureka:
- 構(gòu)成:
- eureka-server:服務(wù)端,注冊中心
記錄服務(wù)信息,心跳監(jiān)控 - eureka-client:客戶端,
服務(wù)提供者(注冊到服務(wù)端,定期向服務(wù)端發(fā)送心跳)、服務(wù)消費(fèi)者(從服務(wù)端拉取服務(wù)列表,基于負(fù)載均衡選擇服務(wù))
- eureka-server:服務(wù)端,注冊中心
- 作用:
- 服務(wù)注冊: Service實(shí)例啟動(dòng)后,會(huì)將自己的信息注冊到 eureka服務(wù)端
- 服務(wù)拉?。?/strong> User 根據(jù) 實(shí)例名 獲取 Service 地址列表
- 負(fù)載均衡: User 根據(jù)負(fù)載均衡算法 從 拉去的 Service 地址列表中 選擇一個(gè)服務(wù)實(shí)例
- 心跳檢查: Service實(shí)例 每隔一段時(shí)間(默認(rèn)30s)就會(huì)向 eureka服務(wù)端 發(fā)起請求,報(bào)告自己的狀態(tài),當(dāng)超過一段時(shí)間沒向 eureka服務(wù)端 發(fā)送心跳,eureka 就會(huì)將此實(shí)例從 地址列表中剔除
nacos
- 概念:
- 服務(wù)注冊中心
- 作用:
-
心跳檢查: 不同于 eureka 只能 Service實(shí)例 主動(dòng)發(fā)起心跳,nacos 對于非臨時(shí)實(shí)例可以主動(dòng)發(fā)起心跳檢查
- 臨時(shí)心跳檢查異常的會(huì)被剔除出 服務(wù)地址列表
- 非臨時(shí)心跳檢查異常的不會(huì)被剔除
- 定時(shí)推送變更: nacos 支持服務(wù)列表變更的消息推送模式,服務(wù)列表更新更及時(shí)
-
心跳檢查: 不同于 eureka 只能 Service實(shí)例 主動(dòng)發(fā)起心跳,nacos 對于非臨時(shí)實(shí)例可以主動(dòng)發(fā)起心跳檢查
2. Eureka
1. 服務(wù)搭建
1. 依賴導(dǎo)入
依賴:
-
springboot 與 springcloud 的版本對應(yīng)關(guān)系
點(diǎn)擊圖片跳轉(zhuǎn) -
父項(xiàng)目依賴
我用的是2.6.11版本的springboot,所以要選擇2021.0.5版本的springcloud<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring.cloud-version>2021.0.5</spring.cloud-version> </properties> <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>
-
子項(xiàng)目依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
2. 配置文件
我們需要將 eureka 注冊到spring容器中,所以需要在配置文件中做相關(guān)配置。
server:
port: 8099
spring:
application:
name: eureka_server
eureka:
client:
# 配置eureka服務(wù)地址
service-url:
defaultZone: http://127.0.0.1:8099/eureka
3. 啟動(dòng)項(xiàng)目
為了讓項(xiàng)目能啟動(dòng) eureka,需要在啟動(dòng)類上加一個(gè)注解:@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
啟動(dòng)項(xiàng)目,訪問地址:http://127.0.0.1:8099:
注冊的服務(wù)名稱就是配置文件中的名稱的大寫。
2. 服務(wù)注冊
在上一步,已經(jīng)將 eureka-server (eureka服務(wù)中心)搭建完畢,現(xiàn)在就開始注冊服務(wù)實(shí)例了。
1. 依賴導(dǎo)入
注意:
-
無論是 服務(wù)提供者 還是 服務(wù)消費(fèi)者,他們的身份都是 eureka-client
-
記得添加 spring-boot-starter-web 的依賴,不然會(huì)報(bào)錯(cuò):Field optionalArgs in org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration required a bean of type ‘com.netflix.discovery.AbstractDiscoveryClientOptionalArgs’ that could not be found.
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
服務(wù)發(fā)現(xiàn)、服務(wù)注冊統(tǒng)一都封裝在eureka-client依賴。
2. 配置文件
需要在配置文件中配置 eureka-server 的地址。
spring:
application:
name: service_provider
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8099/eureka
3. 啟動(dòng)多個(gè)實(shí)例
為了讓項(xiàng)目能啟動(dòng) eureka,需要在啟動(dòng)類上加一個(gè)注解:@EnableEurekaClient。
@SpringBootApplication
@EnableEurekaClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
我們可以通過 IDEA 自帶功能模仿啟動(dòng)多個(gè)服務(wù)實(shí)例。
-
打開 Service 面板
-
復(fù)制原來的 provider 啟動(dòng)配置
-
查看 eureka注冊中心
3. 服務(wù)發(fā)現(xiàn)
1. 依賴導(dǎo)入
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. 配置文件
配置文件:
spring:
application:
name: service_user
server:
port: 8084
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8099/eureka
3. 服務(wù)拉取和負(fù)載均衡
服務(wù)拉取:
-
修改 controller 代碼,將 url 路徑的 ip、端口 修改為 服務(wù)名:
@RestController @RequestMapping("user") public class UserController { @Autowired private RestTemplate restTemplate; @GetMapping("/{id}") public Book getBookById(@PathVariable("id") Integer id) { // String url = "http://127.0.0.1:8081/provider" + id; String url = "http://service_provider/provider"; if (id != null) { url = url + id; } Book book = restTemplate.getForObject(url, Book.class); return book; } }
-
注冊 RestTemplate 的時(shí)候加上注解 @LoadBalanced
@LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); }
-
接口調(diào)用:
@RestController @RequestMapping("user") public class UserController { @Autowired private RestTemplate restTemplate; @GetMapping("/{id}") public Book getBookById(@PathVariable("id") Integer id) { // String url = "http://127.0.0.1:8081/provider" + id; String url = "http://PROVIDER/pro/"; if (id != null) { url = url + id; } Book book = restTemplate.getForObject(url, Book.class); return book; } }
-
訪問接口:
訪問報(bào)錯(cuò):
解決方案: 命名別帶下劃線。
多測試幾下接口,可以發(fā)現(xiàn),user一會(huì)兒調(diào)用的是 provider:8081 一會(huì)兒調(diào)用的是 provider:8082。這就是負(fù)載均衡算法選擇的。
4. 小結(jié)
eureka-server 搭建:
-
引入依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
-
啟動(dòng)類添加 @EnableEurekaServer
-
配置文件配置 eureka 地址
server: port: 8099 spring: application: name: server eureka: client: # 配置eureka服務(wù)地址 service-url: defaultZone: http://127.0.0.1:8099/eureka
服務(wù)注冊:
- 引入依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
- 啟動(dòng)類添加 @EnableEurekaClient
- 配置文件配置 eureka 地址
server: port: 8081 spring: application: name: provider eureka: client: # 配置eureka服務(wù)地址 service-url: defaultZone: http://127.0.0.1:8099/eureka
服務(wù)發(fā)現(xiàn):
- 引入依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
- 啟動(dòng)類添加 @EnableEurekaClient
- 配置文件配置 eureka 地址
server: port: 8089 spring: application: name: user eureka: client: # 配置eureka服務(wù)地址 service-url: defaultZone: http://127.0.0.1:8099/eureka
3. Ribbon
1. 負(fù)載均衡流程
Ribbon負(fù)載均衡流程圖:
http://PROVIDER/pro/4 并非真實(shí)的地址,這個(gè)需要Ribbon負(fù)載均衡去攔截,然后選擇具體的服務(wù)地址。而,Ribbon就是通過 LoadBalancerInterceptor 的 intercept 方法來實(shí)現(xiàn)攔截請求并解析選擇地址。
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
負(fù)載均衡流程:
2. 負(fù)載均衡策略
Ribbon的負(fù)載均衡策略是由 IRule 接口來定義的。
IRule常見規(guī)則:
內(nèi)置負(fù)載均衡規(guī)則類 | 規(guī)則描述 |
---|---|
RoundRobinRule | 簡單輪詢服務(wù)列表來選擇服務(wù)器。它是Ribbon默認(rèn)的負(fù)載均衡規(guī)則。 |
AvailabilityFilteringRule | 對以下兩種服務(wù)器進(jìn)行忽略: (1)在默認(rèn)情況下,這臺(tái)服務(wù)器如果3次連接失敗,這臺(tái)服務(wù)器就會(huì)被設(shè)置為“短路”狀態(tài)。短路狀態(tài)將持續(xù)30秒,如果再次連接失敗,短路的持續(xù)時(shí)間就會(huì)幾何級(jí)地增加。 (2)并發(fā)數(shù)過高的服務(wù)器。如果一個(gè)服務(wù)器的并發(fā)連接數(shù)過高,配置了AvailabilityFilteringRule規(guī)則的客戶端也會(huì)將其忽略。并發(fā)連接數(shù)的上限,可以由客戶端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit屬性進(jìn)行配置。 |
WeightedResponseTimeRule | 為每一個(gè)服務(wù)器賦予一個(gè)權(quán)重值。服務(wù)器響應(yīng)時(shí)間越長,這個(gè)服務(wù)器的權(quán)重就越小。這個(gè)規(guī)則會(huì)隨機(jī)選擇服務(wù)器,這個(gè)權(quán)重值會(huì)影響服務(wù)器的選擇。 |
ZoneAvoidanceRule (默認(rèn)) | 以區(qū)域可用的服務(wù)器為基礎(chǔ)進(jìn)行服務(wù)器的選擇。使用Zone對服務(wù)器進(jìn)行分類,這個(gè)Zone可以理解為一個(gè)機(jī)房、一個(gè)機(jī)架等。而后再對Zone內(nèi)的多個(gè)服務(wù)做輪詢。 |
BestAvailableRule | 忽略那些短路的服務(wù)器,并選擇并發(fā)數(shù)較低的服務(wù)器。 |
RandomRule | 隨機(jī)選擇一個(gè)可用的服務(wù)器。 |
RetryRule | 重試機(jī)制的選擇邏輯 |
自定義負(fù)載均衡策略:
-
方式一: 在user中,@Bean 注入自定義 IRule
@Bean public IRule randomRule(){ return new RandomRule(); }
-
方式二: 在user,配置文件修改 IRule
provider: # 給某個(gè)微服務(wù)配置負(fù)載均衡規(guī)則,這里是userservice服務(wù) ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負(fù)載均衡規(guī)則
注意: 方式一的作用范圍是:在訪問任何微服務(wù)的時(shí)候,都是使用 RandomRule 負(fù)載均衡策略;方式二的作用范圍是:在訪問 provider 微服務(wù)的時(shí)候才是采用 RandomRule 策略,其他的還是使用默認(rèn)策略。
3. 加載策略
Ribbon默認(rèn)采用懶加載,即會(huì)在第一次訪問時(shí)才會(huì)去創(chuàng)建 LoadBalanceClient ,所以會(huì)在第一次請求的時(shí)候花上較長的等待時(shí)間。
可以通過配置文件更改加載策略為餓加載策略,即初始化時(shí)就創(chuàng)建 LoadBalanceClient ,降低第一次訪問的耗時(shí)。
ribbon:
eager-load:
enabled: true # 開啟饑餓加載
clients: provider # 指定饑餓加載的服務(wù)名稱
4. Nacos
1. 下載安裝
Nacos下載地址: https://github.com/alibaba/nacos/releases

下載好之后,解壓就行了。
默認(rèn)端口: 8848 ,可通過 conf/application.properties 的 server.port 修改端口。
單擊啟動(dòng): bin/
-
方式一:雙擊 startup.cmd
-
方式二:
startup.cmd -m standalone
登錄:默認(rèn)賬號(hào)、密碼都是 nacos 。
2. 注冊中心
1. 引入依賴、修改配置
父工程添加 SpringCloudAlibaba 的管理依賴。
<!--spring-cloud-alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
子工程中注釋掉 eureka 依賴,引入 nacos 依賴。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置文件配置nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服務(wù)地址
啟動(dòng) user 和 provider :
注意: eureka 注冊名會(huì)變成大寫,nacos 不會(huì),所以改成 nacos 之后,需要把訪問地址改成小寫。
請求測試:
2. 服務(wù)分級(jí)存儲(chǔ)模型
一個(gè)服務(wù)可以擁有多個(gè)實(shí)例,如:provider 的 8081 和 8082,如果這些實(shí)例分布于全國不同的機(jī)房,如:provider:8081 在成都機(jī)房、provider:8082 在重慶機(jī)房,Nacos就將同一機(jī)房內(nèi)的實(shí)例 劃分為一個(gè)集群。
即,一個(gè)服務(wù)可以擁有多個(gè)集群,一個(gè)集群中可以擁有多個(gè)實(shí)例。
微服務(wù)相互之間訪問時(shí),訪問本地的速度更快,所以應(yīng)該盡可能訪問相同集群的實(shí)例,只有當(dāng)本集群內(nèi)存不夠時(shí),才去訪問其他集群。
1. 配置集群
配置服務(wù)集群:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服務(wù)地址
discovery:
cluster-name: CD
VM Options:
-Dserver.port=8082 -Dspring.cloud.nacos.discovery.cluster-name=CQ

2. 同集群優(yōu)先的負(fù)載均衡
默認(rèn)的 ZoneAvoidanceRule 負(fù)載均衡策略并不能實(shí)現(xiàn)據(jù)同集群優(yōu)先來實(shí)現(xiàn)負(fù)載均衡,因此Nacos中提供了一個(gè)NacosRule
的實(shí)現(xiàn),可以優(yōu)先從同集群中挑選實(shí)例。
修改負(fù)載均衡策略:
-
方式一:
@Bean public IRule nacosRule(){ return new NacosRule(); }
-
方式二:
provider: # 訪問的服務(wù)名 ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 負(fù)載均衡規(guī)則
3. 權(quán)重配置
服務(wù)器的性能之間存在差異,為了讓性能能好的服務(wù)器承擔(dān)更多的用戶請求,Nacos提供了權(quán)重配置來控制訪問率:權(quán)重越大、訪問率越高。
注意: 權(quán)重為0的服務(wù)永遠(yuǎn)不會(huì)被訪問。
4. 環(huán)境隔離
Nacos提供了namespace來實(shí)現(xiàn)環(huán)境隔離功能。
- nacos中可以有多個(gè)namespace
- namespace下可以有g(shù)roup、service等
- 不同namespace之間相互隔離(不同namespace的服務(wù)互相不可見)
1. 創(chuàng)建 namespace
Nacos默認(rèn)的namespace是:public 。
Nacos創(chuàng)建命名空間流程:
2. 配置命名空間
spring:
cloud:
nacos:
discovery:
namespace: e11eb3bc-8eed-4cdd-93f0-7a6c01b85eb4 # 命名空間,填I(lǐng)D

注意: 因?yàn)榇藭r(shí) dev 命名空間中只有 user,導(dǎo)致無法訪問到 public 中的 provider ,發(fā)起訪問請求會(huì)報(bào)錯(cuò)。
3. 永久實(shí)例
Nacos的服務(wù)實(shí)例分為兩種類型:
-
臨時(shí)實(shí)例:如果實(shí)例宕機(jī)超過一定時(shí)間,會(huì)從服務(wù)列表剔除,默認(rèn)的類型
-
非臨時(shí)實(shí)例:如果實(shí)例宕機(jī),不會(huì)從服務(wù)列表剔除,也可以叫永久實(shí)例
臨時(shí)實(shí)例是實(shí)例向注冊中心發(fā)起心跳,永久實(shí)例是注冊中心主動(dòng)向?qū)嵗儐栃奶?/p>
spring:
cloud:
nacos:
discovery:
ephemeral: false # 設(shè)置為永久實(shí)例
3. 配置管理
Nacos不僅可以擔(dān)任微服務(wù)的注冊中心,還可以擔(dān)任配置管理。
1. 統(tǒng)一配置管理
可以使用統(tǒng)一配置管理來處理因?yàn)椴渴鸬奈⒎?wù)數(shù)量過多,配置繁雜等問題。
Nacos一方面可以將配置集中管理,另一方可以在配置變更時(shí),及時(shí)通知微服務(wù),實(shí)現(xiàn)配置的熱更新。
注意: 只把那些需要熱更新的配置文件交給Nacos
1. nacos添加配置文件
Data ID: 配置文件id:服務(wù)名稱-profile.后綴名 。
2. 從nacos拉取配置
spring引入了一種新的配置文件:bootstrap.yaml文件,會(huì)在application.yml之前被讀取,流程如下:
-
引入nacos-config依賴:
<!--nacos配置管理依賴--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
添加bootstrap.yml
spring: application: name: user # 服務(wù)名稱 profiles: active: dev #開發(fā)環(huán)境,這里是dev cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后綴名
這里會(huì)根據(jù)spring.cloud.nacos.server-addr獲取nacos地址,再根據(jù)
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作為文件id,來讀取配置。 -
讀取nacos配置
@Value("${pattern.dateformat}") private String dateformat; @GetMapping("now") public String now() { return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); }
啟動(dòng)報(bào)錯(cuò): org.springframework.beans.factory.BeanCreationException: Error creating bean with name xxx
解決方案:
- 檢查 namespace,配置文件與服務(wù)要在同一個(gè) namespace 中
- 名稱是否拼錯(cuò)
- 升級(jí) nacos 版本
- @Value 切換為 @NacosValue
2. 配置熱更新
配置熱更新: 修改nacos中的配置后,微服務(wù)中無需重啟即可讓配置生效。
實(shí)現(xiàn)方式:
- 方式一: 在@Value注入的變量所在類上添加注解 @RefreshScope
-
方式二:
- 使用 @ConfigurationProperties 注解代替@Value注解
- 在 user 服務(wù)中,添加一個(gè)類,讀取patterrn.dateformat屬性:
@Component @Data @ConfigurationProperties(prefix = "pattern") public class PatternProperties { private String dateformat; }
- 在UserController中使用這個(gè)類代替@Value:
@Autowired private PatternProperties patternProperties; @GetMapping("now") public String now() { return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat)); }
3. 配置共享
其實(shí)微服務(wù)啟動(dòng)時(shí),會(huì)去nacos讀取多個(gè)配置文件,因?yàn)閚acos管理的配置文件不包含環(huán)境信息,可以被多個(gè)環(huán)境共享。
只需要取名的時(shí)候,不加上 profile 就能被共享,如下:文章來源:http://www.zghlxwxcb.cn/news/detail-521295.html

配置共享時(shí)的優(yōu)先級(jí):文章來源地址http://www.zghlxwxcb.cn/news/detail-521295.html
到了這里,關(guān)于微服務(wù)(二)——注冊中心(Eureka、Nacos)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!