阅读导航
<b style="font-size: inherit;"><font color="#f15a23">注册中心 Eureka</font></b><br>
<b><font color="#0076b3">负载均衡 Ribbon + Feign </font></b>👉<br>
<b><font color="#0076b3">断路器 Hystrix</font></b> 👉
<font color="#0076b3"><b>服务网关 Gateway</b> </font>👉
服务注册与发现
使用注册中心管理每个服务与服务之间的依赖关系
服务 <b>提供者 </b>将自己暴露的地址注册到注册中心
服务 <b>消费者 </b>从注册中心拉取服务列表进行调用
注册表存储结构
采用内存的方式来管理服务信息
ConcurrentHashMap存储服务节点
服务注册:新增一个key-value的映射关系
服务发现:获取一个key-value的映射集合
提供服务的注册与发现,key存服务名,value服务地址
组成结构
三大角色:Eureka Server、Service Provider、Service Consumer
两个组件
Eureka Server:提供注册服务
Eureka Client
通过注册中心访问,客户端具备一个内置的使用轮询算法的负载均衡器
默认每30秒向注册中心发送心跳,超过90秒没有收到则移除节点
消费者获取调用地址后,底层使用HttpClient实现远程调用
服务注册与发现<br>是怎么实现的?
Eureka做了二级缓存
第一级叫做 ReadOnly 缓存,二级叫做 ReadWrite 缓存<br>客户端会直接从 ReadOnly 缓存中读取注册表信息<br>
ReadOnly缓存(定时同步)
ReadWrite缓存(立马同步)
定时任务会每30秒检查两个缓存的内容,不一致则将ReadWrite中的数据同步到ReadOnly
为什么要做二级缓存?
这么做的好处在于,<b>优化并发读写的冲突</b>
如果服务进行注册的时候,同时有服务来读去注册表信息,就会存在频繁的读写加锁的操作,<br>写的时候就不能读,导致性能下降,所以我们需要避免大量的读写都去操作一个表
有了二级缓存,大部分的读操作都会走 ReadOnly 缓存,只需要定时同步就好了
自我保护机制
心跳检测
在应用启动后,节点们将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳<br>周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
自我保护
但是如果短时间内丢失了大量的服务实例心跳(80%),Eureka会触发自我保护机制,不踢除服务。<br>防止由于暂时的网络问题误删除健康的服务,是一种应对网络异常的安全措施
CAP
属于CAP里的AP分支,宁可保留错误的服务注册信息,也不盲目的注销任何可能健康的服务实例
如何关闭自我保护?<br>改为CP模式(<b>不推荐</b>)
注册中心
eureka.server.enable-self-preservation: false
eureka.server.eviction-interval-timer-in-ms: 2000
服务端
eureka.instance.lease-renewal-interval-in-seconds: 1
心跳间隔(默认30)
eureka.instance.lease-espiration-duration-in-seconds: 2
超时时间(默认90)
如果Eureka不下<br>线服务怎么办?
手动通知Eureka下线
格式:DELETE /eureka/apps/appID/instanceID
DELETE 127.0.0.1:8761/eureka/apps/EUREKACLIENT1/192.168.10.104:paymentServer:8765
通过运行指定的代码下线
在EurekaClient的代码中添加一个接口
集群
Eureka集群节点之间相互注册,相互监听,peer to peer(点对点)
集群中每个机器的地位是对等的,各个服务可以向任何一个Eureka实例注册,<br>集群中的任何一个Eureka实例接收到写请求后都会自动同步到其他所有实例
对比ZooKeeper
Eureka保证的是AP
牺牲一致性,保证可用性和容错性
Eureka查到的信息可能不是最新的,但是每个节点都是平等的
ZooKeeper保证的是CP
牺牲可用性,保证一致性和容错性
服务down掉立即被踢出,master节点选举期间服务不可用