网站首页 > 技术教程 正文
前言
对于高并发的系统,有三把利器用来保护系统:缓存、降级 和 限流。限流常见的应用场景是秒杀、下单和评论等 突发性 并发问题。
- 缓存 的目的是提升 系统访问速度 和 系统吞吐量。
- 降级 是当服务 出问题 或者影响到核心流程的性能,则需要 暂时屏蔽掉,待 高峰 或者 问题解决后 再打开。
- 有些场景并不能用 缓存 和 降级 来解决,比如稀缺资源(秒杀、抢购)、写服务(如评论、下单)、频繁的复杂查询(最新的评论)。因此需有一种手段来限制这些场景的 并发/请求量,即 限流。
正文
限流的目的
限流的目的是通过对 并发访问/请求进行 限速,或者一个 时间窗口 内的的请求进行限速来 保护系统,一旦达到限制速率则可以 拒绝服务(定向到错误页或告知资源没有了)、排队 或 等待(比如秒杀、评论、下单)、降级(返回托底数据或默认数据,如商品详情页库存默认有货)。
限流的方式
- 限制 总并发数(比如 数据库连接池、线程池)
- 限制 瞬时并发数(如 nginx 的 limit_conn 模块,用来限制 瞬时并发连接数)
- 限制 时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率)
- 限制 远程接口 调用速率
- 限制 MQ 的消费速率
- 可以根据 网络连接数、网络流量、CPU 或 内存负载 等来限流
限流的算法
1. 令牌桶
2. 漏桶
3. 计数器
有时候还可以使用 计数器 来进行限流,主要用来限制 总并发数,比如 数据库连接池、线程池、秒杀的并发数。通过 全局总请求数 或者 一定时间段的总请求数 设定的 阀值 来限流。这是一种 简单粗暴 的限流方式,而不是 平均速率限流。
令牌桶 vs 漏桶
令牌桶限制的是 平均流入速率,允许突发请求,并允许一定程度 突发流量。
漏桶限制的是 常量流出速率,从而平滑 突发流入速率。
应用级别限流
1. 限流总资源数
可以使用池化技术来限制总资源数:连接池、线程池。比如分配给每个应用的数据库连接是 100,那么本应用最多可以使用 100 个资源,超出了可以 等待 或者 抛异常。
2. 限流总并发/连接/请求数
如果你使用过 Tomcat,其 Connector 其中一种配置有如下几个参数:
- maxThreads: Tomcat 能启动用来处理请求的 最大线程数,如果请求处理量一直远远大于最大线程数,可能会僵死。
- maxConnections: 瞬时最大连接数,超出的会 排队等待。
- acceptCount: 如果 Tomcat 的线程都忙于响应,新来的连接会进入 队列排队,如果 超出排队大小,则 拒绝连接。
3. 限流某个接口的总并发/请求数
使用 Java 中的 AtomicLong,示意代码:
try{
if(atomic.incrementAndGet() > 限流数) {
//拒绝请求
} else {
//处理请求
}
} finally {
atomic.decrementAndGet();
}
4. 限流某个接口的时间窗请求数
使用 Guava 的 Cache,示意代码:
LoadingCache counter = CacheBuilder.newBuilder()
.expireAfterWrite(2, TimeUnit.SECONDS)
.build(newCacheLoader() {
@Override
public AtomicLong load(Long seconds) throws Exception {
return newAtomicLong(0);
}
});
longlimit =1000;
while(true) {
// 得到当前秒
long currentSeconds = System.currentTimeMillis() /1000;
if(counter.get(currentSeconds).incrementAndGet() > limit) {
System.out.println("限流了: " + currentSeconds);
continue;
}
// 业务处理
}
5. 平滑限流某个接口的请求数
之前的限流方式都不能很好地应对 突发请求,即 瞬间请求 可能都被允许从而导致一些问题。因此在一些场景中需要对突发请求进行改造,改造为 平均速率 请求处理。
Guava RateLimiter 提供了 令牌桶算法实现:
- 平滑突发限流 (SmoothBursty)
- 平滑预热限流 (SmoothWarmingUp) 实现
平滑突发限流(SmoothBursty)
RateLimiter limiter = RateLimiter.create(5);
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
将得到类似如下的输出:
0.0
0.198239
0.196083
0.200609
0.199599
0.19961
平滑预热限流(SmoothWarmingUp)
RateLimiter limiter = RateLimiter.create(5, 1000, TimeUnit.MILLISECONDS);
for(inti = 1; i < 5; i++) {
System.out.println(limiter.acquire());
}
Thread.sleep(1000L);
for(inti = 1; i < 5; i++) {
System.out.println(limiter.acquire());
}
将得到类似如下的输出:
0.0
0.51767
0.357814
0.219992
0.199984
0.0
0.360826
0.220166
0.199723
0.199555
SmoothWarmingUp 的创建方式:
RateLimiter.create(doublepermitsPerSecond, long warmupPeriod, TimeUnit unit);
- permitsPerSecond: 表示 每秒新增 的令牌数
- warmupPeriod: 表示在从 冷启动速率 过渡到 平均速率 的时间间隔
速率是 梯形上升 速率的,也就是说 冷启动 时会以一个比较大的速率慢慢到平均速率;然后趋于 平均速率(梯形下降到平均速率)。可以通过调节 warmupPeriod 参数实现一开始就是平滑固定速率。
分布式限流
分布式限流最关键的是要将 限流服务 做成 原子化,而解决方案可以使用 redis + lua 或者 nginx + lua 技术进行实现。
接入层限流
接入层 通常指请求流量的入口,该层的主要目的有:
- 负载均衡
- 非法请求过滤
- 请求聚合
- 缓存、降级、限流
- A/B测试
- 服务质量监控
对于 Nginx 接入层限流 可以使用 Nginx 自带了两个模块:连接数限流模块 ngx_http_limit_conn_module 和 漏桶 算法实现的 请求限流模块 ngx_http_limit_req_module。还可以使用 OpenResty 提供的 Lua 限流模块 lua-resty-limit-traffic 进行 更复杂的 限流场景。
- limit_conn: 用来对某个 KEY 对应的 总的网络连接数 进行限流,可以按照如 IP、域名维度 进行限流。
- limit_req: 用来对某个 KEY 对应的 请求的平均速率 进行限流,并有两种用法:平滑模式(delay)和 允许突发模式 (nodelay)。
OpenResty 提供的 Lua 限流模块 lua-resty-limit-traffic 可以进行更复杂的限流场景。
- 上一篇: Nginx如此之快(nginx!)
- 下一篇: Nginx负载均衡最全详解(图文全面总结)
猜你喜欢
- 2024-10-13 Nginx 多进程高并发、低时延、高可靠机制在滴滴缓存代理中的应用
- 2024-10-13 linux的TCP连接数量不能超过65535个,如何应对千万的并发的?
- 2024-10-13 Nginx实现高速并发处理的原理详解
- 2024-10-13 Java开发大型互联网企业高并发限流特技
- 2024-10-13 高并发下的Nginx限流实战(nginx并发能力是多少)
- 2024-10-13 nginx——控制 Nginx 并发连接数(nginx 并发限流)
- 2024-10-13 Nginx(七) 测试使CPU占用更多能否提升并发数
- 2024-10-13 Nginx凭啥子并发数可以达到3w!(nginx的并发量)
- 2024-10-13 nginx负载均衡-提升服务的并发能力
- 2024-09-28 服务器能承载3000人但来5000人!服务器宕机了!如何救
你 发表评论:
欢迎- 最近发表
-
- Win10 TH2正式版官方ESD映像转换ISO镜像方法详解
- 使用iso镜像升级到Windows 10的步骤
- macOS Ventura 13.2 (22D49) Boot ISO 原版可引导镜像
- 安利一个用ISO镜像文件制作引导U盘的的小工具RUFUS
- CentOS 7使用ISO镜像配置本地yum源
- 用于x86平台的安卓9.0 ISO镜像发布下载:通吃I/A/N、完全免费
- AlmaLinux 9.6发布:升级工具、初步支持IBM Power虚拟化技术
- Rufus写入工具简洁介绍与教程(写入模式)
- 新硬件也能安装使用了,Edge版Linux Mint 21.3镜像发布
- 开源工程师:Ubuntu应该抛弃32位ISO镜像
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)