springcloud 各组件理解
restTemplate(远程调用)
eureka(服务注册)
Ribbon(负载均衡)
openFeign(远程调用+负载均衡)
hystrix(熔断器)
gateway(网关)
config(配置中心)
stream(消息中间件统一接口)
eureka包含两个组件:eureka server和eureka client
eureka server(提供服务注册 ):服务通过配置,在启动的时候注册到eureka中,从eureka server的注册表可以看到服务节点的信息
eureka client(通过注册中心进行访问):是一个Java客户端,用于简化eureka server的交互,内置了轮询(round-robin)负载算法的负载均衡器。
应用启动后会向eureka server发动心跳 (默认周期30秒),如果eureka server在多个心跳周期没有收到某个节点心跳,eureka server会将该节点从注册表中删除(默认90秒)。
如果短时间内丢失大量的节点心跳,将会进入自我保护机制(默认开启)
该机制是避免网络连接故障,而误将应用节点从注册表删除,即使后面回复了之后,也无法重新注册,因为只有在启动的时候才会注册服务节点。
进入保护模式的条件:
最近一分钟收到心跳次数小于阈值,则会触发自我保护模式,所有掉线服务节点都不会删除,即使该实例确实是人为停掉的。
退出保护模式:心跳次数大于阈值。
阈值:应用节点(实例)* 每分钟发送的次数(默认30秒一次)*保护系数(默认0.85)
比如:10(服务实例)*2(30秒一次,一分钟2次)*0.85 = 17(一分钟需要心跳17次,低于17次开启保护)
Ribbon:ribbon是一个负载均衡的框架。
负载均衡算法:接口请求数(第几次)%服务器总数=实际调用服务器位置下标,每次服务器重启rest接口计数从1开始。
openFeign:远程调用+负载均衡
feign默认请求时间超时是1秒钟,如果业务逻辑处理超过的话会抛出超时错误。
hystrix(熔断器):服务降级、服务熔断、服务限流
为什么使用:如果某服务出现问题/消耗资源高/耗时--等原因导致线程阻塞,此时还有大批量的并发访问,servlet的线程资源就会被消耗完毕,导致服务瘫痪。
服务与服务会有依赖性,故障会传播,会对整个微服务造成严重后果,这就是服务”雪崩“效应。
hystrix可以对客户端(向外暴露的服务)使用,也可以对服务端(业务服务)使用
服务降级:不执行该接口,选择另一种方案(触发其他的方法,比如显示访问人数过多,请稍后再试)
可以设置接口访问时长、设置备用方法,发送异常/超时等都会调用备用方案。
服务熔断:某服务出现问题后,断路器会开启,关闭所有对该接口的访问,并对其降级(服务降级)
断路器三个重要参数:快照时间窗、请求总数阈值、错误百分比阈值
快照时间窗默认是最近10秒,作为统计是否开启断路器的条件
请求总和数默认20,最近10秒内达到20次访问,才能触发是否开启断路器条件。如果10秒不及20次请求,即使所有请求都错误/超时,也不会触发断路器
错误百分比默认值50%,也就是说10秒内,超过20次请求,错误达到10次,就会开启 断路器
开启断路器之后,所有请求都会服务降级调用fallback方法,一段时间后(默认5秒)就会处于半开启状态,
如果再次请求,还是错误的话,就会又开启断路器,并重新记时(5秒)
如果再次请求,成功的话,则从半开启状态转为关闭状态
断路器执行流程:
1、判断处于开启/半开启状态,如果开启,直接调用服务降级回退逻辑。
2、如果半开启的话,需要判断线程池、队列、信号量是否包和,如果饱和,直接调用服务降级回退逻辑。
3、实际触发远程调用,如果超时,直接调用服务降级回退逻辑。
4、判断是否执行成功,成功返回结果。失败的话,直接调用服务降级回退逻辑。
5、把所有的运行状态(成功、失败、超时、拒绝)上报给熔断器,用于统计,从而影响断路器的状态。
进入回退逻辑:
没有实现降级方法,直接抛出异常。
降级方法执行成功,直接放回。
降级方法执行失败,抛出异常。
返回结果。
服务限流:Hystrix隔离方式采用线程/信号的方式,通过隔离限制依赖的并发量和阻塞扩散
(1) 线程隔离:
执行依赖代码的线程与请求线程分离。简单理解就是:发送请求线程和处理请求不是一个线程。
通过线程池大小可以控制并发量,当线程池饱和时可以提前拒绝服务,防止依赖问题扩散。
建议:线程池不要设置过大,否则大量堵塞线程有可能会拖慢服务器。
当并发请求时,先从hystrix管理的线程池里获取一个线程(默认10),当线程池饱和时,会进入队列排队(默认5),之后进来的则转到降级的fallback方法。
(2) 线程隔离的优缺点:
线程隔离的优点:
发送请求线程和处理请求不是一个线程,线程可以快速放回。
如同异步编程。
当一个失败的依赖变成可用时,线程池将清理,并立即回复可用,而不是长时间的回复。
线程隔离的缺点:
线程池的主要缺点是它增加了cpu,因为每个命令的执行涉及到排队(默认使用SynchronousQueue避免排队),调度和上下文切换。
对使用ThreadLocal等依赖线程状态的代码增加复杂性,需要手动传递和清理线程状态。
线程隔离开销足够小,不会造成重大的成本或性能的影响。
(3) 信号隔离:
作用:
信号隔离也可以用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请)
如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。
流程:
每个并发都要获取一个信号量才能真正去调用目标服务接口,但信号量有限,默认是10个。如果并发请求数多于信号量个数,就有线程需要进入队列排队,
但排队队列也有上限,默认是 5,如果排队队列也满,则必定有请求线程会走fallback流程,从而达到限流和防止雪崩的目的。
注意:信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。
gateway(网关):就是拦截请求,请求分配到哪个服务,该请求是否达到匹配规则,说白就是一个filter器
config(配置中心):在微服务开发中,配置信息非常之多,如果需要修改配置文件每次都要重启,代价非常高,
所以可用用到配置中心,把配置写道git中,然后配置中心到git读取,一但git更新,就会立即重新加载,