Eureka
服务注册
常用注册中心
技术 | 协议 | AOP | pull/push | 存储 | |
---|---|---|---|---|---|
Eureka | AP(为了保证Eureka挂了,服务之间还能同行) | long polling(长轮询) | 非持久化存储 | ||
Consul | raft协议(redis-sentinel / nacos选举) | long polling(长轮询) | |||
Zookeeper | zab协议(paxos算法的衍生) | CP | |||
Etcd | raft协议 | long polling(长轮询) | |||
Nacos | raft协议 | long polling(长轮询) |
Eureka Client 发起服务注册
Eureka Client发起服务注册时,有两个地方会执行服务注册的任务:
1. 在Spring Boot启动时,由于自动装配机制将Cloud Eureka Client注入到了容器,并且执行了构造方法,而在构造方法中有一个定时任务每40s会执行一次判断,判断实例信息是否发生了变化,如果是则会发起服务注册的流程。
2. 在Spring Boot启动时,通过refresh方法,最终调用StatusChangeListener.notify进行服务状态变更的监听,而这个监听的方法受到事件之后会去执行服务注册。
Eureka Server收到请求之后的处理
Eureka Server 会把客户端的地址信息保存到ConcurrentHashMap中存储。并且服务提供者和注册中心之间,会建立一个心跳检测机制。
请求入口在: com.netflix.eureka.resources.ApplicationResource.addInstance() 。
这里所提供的REST服务,采用的是jersey来实现的。
在 addInstance 方法中,最终调用的是 PeerAwareInstanceRegistryImpl.register 方法。
1. 当服务端超过90s(租约过期时间)没有收到客户端的心跳,则主动剔除该节点。
2. 调用super.register发起节点注册
3. 将信息复制到Eureka Server集群中的其他机器上,同步的实现也很简单,就是获得集群中的所有节点,然后逐个发起注册
自我保护机制
运行期间,心跳失败的比例15分钟内低于85%的服务,Eureka Server 会将这些实例保护起来,让这些实例不过期(本应被剔除),减少网络不稳定/网络分区的情况下,Eureka Server 将健康服务剔除下线的 问题。
Eureka Server 进入自我保护状态后,
1. Eureka Server不再从注册列表中移除过期服务(长时间没有收到心跳而应该剔除的)
2. Eureka Server仍能接受新服务的注册和查询请求,但是不会被同步到其他节点上,保证当前节点依然可用。
默认开启(不建议关闭)
eureka.server.enable-self-preservation=false // 关闭保护机制
eureka.server.wait-time-in-ms-when-sync-empty=10000 // 修改判定时间10S,默认5分钟,
缺陷
在保护期内,如果服务刚好非正常下线了,此时服务消费者就会拿到一个无效的服务实例,调用失败。所以需要服务消费者端要有一些容错机制,如重试,断路器等。
三级缓存
Eureka Server存在三个变量:(registry、readWriteCacheMap、readOnlyCacheMap)保存服务注册信息。
默认情况下定时任务
1. 每30s将readWriteCacheMap同步至readOnlyCacheMap,
2. 每60s清理超过90s未续约的节点,
3. Eureka Client每30s从readOnlyCacheMap更新服务注册信息,而客户端服务的注册则从registry更新服务注册信息。
多级缓存的意义
当大规模的服务注册和更新时,如果只修改一个ConcurrentHashMap数据,那势必因为锁的存在导致竞争,影响性能。Eureka又是AP模型,只需要满足最终可用就行。所以用多级缓存实现读写分离。
注册方法写的时候直接写内存注册表,写完表之后主动失效读写缓存。
获取注册信息接口,读取顺序:只读缓存 -> 读写缓存 -> 内存注册表里(不只是取,此处较复杂)。并且读写缓存会更新回写只读缓存
responseCacheUpdateIntervalMs : readOnlyCacheMap 缓存更新的定时器时间间隔,默认为30秒
responseCacheAutoExpirationInSeconds : readWriteCacheMap 缓存过期时间,默认为 180 秒 。
服务注册的缓存失效
在AbstractInstanceRegistry.register方法的最后,会调用invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress()); 方法,使得读写缓存失效。
定时同步缓存
ResponseCacheImpl的构造方法中,会启动一个定时任务,这个任务会定时检查写缓存中的数据变
化,进行更新和同步。
续约
服务续约,其实就是一种心跳检查机制。客户端会定期发送心跳来续约。