滑动窗口
维护一个计数器,将单位时间段(比如1s)当做一个窗口,计数器记录这个窗口接收请求的次数。
- 当次数少于限流阀值,就允许访问,并且计数器+1
- 当次数大于限流阀值,就拒绝访问。
- 当前的时间窗口过去之后,计数器清零。
缺点
- 但是一旦到达限流后,请求都会直接暴力被拒绝
- 边缘效应,还是可能出现一段时间请求超过限制的问题
滑动队列
- 使用队列作为请求的标识,每次请求之前将1分钟(假设以1分钟作为单位)前的请求全部pop出去,然后检查队列长度是否依旧大于最大值
缺点
- 简单但是占空间大,因为有实体,有些过期的依旧会被保存
漏桶
- 流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的。
- 桶的容量一般表示系统所能处理的请求数。
- 如果桶的容量满了,就达到限流的阀值,就会丢弃水滴(拒绝请求)
- 流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求。
- 存下请求
- 匀速处理
- 多余丢弃
缺点
- 面对突发流量的时候,漏桶算法还是循规蹈矩地处理请求,这就不是我们想看到的啦。流量变突发时,我们肯定希望系统尽量快点处理请求,提升用户体验
令牌桶
- 有一个令牌管理员,根据限流大小,定速往令牌桶里放令牌。
- 如果令牌数量满了,超过令牌桶容量的限制,那就丢弃。
- 系统在接受到一个用户请求时,都会先去令牌桶要一个令牌。如果拿到令牌,那么就处理这个请求的业务逻辑;
- 如果拿不到令牌,就直接拒绝这个请求
- 用的最多,如果放令牌速度不变退化成漏桶
- 优点是满足突然的高峰需求
缺点
- 放置令牌的速率难以控制
滑动窗口计数法
- 结合了计数法和队列法的特点
- 当前的请求数量=当前窗口的请求+上个窗口的请求*((窗口长度-当前窗口长度)/窗口长度)
[!example] 上图中的计算 3+5*0.7%=6.5 舍和入都可以
- 优点是滑了流量峰值,因为速率是基于前一个窗口的平均速率和内存效率高
缺点
- 它假设前面窗口请求是均匀分配的,如果出现不均匀分配,可能出现错误放通或禁止,只适用于不那么严格的向后看窗口
并发限流
- 对于每个请求,并发度限流分三个步骤:
- 资源申请:请求开始时,业务服务申请资源,并发度+1。当并发度达到阈值,拒绝请求,在这之前设置了最大并发度。
- 业务逻辑:请求进行中,业务执行访问数据库、下游服务等操作。
- 资源释放:请求结束后,业务服务释放资源,并发度-1。
- 这个其实可以和别的限流方法一起使用
- 相当于通过并发的维度而不是通过QPS的维度,在大规模秒杀场景很管用
微信
过载保护
- 依赖微服务框架的快速拒绝
- client端漏桶策略:每15秒为一个统计周期,统计请求所有ip:port的连接和超时(-202)次数,当某个ip:port的fail次数超过4次,则本周期内不在请求这个ip:port,client端会尝试请求其他ip:port。这部分类似熔断策略
- INQUEUE TIMEOUT: hikit woker从INQUEUE里取到一个任务时,发现任务在队列里面等待超过了500ms,那么直接不处理,给client返回-1235,client端直接失败,默认没有重试策略。
- FastReject策略: 一个请求在入队前,判断上一周期(默认是上1秒)的所有请求入队/出队平均耗时,如果耗时大于20ms,那么直接不入队,给client返回-1233,client端重试下一台,如果两台机都返回-1233,那么不再重试,client返回-1234失败
频率拦截服务
- 本地Agent通过RPC代理上报访问信息到后台,同时拉取拦截策略并更新至拦截策略共享内存
- 频率拦截后台负责统计访问频率,达到阈值时触发新的拦截策略。
- 拦截Api将访问信息push到队列中,同时通过拦截策略共享内存获知当次访问是否需要拦截。
熔断
- 两种熔断机制,一种是本地熔断,快速拒绝,计算平均响应时间
- #TODO 完成熔断部分的学习
参考
- https://zhuanlan.zhihu.com/p/376564740