一个高并发的系统,保护系统的方法一般有三种:缓存、降级和限流,本文主要讲一讲常见的限流策略。限流的目的是通过对并发访问进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务(定向到错误页或告知资源没有了)、排队或等待(比如秒杀、评论、下单)、降级(返回兜底数据或默认数据,如商品详情页库存默认有货)
单机限流
常见限流措施
- 限制总并发数(比如数据库连接池、线程池)
- 限制瞬时并发数(如nginx的limit_conn模块,用来限制瞬时并发连接数)
- 限制时间窗口内的平均速率(如Guava的RateLimiter、nginx的limit_req模块,限制每秒的平均速率)
- 限制远程接口调用速率
- 限制消息队列的消费速率
- 根据网络连接数、网络流量、CPU或内存负载等来限流
限流算法
令牌桶算法:令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求(Nginx限速模块的实现/Guava RateLimiter SmoothBursty)
漏桶算法:漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝(Guava RateLimiter SmoothWarmingUp)
计数器限流:主要用来限制总并发数,比如数据库连接池、线程池、秒杀的并发数;只要全局总请求数或者一定时间段的总请求数设定的阀值则进行限流,是简单粗暴的总数量限流,而不是平均速率限流(atomic.incrementAndGet() + atomic.decrementAndGet())
分布式系统限流
分布式限流 — redis技术/一致性hash流量分片
- 分布式系统:基于 REDIS 实现,存储两个 KEY,一个用于计时,一个用于计数。请求每调用一次,计数器增加 1,若在计时器时间内计数器未超过阈值,则可以处理任务。
- 单机:使用Guava的Cache来存储计数器,过期时间设置为2秒(保证1秒内的计数器是有的),然后我们获取当前时间戳然后取秒数来作为KEY进行计数统计和限流