面试突击:springcloud五大组件

平时工作很多概念性的东西用不到,长时间不用吧,容易忘,但面试又确实是要问,只能复习面试的时候整理下来,也是再学习一遍。

真希望能找到一份,能把学习到的诸多理论知识变成实践的工作,而不是业务复杂,但技术不复杂的工作,嗨,加油吧。

eureka

eureka是常用的注册中心,功能是让多个服务注册在注册中心,实现服务发现和故障转移的功能。

最基本的工作原理是:

  1. client启动后会定时从server拉取其他服务的信息
  2. client同时也会定时向server发送自己的信息(名字、ip、端口)
  3. client就根据拉取到的信息互相调用

工作流程是:

  1. client在启动时,在DiscoveryClient的构造方法里面初始化了一个叫heartBeatExecutor的线程池
  2. 然后在initScheduleTasks方法里面,先创建了一个叫CacheRefreshThread的线程
  3. 这个线程以30秒为周期从server请求数据,通过CAS和本地保存的远端数据比较并替换
  4. 又初始化了一个叫heartBeatThread的线程
  5. 这个线程也以30秒为周期发送心跳数据给server,根据返回的状态码,如果是404,就向server发送instanceInfo来注册,如果是200,这次心跳就结束
  6. server接受到instanceInfo之后,保存在concurentHashMap里,key是appName,value是一个Lease的一个包装类,这个类里面有instanceInfo的信息,有注册的时间,实例存活时间,上次更新时间等信息

自我保护机制

因为可能由于网络原因,client并没有挂掉,但是server却收不到一个或多个client的心跳了,那么就会触发自我保护机制

自我保护机制是说,哪怕长时间都没有收到心跳,仍然不会将服务剔除,这是因为eureka遵循CAP原则中的AP,牺牲了C

CAP原则

C (一致性),A(可用性),P(分区容错性)

服务剔除

如果关闭了自我保护机制,那么默认在90秒内,如果收到的心跳数少于:

client数 * (60 / 心跳间隔时间,默认30) * 系数,默认0.85

那么就会根据一个随机数剔除过期的服务实例

Ribbon

Ribbon是一个客户端负载均衡工具,用得最多的一般就是轮询吧,就是直接服务启动后的总请求次数%微服务集群总数量,余数就是负载到第几台服务器去,每次重启后总请求次数清零,通过自旋锁来确保能获取到正确的数

Ribbon默认提供了一些策略:

  1. 轮询
  2. 随机
  3. 先轮训,失败了重试
  4. 响应越快的实例权重越大,越被优先选择
  5. 过滤掉故障的实例,选并发量最小的实例
  6. 过滤掉被熔断降级的实例,选并发量最小的实例
  7. 默认,根据性能和可用性多重考虑选择实例

也可以自己写平衡策略,然后在注解@RibbonClient那里指定自己写的平衡策略就可以了

一般很少单独使用ribbon的吧,一般都直接用OpenFeign,OpenFeign里面集成了Ribbon

OpenFeign

OpenFeign的功能是简化微服务之间的调用,从http调用改为rpc调用,并且集成了ribbon,又解决了微服务环境下,多实例之间互相调用的负载均衡问题

原理大概是:

  1. OpenFeign会给加了@FeignClient的接口扫描出来,注册一个FactoryBean的实例
  2. 当spring调用的时候OpenFeign返回一个生成的动态代理的对象,拦截接口的执行
  3. 然后生成http请求模板去请求,拿到返回值以后再反序列化了返还给调用方

Hystrix

因为现在微服务化了,调用链路变长,变长之后每一个调用链路理论上都有可能出问题,那出问题的可能性随着调用链路的增长就会变大

那调用链路中的一环出了问题,后面就会引起异常的蔓延,为了避免一处错误使得整个调用链路出问题,或者是为了让整个调用链路在高并发下有着更好的表现,Hytrix就应运而生

为了避免上述问题,hystrix主要做了以下四个工作

1. 线程池隔离

Hystrix内部通过HystrixThreadPool.factory,用concurrentHashMap管理了多个线程池,key是HystrixThreadPoolKey,可以把它理解成一个资源或者对象。

请求同一个资源的线程都得进入这同一个线程池,这样同一时间的并发量再大,实际起作用的也就是线程池内数量的线程,如果超出了线程池的最大等待数量,就触发fallback降级。

有着显著的削峰效果,降低了服务的压力,这就是线程池隔离。

2. 信号量隔离

信号量隔离就是Hystrix维护了一个最大信号数量,每次请求进来就会占用一个信号量,成功了就释放掉,也就相当于最大并发数吧。如果当前信号量达到了最大信号量,后续的请求全部触发fallback降级。

3. 服务降级

也就是之前说的fallback。

不管是主动触发fallback,比如上面的线程池隔离的时候达到最大等待数了,还是信号量隔离达到最大信号量了,回由Hystrix主动触发降级也好。

还是因为微服务内部抛异常了/内部处理超时了等,触发了fallback。

这个服务降级本身就相当于,调用链路到fallback就不再往下走了,直接返回一个之前预设的值,这次请求就结束了

4. 服务熔断

服务熔断就类似于会自我修复的保险丝一样,一旦这个系统fallback次数达到一定程度,那实际上也就说明当前这个服务已经超出它的工作能力了,就得让负载均衡分给别人了,大体流程位:

  1. 正常
  2. 看时间窗口内,失败次数的百分比,比如过去十秒内,失败次数达到了50%,触发熔断
  3. 熔断时所有请求直接fallback
  4. 等待一个时间后,进入半开放状态
  5. 在半开放状态下,放进来一个请求,看这次请求能否成功,如果成功,解除半开放状态,恢复正常;如果这次还失败了,那么结束半开放状态,继续熔断,再等待一个时间周期继续进入半开放状态

zuul & gateway

因为zuul连续跳票,所以Spring团队自己孵化出了Gateway项目,作用都是一样的,但是Gateway是异步非阻塞的,理论上性能更好一些,之前公司用的也是gateway

gateway顾名思义,就是网关,主要干的事就是路由(route)、拦截(Filter)、统一处理(Handler),比如说:

  1. 现在微服务化了,一个项目可能会部署多个实例,每个实例要占用不同的端口,那调用方需要知道被调用方这么多具体的信息么,其实并不需要,调用方只需要知道网关的地址就可以了,由网关来分发请求
  2. 比如判断登陆状态,加了oauth2以后,每次请求有没有带token,不需要每个微服务都做一遍,只需要最前方的网关做了校验,非法请求就不会走到后面去

所以在网关着一层可以做一些更高层次的事情,比如流量过滤,合法性校验,监控,日志输出等

分布式事务

两段式提交/使用消息中间件,由起始的微服务发消息并等待回调才算结束一个事务

Comments

You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.