注册中心
文章目录
1. 服务注册中心基础
-
注册中心
注册中心可以说是微服务架构中的通讯录,记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其他服务时,就这这里找服务的地址进行调用
-
主要作用(功能)
- 服务发现
- 服务注册/反注册:保存服务提供者和服务调用者的信息
- 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
- 服务路由(可选):具有筛选整合服务提供者的能力
- 服务配置
- 配置订阅:服务提供者和服务调用者订阅微服务相关的配置
- 配置下发:主动将配置推送给服务提供者和服务调用者
- 服务健康检测
- 检测服务提供者的健康情况
- 服务发现
-
常见的注册中心
-
Zookeeper
文件系统 + 监听通知机制。主要用来解决分布式应用中经常遇到的数据管理问题
-
Eureka
基于Java、Restful ApI开发的服务注册与发现组件
-
Consul
基于GO语言开发的支持多数据中心分布式高可用的服务发布和组册服务软件,采用Raft算法保证服务的一致性,且支持健康检查,三个主要应用场景:服务发现、服务隔离、服务配置。
-
Nacos
更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。是注册中心 + 配置中心的组合,提供简单易用的特性集,帮助我们解决微服务开发必会设计到的服务注册与发现、服务配置、服务管理等问题
组件名 语言 CAP 一致性算法 服务健康检查 对外暴露接口 Zookeeper Java CP Paxos 支持 客户端 Eureka Java AP 无 可配支持 Http Consul Go CP Raft 支持 Http/DNS Nacos Java AP Raft 支持 Http -
2. Eureka
目前Eureka1版本的源码Netflix公司已经不再维护,Eureka2版本已经宣布闭源。
2.1. 基础架构
- Eureka Server
- 提供服务注册和发现
- Service Provider
- 服务提供方
- 将自身服务注册到Eureka,从而使服务消费方能够找到
- Service Consumer
- 服务消费方
- 从Eureka获取注册服务列表,从而能够消费服务
2.2. 交互过程与原理
-
服务提供方
- 在服务启动时,使用Eureka Client工具包,向Eureka Server发送注册信息
- Eureka Server接收到注册信息后将这些信息保存在内存中
- 服务提供方使用Eureka Client工具包,默认每隔30秒向Eureka Server发送心跳
- 当默认超过90秒后Eureka Server接收不到这个Eureka Client发送的心跳后,就将此服务提供方的注册信息从内存中删除
-
服务消费方
- 在服务启动时,使用Eureka Client工具包,从Eureka Server获取注册信息,并将其缓存到内存中
- 服务消费方使用服务提供方的服务时,从内存中获取注册信息,进行调用
2.3. 使用Eureka的步骤
-
搭建Eureka Server
- 依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
- 配置:
server: port: 8000 eureka: instance: hostname: localhost #主机地址名称 client: register-with-eureka: false #是否将自己注册到注册中心 fetch-registry: false #是否从注册中心中获取注册信息 service-url: #配置暴露给Eureka Client的请求地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 启动类激活Eureka Server
@EnableEurekaServer
- 访问Eureka Server 控制台
http://localhost:8000
-
将服务提供者注册到Eureka Server上
- 依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
- 配置:
eureka: client: service-url: #Eureka Server的地址 defaultZone: http://localhost:8000/eureka/ instance: prefer-ip-address: true #使用IP地址注册
- 启动类激活Eureka Client
@EnableEurekaClient
或
@EnableDiscoveryClient
-
服务消费者通过注册中心获取服务列表,并调用
Eureka的元数据:已经注册的服务信息(服务的主机名、IP等),或者是一些配置信息。
-
依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
-
配置
eureka: client: service-url: #Eureka Server的地址 defaultZone: http://localhost:8000/eureka/ instance: prefer-ip-address: true #使用IP地址注册
-
启动类激活Eureka Client
@EnableEurekaClient
或
@EnableDiscoveryClient
-
注入DiscoveryClient(Spring Cloud提供的获取元数据的工具类)
@Autowired private DiscoveryClient discoveryClient;
-
调用工具类中的方法,获取元数据
List<ServiceInstance> instances = discoveryClient.getInstance("服务提供者的服务名称"); ServiceInstance instance = instances.get(0); String ip = instance.getHost(); // 服务提供者的主机地址 String port = instance.getPort(); // 服务提供者的端口号
-
2.4. Eureka Server的高可用集群
-
说明
因Eureka Server在整个系统中起着纽带作用,若Eureka Server宕机,则会致使整个系统不可用,所以需要搭建Eureka Server的高可用集群。服务提供者可以向集群中的多个Eureka Server节点注册信息,服务消费者也可以从任意一个Eureka Server节点上获取元数据,集群中的多个Eureka Server节点可以相互注册,进行信息的同步,即互为备份。
-
搭建Eureka Server高可用集群的步骤
-
准备多个Eureka Server,需要相互注册
修改Eureka Server的配置:
server: port: 8000 eureka: instance: hostname: localhost #主机地址名称 client: register-with-eureka: true #是否将自己注册到注册中心 fetch-registry: true #是否从注册中心中获取注册信息 service-url: #配置另外一台Eureka Server的URL defaultZone: http://另外一台Eureka Server的IP:9000/eureka/
增加另一个Eureka Server:
server: port: 9000 eureka: instance: hostname: localhost #主机地址名称 client: register-with-eureka: true #是否将自己注册到注册中心 fetch-registry: true #是否从注册中心中获取注册信息 service-url: #配置另外一台Eureka Server的URL defaultZone: http://另外一台Eureka Server的IP:8000/eureka/
-
需要将服务注册到多个Eureka Server上
修改Eureka Client的配置:
eureka: client: service-url: #Eureka Server的地址,多个Eureka Server地址之间用逗号隔开 defaultZone: http://localhost:8000/eureka/,http://localhost:9000/eureka/ instance: prefer-ip-address: true #使用IP地址注册
-
2.5. Eureka Server 的其他细节问题
-
Eureka Server控制台显示各个服务的IP
-
Eureka Client中配置服务ID,采用服务IP:Port的形式
eureka: instance: instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心注册服务Id
-
-
Eureka的服务剔除问题
Eureka Client会每隔30秒向Eureka Server发送心跳,同时通知Eureka Server若超过90秒没有接收到心跳,就说明Eureka Client已经宕机,这时Eureka Server会从服务列表中剔除此Eureka Client的注册信息。
-
Eureka Client中修改发送心跳时间间隔和续约到期时间(正式上线阶段推荐使用默认值,不要修改)
eureka: instance: lease-renewal-interval--in-seconds: 30 #默认每隔30秒发送心跳 lease-expiration-duration-in-seconds: 90 #默认续约到期时间为90秒
-
-
Eureka的自我保护机制
当Eureka Server超过Eureka Client的续约到期时间还没有接收到心跳,并不会立刻去剔除注册信息,而是会统计15分钟以内所有的Eureka Client的心跳未接收到的比率是否超过85%,若超过了85%,Eureka就会进入自我保护机制,不再会去剔除注册列表中的任何信息。
-
Eureka Server中关闭自我保护机制和缩短剔除服务的时间间隔(开发阶段提高开发效率,正式上线阶段推荐使用默认值,不要修改)
eureka: server: enable-self-preservation: false #关闭自我保护机制 eviction-interval-timer-in-ms: 4000 #剔除服务的时间间隔,单位:毫秒
-
2.6. Eureka源码解析
-
Spring Boot中的自动装载
-
ImportSelector接口
ImportSelector接口是Spring导入外部配置的核心接口,在Spring Boot的自动化配置和@EnableXXX(功能性注解)中起到了决定性的作用
-
自动装载
启动类中的
@SpringBootApplication
注解,包含@EnableAutoConfiguration
注解,此注解中使用@Import({AutoConfigurationImportSelector.class})
注解加入了AutoConfigurationImportSelector
接口,自动执行了selectImports()
方法,这个方法中加载了很多自定义的配置和所有SpringBoot中META_INFO/spring.factories
的配置,spring.factories中包含了很多外部的配置类,这些配置类中包含了很多外部的对象,即只要启动类启动,就会把这些外部的对象都自动装载到Spring容器中。
-
-
Eureka Server的源码解析
根据SpringBoot的自动装载机制,找到Eureka Server的jar包中的spring.factories中配置的EurekaServerAutoConfiguration配置类:里面包含EurekaController(配合Eureka Server的控制台页面完成相关功能)、jerseyApplication(jersey相关的配置,自动扫描"com.netflix.discovery"和"com.netflix.eureka"这两个包里面@Path、@Provider、@Produces注解等内容,将这些内容发布上一个一个的web接口,让Eureka Client进行调用)
3. Consul
3.1. Consul概述
Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置,与其他分布式服务注册与发现的方案相比,Consul的方案更加“一站式”,内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具,使用起来也较为简单,Console使用Go语言编写,因此具有天然可移植性(支持Linux、windows、Mac);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。
-
Consul与Eureka的区别
-
一致性
Console强一致性(CP):服务注册相比Eureka会慢一些,因为Consul的Raft协议要求必须过半数的节点都写入成功才认为注册成功;Leader挂掉时,重新选举期间整个Consul不可用,保证了强一致性但牺牲了可用性。
Eureka保证高可用和最终一致性(AP):服务注册相对要快,因为不需要等待信息replicate到其他节点,也不保证注册信息是否replicate成功;当数据出现不一致时,虽然多个节点上的注册信息不完全一致,但每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求一个节点查不到,但请求另一个节点就能查到,如此保证了可用性,但牺牲了一致性。
-
开发语言和使用
Console是Go语言编写,安装启动即可
Eureka就是个servlet程序,跑在servlet容器中
-
-
Consul的环境
启动Consul
consul agent -dev -client=0.0.0.0 # agent 启动一个Consul的守护进程 # -dev 以开发者模式启动 # -client=0.0.0.0 允许所有ip地址访问
管理后台界面,Consul管理控制台的默认端口号:8500
http://ip:8500
-
Spring Cloud对Consul进行了进一步的处理,向其中集成了对Ribbon的支持
3.2. Consul的服务注册与发现
-
将服务提供者注册到Consul注册中心
-
添加依赖
<!--Spring Cloud提供的对基于Consul的服务发现的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <actifactId>spring-cloud-starter-consul-discovery</actifactId> </dependency> <!--actuator的健康检查--> <dependency> <groupId>org.springframework.boot</groupId> <actifactId>spring-boot-starter-actuator</actifactId> </dependency>
-
添加配置
spring: cloud: consul: host: 127.0.0.1 #Consul服务器(Consul client)的IP地址 port: 8500 #Consul服务器(Consul client)的端口号 discovery: #是否需要注册 register: true #注册的实例ID,为一个唯一标识,示例使用: 服务名-ip-port 的形式 instance-id: ${spring.application.name}-${spring.cloud.client.ip-address}-{server.port} #服务的名称 service-name: ${spring.application.name} #服务的请求端口 port: {server.port} #指定开启IP地址注册 prefer-ip-address: true #当前服务的请求IP ip-address: ${spring.cloud.client.ip-address}
-
-
服务消费者从Console注册中心中获取注册信息
-
添加依赖
<!--Spring Cloud提供的对基于Consul的服务发现的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <actifactId>spring-cloud-starter-consul-discovery</actifactId> </dependency> <!--actuator的健康检查--> <dependency> <groupId>org.springframework.boot</groupId> <actifactId>spring-boot-starter-actuator</actifactId> </dependency>
-
添加配置
spring: cloud: consul: host: 127.0.0.1 #Consul服务器(Consul client)的IP地址 port: 8500 #Consul服务器(Consul client)的端口号 discovery: #是否需要注册 register: false #注册的实例ID,为一个唯一标识,示例使用: 服务名-ip-port 的形式 instance-id: ${spring.application.name}-${spring.cloud.client.ip-address}-{server.port} #服务的名称 service-name: ${spring.application.name} #服务的请求端口 port: {server.port} #指定开启IP地址注册 prefer-ip-address: true #当前服务的请求IP ip-address: ${spring.cloud.client.ip-address}
-
3.3. Consul的高可用集群
-
核心概念
-
agent 中的模式
-
dev : 开发者模式
-
client : 是Consul代理,主要目的是和Consul Server进行交互。
建议一个微服务对应一个client,并且微服务和client部署到同一个机器上,即让微服务和client组成一个整体,微服务把信息交给client,client通过内部RPC的方式将信息发送给server,让server进行统一的调度。
-
server : 处理任务的Consul服务
官方建议一般3-5台,增加的越多,会导致数据同步的越慢。
client 和 server 共同组成了Consul的集群。
-
-
Gossip协议(流言协议)
Consul client和server之间内部传播信息的协议。一个节点上的数据,随机向集群中的另外一个节点发送数据,然后这两个节点再次随机向另外的节点发送数据,依次进行下去,进行数据的扩散,即类似于流感的传播。
所有的Consul节点都会参与到Gossip协议中,进行多节点中数据的复制。
-
Reft协议(分布式中保持一致性的算法)
保证Consul server集群的数据一致性,包含3个角色。
- Leader : 是server集群中唯一处理客户端请求的服务,以及将数据同步到Follower中(同一时刻系统中只存在一个Leader)
- Follower : 选民,被动接收数据
- Candidate : 候选人, Follower中的一个节点,可以被选举为Leader
整个流程
- 选主:多个Follower节点中的一个作为Candidate节点,向其他所有的Follower节点发送数据,询问是否可以作为Leader节点,其他的Follower节点进行回复,当都同意请求后,Candidate节点将成为Leader节点。
- 数据同步:Leader节点接收到客户端的数据后,同时向所有的Follower节点发送这份数据,当所有的Follower节点回复Leader节点接收到数据后,才通知客户端数据接收成功了,Leader节点会再次向所有的Follower节点发送数据进行同步。
-
-
集群搭建
-
server 启动
# 节点1 以server形式运行 consul agent -server -bootstrap-expect 3 -data-dir /usr/local/consul.d -node=server-1 -bind=192.168.0.1 -ui -client 0.0.0.0 & # 节点2 以server形式运行 consul agent -server -bootstrap-expect 2 -data-dir /usr/local/consul.d -node=server-2 -bind=192.168.0.2 -ui -client 0.0.0.0 & # 节点3 以server形式运行 consul agent -server -bootstrap-expect 2 -data-dir /usr/local/consul.d -node=server-3 -bind=192.168.0.3 -ui -client 0.0.0.0 & # -server : 以server身份运行 # -bootstrap-expect : 集群要求的最少server数量,当低于这个数量,集群即失效 # -data-dir : data存放的路径 # -node : 节点ID,在同一集群下不能重复 # -bind : 监听的IP地址 # -ui : 开启web管理的页面 # -client : 客户端的IP地址(0.0.0.0表示不限制) # & 在后台运行
-
client 启动及加入集群
# 节点1 以client形式运行 consul agent -client=0.0.0.0 -bind=192.168.1.1 -data-dir /usr/local/consul.d -node=client-1
-
加入集群
# 选定一个server节点,将其他节点都加入到这个server上,构成一个集群 # 在其他所有的节点上执行加入命令: consul join 192.168.0.1 # 192.168.0.1 选定一个server节点的监听IP地址
-
查看集群信息
consul members
-
-
常见问题
-
节点和服务注销
当服务或节点失效,Consul不会对注册的信息进行剔除,仅仅对状态进行标记为不可用,如果担心失效节点和失效服务过多影响监控,可以调用HTTP API的方式进行处理:
注销任意节点和服务:/catelog/deregister
注销当前节点和服务:/agent/service/deregister/:service_id
如果某个节点不继续使用了,也可以在本机使用 consul leave 命令,或者在其他节点使用 consul force-leave 节点ID 命令注销。
-
健康检查与故障转移
在集群环境下,健康检查是由服务注册到的Agent来处理的,那么如果这个Agent挂了,那么此节点的健康检查就处于无人管理的状态。
从实际应用来看,节点上的服务可能既要被发现,又要发现别的服务,如果节点挂掉了,仅提供被发现服务的功能实际上服务还是不可用的,当然发现别的服务也可以不使用本机节点,可以通过访问一个Nginx实现的若干Consul节点的负载均衡来实现。
-