高可用和稳定性
多副本
- 本地缓存多副本
- Redis多副本
- MySQL多副本
- 消息中间件多副本
隔离、限流、熔断和降级
隔离
定义:将系统或资源分割开,在系统发生故障时能限定传播范围和影响范围,即发生故障后不会出现滚雪球效应
- 数据隔离
- 机器隔离
- 线程池隔离:为了某个rpc接口较慢导致线程池打满,为不同的rpc接口提供不同的线程池
- 信号量隔离:为了解决线程数过多导致上下文切换开销的大问题,共用线程池但是取线程之前需要获得信号量,信号量达到阈值则无法获取线程
限流
定义:系统的处理能力不能应对外部请求的涂增流量时,为了不让系统崩溃(如线程池资源耗尽),需要采取限流的措施
方式
- 技术层面的限流
限制并发数:比如数据库连接池、线程池、Nginx的limit_conn模块
限制速率:比如Guava的RateLimiter、Nginx的limit_req模块 - 业务层面的限流
如在秒杀系统中,一个商品的库存只有100件,现在有2万人抢购,没有必要放2万个人进来,只需要放前500个人进来,后面的人直接返回已售完即可。具体实现上,有团队使用Redis,也有团队直接基于Nginx+Lua脚本来实现
限流算法
并发数限制
限制并发数的计算原理很简单,系统只需要维护正在使用的资源数或空闲数,比如数据库的连接数、线程池的线程数
速率限制
- 固定窗口计数
- 方式:
- 在固定时间区间内统计请求数量
- 达到阈值后拒绝请求
- 缺点:
- 临界点爆发问题,0.99秒1000个请求,1.01秒1000个请求
- 突刺,0.1处理1000个请求,剩下0.9秒无法处理请求
- 滑动窗口计数
- 方式:
- 将时间窗口进一步细分为小块(比如1秒->10个0.1秒)
- 每个小窗口分别计数,滑动加总
- 优点:缓解临界爆发,流量统计更平滑
- 缺点:缓解临界爆发,不解决
- 滑动时间窗口
- 方式:
- 精确记录每次请求的时间戳
- 每次检查当前时间,除去超过时间范围的请求计数,计算窗口内真实数量
- 缺点:内存占用高,不适合高并发场景
- 漏桶算法
- 方式:
- 请求以仁义速度进入系统,被积压放入桶中,即入水速度任意
- 请求按固定速率处理(出水速率恒定),即出水速度恒定
- 请求可以缓冲排队,溢出直接丢弃
- 特点:平滑流量,不能积压太多突发流量
- 令牌桶算法
- 方式:
- 定时向桶内放入令牌(以固定速率)
- 每个请求拿一个令牌,拿到才能处理,没有就拒绝或者排队
- 特点:可以应对突发流量
漏桶算法 vs 令牌桶算法
| - | 漏桶算法 | 令牌桶算法 |
|---|---|---|
| 特点 | 流出速率保持恒定 | 流入速率保持恒定 |
| 用途 | 类似消息队列,起到了削峰的作用,平滑了突发流入速率 | 限制的是平均流入速率,可能一段时间没有请求令牌累积,突发流量一瞬间取令牌处理 |
熔断
定义:当某个服务持续失败或响应异常,系统主动“断开”对它的调用一段时间,避免整个系统雪崩
根据请求失败率做熔断
对于客户端调用的某个服务,如果服务在短时间内大量超时或抛错,则客户端直接开启熔断,也就是不再调用此服务。然后过一段时间,再把熔断打开,如果还不行,则继续开启熔断。这也正是经常提到的“快速失败(Fail Fast)”原则”
根据请求响应时间做熔断
Sentinel 的思路根据请求响应时间做熔断。当资源的平均响应时间超过阈值后,资源进入准降级状态。接下来如果持续进入5个请求,且它们的RT 持续超过该阈值,那么在接下来的时间窗口内,对这个方法的调用都会自动地返回
降级
定义:降级是一种兜底方案,是在系统出故障之后的一个尽力而为的措施。比如电商推荐系统,当宕机时,可以为首页准备一个非个性化的商品列表,甚至一个静态的商品列表