1.微服务为什么要使用服务发现与注册?eureka 的工作原理是什么?和 zookeeper 的区别是什么
使用服务发现与注册可以:
- 屏蔽、解耦服务之间的相互依赖的细节
服务之间的远程调用需要知道对方的 IP、端口等信息,若是在调用方使用硬编码的方式直接配置依赖存在明显的问题,若服务方 IP、端口等发生变化,或服务扩容,则调用方也要同步调整修改
- 对微服务进行动态的管理
微服务架构中,服务众多,服务之间的依赖关系错综复杂,无论是服务的主动停止、意外下线、还是因为流量增加对服务实现进行扩容等,这些服务数据或状态上的动态变化,都需要尽快的通知到调用。
因此,服务注册与发现要实时管理服务的数据状态,管理服务的注册上线、服务主动下限、异常服务的踢出
eureka 的工作原理:
- eureka server 启动成功后,等待服务端的注册;如果配置了集群,集群间定时通过 replicate 同步注册表信息
- eureka client 启动时根据配置的 eureka server 地址去注册中心注册服务,eureka client 会先发送一个心跳数据到服务端,若服务端返回响应状态 404 表明不存在该客户端服务信息,就向服务端发起注册请求
- eureka client 会定时(默认 30 秒)向 eureka server 发送一次心跳请求,证明客户端服务正常
- eureka server 若在某个周期内(默认 90 秒)内没有收到 eureka client 的 心跳,注册中心则会认为该节点失效,会注销该实例 但是在微服务场景下,服务之间通过都是跨进程调用,网络通信往往面临着各种问题,如服务状态正常,网络分区故障导致服务实例被注销。因此 eureka server 有自我保护机制,来保证服务的可用行,避免错杀
- 如果开启了自我保护,那么所有服务,包括长时间没有收到心跳的服务都不会被踢出
- 如果未开启自我保护机制,那么将判断最后一分钟收到的心跳数与每分钟收到的心跳数临界值比较,若每分钟心跳数临界值大于 0 并且最后一分钟收到的心跳数大于每分钟收到的心跳数的临界值,则启用租约到期机制,开始剔除服务
- 一旦服务剔除机制开启,eureka server 端并不会直接剔除所有已过期的服务,而是通过随机数的方式进行剔除,避免自我保护开启之前将所有的服务包括正常服务给剔除
- 每分钟内收到的心跳数临界值 = 客户端数量 * (60 / 心跳间隔_默认30)* 心跳百分比阈值_默认0.85
- eureka 进入自我保护机制,不再从注册表剔除过期未续约服务;仍然能够接受新服务的注册和查询请求,但是不会同步到其他 server 节点上;等到网络稳定时,当前实例新注册的信息会被同步到其他节点中;当客户端心跳恢复时,eureka server会自动退出自我保护机制
- eureka client 会定时全量或增量从注册中心获取服务注册表,并将获取到的信息缓存到本地,每次拉取后刷新本地已保存的信息,需要使用时直接从本地获取
- eureka client 程序关闭时向 eureka server 发送取消请求,eureka server 将实例从注册表中删除
和 zookeeper 的区别:
CAP 理论:
consistency 一致性:所有节点在同一时间的数据完全一致
availability 可用性:服务在正常响应时间内一直可用
partition tolerance:分区容错性:分布式系统再遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务
- eureka 是基于 ap 的,zookeeper 是基于 cp 的
- zookeeper 当 master 节点以为网络故障与其他节点失去联系事,剩余节点会重新进行 master 节点的选举,选举的时间太长 30 ~ 120 秒,且选举期间整个 zk 集群都是不可用的
2. ribbon 是什么?工作原理和负载策略
主流的负载方案分为两种
- 集中式负载:在服务的消费方和提供方之间使用独立的 lb 设施,由该设施负责把访问请求通过某种策略转发到服务的提供方
- 进程内负载:将 lb 逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中通过某种策略选择出一个合适的服务器
ribbon 属于进程内负载,丰富的组件库,包含七种负载策略,适配性好,eureka、feign、gateway、zuul、hystrix 都集成了 ribbon
七种负载策略:
- RandomRule -- 随机算法实现,随机选择
- RoundRobinRule -- 轮询负载策略,依次轮询所有的可用服务器列表,遇到第一个可用的即返回
- RetryRule -- 先按照 RoundRobinRule 策略获取服务,如果获取服务失败会在指定时间内重试
- AvaliabilityFilteringRule -- 过滤掉那些因为一直连接失败的被标记为 circuit tripped 的服务,并过滤掉那些 active connections 超过配置阈值的服务
- BestAvaliableRule -- 会过滤掉由于多次访问故障二次处于断路器跳闸状态的服务,然后选在一个并发量最小的服务
- WeightedResponseTimeRule -- 根据响应时间分配一个 weight,响应时间越长,weight 越小,被选中的可能性越低
- ZoneAvoidanceRule -- 复合判断 server 所在区域的性能和可用性来选择
ribbon 主要通过两种模式进行工作:IPing 和 IRule,IPing 是 ribbon 的一套 health check 机制,检查目标机器是否在线;IRule 是 Ribbon 的组件库,各种负载策略都是继承或间接继承自 IRule 接口,所有经过 ribbon 的请求都会先请示 IRule 一把,找到负载均衡策略选定的目标机器,然后再把请求转发出去
nginx 是集中式负载,客户端将所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发
ribbon 是进程内负载,通过获取注册中心的服务列表,在本地实现负载均衡策略
3. Fegin 的工作原理
主程序入口 添加了 @EnableFeignClients 注解开启对 FeignClient 扫描加载处理,根据 Feign Client 的开发规范,定义接口并添加 @FeignClient 注解。当程序启动时,会进行包扫描,扫描所有 @FeignClients 注解的类,并且将这些信息注入 Spring IOC 容器中,当定义的 Fegin 接口 中的方法被调用时,通过 JDK 的代理方式,来生成具体的 RequestTemplate。当生成代理时,Feign 会为每个接口方法创建一个 RequestTemplate 对象,该对象封装了 HTTP 请求需要的全部信息。然后 RequestTemplate 生成 Request,然后把 Request 交给 Client 去处理,这里 client 指的是原生的 URLConnection,Apache 的 HttpClient,也可以是 OKhttp,最后 Client 被封装到 LoadBalanceClent 类,这个类结合 Ribbon 负载均衡发起服务之间的调用。
4. zuul -- url 鉴权,路由转发
zuul filter -- 四个方法:shouldFilter() -- 是否执行,run() - 执行业务逻辑 ,filterType - 过滤器类型(pre、route、post、error),filterOrder -- 执行顺序