1. 简介
所谓服务注册中心就是在整个的微服务架构中单独提出一个服务(本身也是一个服务),这个服务不完成系统的任何的业务功能,仅仅用来完成对整个微服务系统的服务注册和服务发现,以及对服务健康状态的监控和管理功能(以及服务元数据信息存储,如服务的IP和端口)。
目录
# 服务注册中心
- 可以对所有的微服务的信息进行存储,如微服务的名称、IP、端口等
- 可以在进行服务调用时通过服务发现查询可用的微服务列表及网络地址进行服务调用
- 可以对所有的微服务进行心跳检测,如发现某实例长时间无法访问,就会从服务注册表移除该实例(健康状态管理)
常用服务注册中心
- Eureka (Netflix)
- Zookeeper (Java)
- Consul (Go)
- Nacos (Alibaba)
这些注册中心在本质上都是用来管理服务的注册和发现以及服务状态的检查的。
2. Eureka
- Eureka是Netflix开发的服务发现框架,SpringCloud将它集成在其子项目spring-cloud-netflix中,实现SpringCloud的服务注册和发现功能
- Eureka包含两个组件:Eureka Server(服务端,服务注册中心)和Eureka Client(客户端,需要被注册的服务)
2.0 版本
Eureka 1.0 还在大规模的生产实践中
Eureka 2.0 Discontinued,不再维护
2.1 Eureka Server
开发server服务端
-
创建子项目springcloud_01_eureka_server -
pom.xml引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
-
application.properties配置文件 # eureka server默认端口号即8761
server.port=8761
# 指定服务名称 唯一标识,注意:服务名不能出现下划线,默认服务名不区分大小写,但是推荐大写
spring.application.name=EUREKASERVER
# eureka server 服务注册中心的地址 暴露服务地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
-
创建入口类,开启Eureka Server,入口类加入注解 @SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
-
登陆 localhost:8761 查看
# 虽然能看到管理界面为什么项目启动控制台报错?(见3.2 Eureka Server细节)
- 出现上述问题原因:eureka组件包含 eurekaserver 和 eurekaclient。server是一个服务注册中心,用来接受客户端的注册。client的特性会让当前启动的服务把自己作为eureka的客户端进行服务中心的注册,当项目启动时服务注册中心还没有创建好,所以找不到服务的客户端组件就直接报错了,当启动成功服务注册中心创建好了,日后client也能进行注册,就不再报错啦!
Eureka Server细节
-
如果在Server端发现了application名字为UNKNOWN ,说明该服务没有起名字。在微服务项目中,服务名称至关重要,必须唯一;服务名称不能出现下划线 -
在Eureka Server 启动过程中会报错: com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
原因:Eureka 含有两个组件Eureka Server 和Eureka Client 组件,当项目中引入Eureka Server 组件时,这个组件会同时将Eureka Client 引入到项目中,因此启动时,不仅会将自己作为一个服务中心启动,同时也会将自己作为服务客户端进行注册,默认启动时立即注册,注册时服务还没有准备完成,因此会出现当前错误。 -
如何让Eureka Server 关闭Eureka client 的立即注册,并且自己不会出现在服务列表中,同时解决上面的报错,在注册中心的配置文件: # 关闭eureka client立即注册
eureka.client.fetch-registry=false
# 让当前应用仅仅是服务注册中心
eureka.client.register-with-eureka=false
如此,启动时不会再报错,并且在Eureka的服务注册列表中也不会再出现自己
2.2 Eureka Client
eureka client其实就是一个微服务,只是在server服务端眼里,所有微服务都是client客户端
开发client客户端
流程和开发server几乎一模一样
-
创建子项目springcloud_02_eureka_client -
pom.xml引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
-
application.properties配置文件 server.port=8989
spring.application.name=EUREKACLIENT
# 指定服务注册中心地址(server端暴露的服务地址)
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
-
创建入口类,开启Eureka Client,入口类加入注解 @SpringBootApplication
@EnableEurekaClient
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
-
测试:先启动server端,再启动client,client会去server端注册,登陆 localhost:8761 :
2.3 Eureka自我保护机制
问题与原因
核心:“宁可信其有不可信其无”。保护的对象是***“服务列表”***。
# 问题:服务频繁启动时 EurekaServer出现错误
- 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.
# 原因:自我保护机制
- 官网地址: https://github.com/Netflix/eureka/wiki/Server-Self-Preservation-Mode
- 默认情况下(没有自我保护机制),如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例;开启自我保护机制情况下,当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
- Eureka Server在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期。这种设计的哲学原理就是"宁可信其有不可信其无!"。自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
举例:
如果此时用户服务集群的一台服务器宕机,在有eureka自我保护机制的情况下,server端不会立即更新用户服务的集群的ip list,进而也不会立即提醒商品服务进行相关更新。
确保灾难性的网络事件(网络异常波动)不会清楚eureka注册表数据,并将其传播到下游的所有客户端。
现象
在自我保护模式下,eureka服务器将停止逐出所有实例,直到:
- 心跳次数高于阀值
- 自我保护模式禁用
设置/关闭
自我保护机制默认开启。
在eureka server端可关闭该机制:
# 关闭自我保护
eureka.server.enable-self-preservation=false
# 超时3s自动清除
eureka.server.eviction-interval-timer-in-ms=3000
但是注意关闭后,服务宕机依然不会很快清除,原因是还有***心跳机制***,所以想要达到“一宕机就清除”,还需要修改缩短心跳时间
#用来修改eureka server默认接受心跳的最大时间 默认是90s
eureka.instance.lease-expiration-duration-in-seconds=10
#指定客户端多久向eureka server发送一次心跳 默认是30s
eureka.instance.lease-renewal-interval-in-seconds=5
# 尽管如此关闭自我保护机制还是会出现警告
- THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
- `官方并不建议在生产情况下关闭
2.4 Eureka集群
如果要实现服务注册中心的高可用,只需要做集群。集群就是多个运行eureka软件的节点,节点之间相互发现对方,相互注册。
搭建
以创建3个Eureka server节点的集群作为例子,步骤:
-
创建3个springboot项目 -
引入eureka server依赖 -
配置文件application.properties node1 server.port=8761
eureka.client.service-url.defaultZone=http://localhost:8762/eureka,http://localhost:8763/eureka
node2 server.port=8762
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8763/eureka
node3 server.port=8763
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka
-
3个节点的入口类添加注解@EnableEurekaServer
另一种更便捷的启动集群的方式是:
- 用IDEA复制项目
- 每次启动一个节点时,手动修改一下注册地址
- 启动时从传入port参数,覆盖项目自己的port
详细步骤查看:
【编程不良人】2021年最新SpringCloud微服务实战教程
搭建完成后,服务注册到任意一个集群下的节点,这个服务数据就会被同步并注册在三个节点里,也就是集群中。但是客户端的服务只注册到一个节点并不好,如果该服务端节点宕机那么客户端的服务就会注册失败。所以在保护服务端高可用的同时,还应保护客户端的高可用,所以应该给客户端把集群所有的节点的注册地址都写上,这样客户端会随机选择一台节点注册自己。
client集群和server集群搭建方式一样,可以修改他们的port,但是服务名必须一致!
2.5 不推荐使用
- 最新版本停止更新
- 每次必须手动通过代码的方式开发创建一个服务注册中心
3. Consul
3.1 简介
consul是一个可以提供服务发现,健康检查,多数据中心,Key/Value存储等功能的分布式服务框架,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,使用起来也较为简单。Consul用Golang实现,因此具有天然可移植性(支持Linux、Windows和Mac OS X);安装包仅包含一个可执行文件,方便部署。
3.2 安装
Mac consul 安装与启动
需要拷贝到/usr/local/bin :
sudo cp consul /usr/local/bin
根据安装目录进行环境变量配置
测试:
(base) ? ~ consul -v
Consul v1.11.2
Revision 37c7d06b
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
启动:
consul agent -dev
访问consul的web服务端口8500(consul服务默认端口):
http://localhost:8500
UI界面:
dc1:数据中心名称(data center);指定数据中心启动:consul agent -dev -datacenter=name
servicesL:当前注册的服务列表;默认:consul server启动时会注册自己,出现一个consul服务
nodes:用来查看consul集群
3.3 Consul客户端
开发consul 客户端即微服务
这里以学习为目的,不考虑业务,所以取名为"consul client"
-
创建子项目springcloud_03_consul_client -
引入依赖 <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
</dependencies>
-
application.properties 配置文件 server.port=8889
spring.application.name=CONSULCLIENT8889
# consul server 服务注册地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
# 指定当前注册的服务的服务名,默认引用:spring.application.name
spring.cloud.consul.discovery.service-name=${spring.application.name}
-
在入口类添加注解 @SpringBootApplication
@EnableDiscoveryClient
public class ConsulClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulClientApplication.class, args);
}
}
注意:@EnableDiscoveryClient 注解,Spring会看注册中心使用的是什么组件,比如consul, zookeeper(eureka除外,他有自己的@EnableEurekaClient ),就会把这个服务作为什么注册中心的client。所以这是一个通用的服务注册客户端注解 。 -
启动consul client:
3.4 健康检查
上一节,启动后会发现刚刚的服务不可用,原因:consul server会检测所有客户端心跳,而发送心跳时,客户端必须给予相应,该服务才能正常使用。在现有的客户端中,我们并没有引入健康检查的依赖,所以导致健康检查始终不能通过,导致服务不能正常使用。
该检查默认开启,可以关闭,但不建议。
想要client可以给予相应,只需要引入健康检查依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
刷新项目,重新启动,服务就能通过健康检查,正常使用。
3.5 (没有)自我保护机制
与Eureka不同,Consul的client只要宕机,服务中心就会很快把客户端从服务列表中剔除。
|