早在1994年,Peter Deutsch就提出了分布式计算的七大谬论,后来被James Gosling(Java之父)等人完善为八大谬论。
●网络是可靠的。(The network is reliable.)
●网络是没有延迟的。(Latency is zero.)
●带宽是无限的。(Bandwidth is infinite.)
●网络是安全的。(The network is secure.)
●网络拓扑不会改变。(Topology doesn’t change.)
●肯定至少有一个(在值班的)管理员。(There is one
administrator.)
●传输开销为零。(Transport cost is zero.)
●网络是同质的。(The network
is homogeneous.
系统出现故障时可能出现的原因:
- 网络问题
- 黑客攻击
- 程序BUG
- 服务器宕机
- 自然灾害
- 管理人员误操作
- 磁盘存满了
- 等等
经典案例:服务雪崩
单个实例故障时,处理请求速度缓慢或没有响应,导致本实例的调用者的速度也变慢了,请求堆积,负载升高,以此类推,将导致服务器大范围出现故障,形同雪崩,这种由单个实例导致的级联故障称之为服务雪崩。
造成雪崩原因可以归结为以下三个:
- 服务提供者不可用(硬件故障,程序bug,缓存击穿,用户大量请求)
- 重试加大流量(用户重试,代码逻辑重试)
- 服务调用者不可用(同步等待造成的资源耗尽)
常见服务容错模式
- 超时:最简单的容错方式,在调用方为服务调用设置一个超时时间,避免无限制的等待下游系统造成的线程堆积
- 限流:在提供方一端限制进入的流量,保证服务不会因为超负荷流量而崩溃List item。
- 仓壁模式:资源隔离手段。在调用方进行资源隔离,比如使用线程池,保证消耗的资源有上限,避免无限量调用资源占用其他请求的资源。
- 熔断器:在调用方进行控制,根据策略定义失败情况,失败数字达到阈值时打开熔断器,不再调用底层服务,熔断窗口(一段时间过后)达到时,释放一个请求进入底层,如果请求执行成功则关闭熔断器,正常调用,如果请求失败则继续保持熔断器打开直到下一个熔断窗口达到。
解决方案
netflix-hystrix resillence4j alibaba-sentinel
我学习并使用的是alibaba-sentinel,以下是sentinel的几种容错解决方法
QPS : Queries Per Second 每秒请求数量
限流
流控模式:
• 直接:直接对资源限流
• 关联:当前资源A设置一个关联资源B,如果B的阈值达到则对A限流。通常用在有关联关系的资源中,比如对某个表的查询和更新操作可以设为关联,当更新频繁时限制查询,以提高整体性能
- 创建两个资源A 和B
- 对A设置规则,指定关联B
- 请求B,使其达到频率,访问A发现被流控
• 链路:以调用链路为单位做限流处理,例如:A->B->C 这个链路的总体流量只按入口A的请求量来计算
流控效果:
- 快速失败:拒绝默认流量控制方式,当QPS超过任意规则的阈值后,新的请求将会被拒绝,这种方式适用于对系统处理能力确切已知的情况下。
- warm up(预热):冷启动方式。防止当流量突然增大时压垮系统,所以在预热时间内逐步让流量增加,在一定时间内达到阈值。
目标: QPS 100
冷加载因子: 3
起始阈值:33.33
时长:10s
在10s内,将qps从33.33 拉升到100 - 排队等待:匀速器方式。设置阈值为QPS,可以严格控制请求通过时间
熔断
- RT 慢调用比例:需要设置一个慢调用时间(最大响应时间),请求中大于该时间的为慢调用,单位时长内请求数目大于设置的最小请求数目,且慢调用比例大于阈值,则在接下来的熔断时长内,请求会被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
- 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
- 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
降级
提供一个后备服务,使用@SentinelResource(value="",fallback=“a”)
其中,a是注解下方法出现异常时的备用方法