前言
限流是系统在应对突发流量时保证自身运行稳定性而采取的典型操作,常见的的限流算法有固定窗口限流、滑动窗口限流、令牌桶限流和漏桶限流等 [1],具体的算法原理和实现方式当前已有大量文章介绍,本文不再赘述。本文将着重介绍 AutoMQ 中如何通过限流机制应对不同场景的需求。
流量平滑
限流的最典型作用就是用于平滑尖刺,而 AutoMQ 由于其基于 S3 的架构,也存在着一些具有短时量大的请求特征,为避免这类请求影响系统的稳定性,AutoMQ 使用了对应的限流策略进行平滑处理
平滑上传
AutoMQ 的消息处理链路如下图所示:
当消息在内存中攒批完成后会触发上传至 S3,由于攒批的默认大小一般为数百 MB,每次触发上传时意味着一次性向网络中写入数百 MB 的数据,从而产生一次较大的网络尖刺,在机器带宽受限的情况下,可能导致正常消息收发链路延迟毛刺,影响业务稳定性,而理想的流量特征应为上传速率与发送速率相匹配,也即平滑上传流量。
但除正常发送链路攒批上传 S3 外,当发生分区迁移,节点 failover 等事件时,AutoMQ 也会将缓存中的分区数据强制上传至 S3,以保证分区在新节点能够读取完整数据,此时上传时效比流量平滑优先级更高。而由于 AutoMQ 采用了单线程模型实现数据上传,故在这类场景中还需要动态调整正在上传中的任务,使其尽可能快的完成,避免对分区迁移或节点 failover 造成阻塞。为满足上述需求,AutoMQ 基于 Guava 中的 RateLimiter 实现了一个可动态变更限流速率的异步限流器:在常规的消息发送链路,可动态计算出平滑上传速率,使之与发送速率相匹配;而当特殊场景中需要进行上传加速时,则可提高限流速率保障上传时效性。
平滑 Compaction
在之前的文章 [2] 中我们介绍过了 AutoMQ 的 Compaction 机制,通过定期将 S3 上的零散对象规整成为大块连续数据,可以有效提高消息检索效率、减少元数据规模。而为了避免 Compaction 覆盖的数据量过大,导致过度挤占 JVM 内存,AutoMQ 还会将 Compaction 拆分为多次迭代完成,在未对 Compaction 进行限流时的系统典型流量特征将如下图:
在每轮 Compaction 的每次迭代开始时会集中触发一次读取,将需要被 Compact 的数据读到本地,本地完成数据拼接后上传为新的 S3 Object。对 Compaction 进行平滑限流后,Compaction 的读取和上传流量被打散至完整的 Compaction 周期内,从而作为稳定的「背景流量」存在于系统中,最大化减少对系统的毛刺影响:
分级限流
在 AutoMQ 中存在着以下几种网络流量:
-
消息发送流量:Producer -> AutoMQ -> S3
-
追尾读消费流量:AutoMQ -> Consumer
-
追赶读消费流量:S3 -> AutoMQ -> Consumer
-
Compaction 读取流量:S3 -> AutoMQ
-
Compaction 上传流量:AutoMQ -> S3
可以看到,与 S3 的交互带来了网络流量的读写放大,一个 AutoMQ 节点的网络带宽计算如下:
-
上行带宽 = 消息发送流量 + 追尾读消费流量 + 追赶读消费流量 + Compaction 上传流量
-
下行带宽 = 消息发送流量 + 追赶读消费流量 + Compaction 读取流量
为避免在有限的带宽下,不同类型的网络流量互相抢占导致影响生产链路稳定性,AutoMQ 对上述流量类型进行了分级:
-
Tier-0:消息发送流量
-
Tier-1:追尾读消费流量
-
Tier-2:Compaction 读写流量
-
Tier-3:追赶读消费流量
同时基于优先队列和令牌桶的思想实现了异步分级限流器,所有网络请求都通过分级限流器进行管理,其主要原理如下图:
对于 Tier-0 级的请求,限流器不做流量控制,扣除请求相应的 token 后直接返回成功,对于 Tier-1 ~ Tier-3 级请求,在当前可用 token 不足的情况下,根据请求优先级放入优先队列。当令牌桶每次定时添加 token 时唤醒 callback 线程,尝试从队头开始完成队列中排队的请求 Future,当一次请求的 token size 超出每次 refill 添加的 token 时,会直接将此次 refill 的 token size 从总的请求 size 中减去,作为该请求的预留时间片,当 refill 累计的 token 最终满足请求的需求时,再一次性将请求完成,以上图为例,T1-CF-0 经过 3 次 refill 周期后被完成。
下图为 AutoMQ 使用 10ms refill 周期,限流速率 100MB/s 的配置进行的多级流量测试。发压流量如下:
-
Tier-0 流量按峰值约 100MB/s,2 分钟周期进行波动
-
Tier-1 和 Tier-2 流量按峰值 约 60MB/s,2 分钟周期进行波动
经多级限流后,实际流量曲线如下:
t0 ~ t1:此时 Tier-0~Tier-2 流量同步上涨,随着限流 token 被耗尽,Tier-2 和 Tier-1 流量按照优先级先后下跌,直至跌零,发压请求进入队列排队。Tier-0 实际流量不受影响,按照发压流量达到峰值。
t1 ~ t2:此时 Tier-0 流量低于峰值,此前Tier-1 和 Tier-2 级流量排队的请求得以放出,Tier-1 由于优先级高于 Tier-2,排队请求优先放出,故 Tier-1 流量先于 Tier-2 开始上涨。
t3 ~ end:随着 Tier-0 流量停止,Tier-1 和 Tier-2 排队流量依次放出,直至发压流量耗尽,同时全程保持 100MB/s 的最大流量限制
总结
本文介绍了 AutoMQ 如何利用限流机制进行流量平滑和分级控制,保障系统在复杂生产环境下的平稳运行。
参考链接
[1] What are different rate limiting algorithms:https://www.designgurus.io/answers/detail/rate-limiting-algorithms
[2] AutoMQ 对象存储数据高效组织的秘密: Compaction:https://www.automq.com/blog/automq-efficient-data-organization-in-object-storage-compaction
共同学习,写下你的评论
评论加载中...
作者其他优质文章