跳到主要内容

Async Store 压测对比

概述

本文比较 AsyncTaskStore 的 Redis 与 JDBC(MySQL)实现在创建任务、并发领取并完成任务,以及读取任务三类负载下的表现。测试直接连接真实的本地 Redis 和 MySQL,完整经过序列化、索引、CAS 和 Lease 路径。

Async Store 同时承担状态持久化与调度协调,因此不能只看最高吞吐量。典型延迟决定日常响应速度,p95/p99 尾延迟会影响 Worker 调度抖动,而数据库的一致性、可恢复性和运维方式同样影响最终选型。

先看结论

  • Redis 创建吞吐量约为 MySQL 的 1.23 倍,且各延迟分位均更低。
  • MySQL 的完整领取与完成吞吐量约比 Redis 高 18%,但 Redis 的延迟明显更低:p50 低约 41%,p99 低约 51%。这是“总吞吐”和“单任务延迟”指向不同选择的典型场景。
  • 两者读取能力接近,Redis 吞吐量约高 5%;MySQL 的 p95/p99 略低,Redis 的 p50 更低。
  • 低延迟、高频调度优先考虑 Redis;偏重批量生命周期吞吐、关系型事务和现有数据库治理,并能接受更高尾延迟时,可以选择 MySQL。

测试对象

压测覆盖 Async Task 的三个主要 Store 操作:

阶段操作代表的实际负载
Create创建一个到期可查询的 RUNNING 任务提交任务并进入持久化调度
Claim + complete并发领取到期任务,保存 SUCCEEDED 状态并释放 LeaseWorker 查询调度、CAS 更新和租约处理
Load按任务 ID 并发加载状态轮询、结果查询和恢复

Claim + complete 覆盖候选扫描、原子领取、Lease 建立、带版本保存和 Lease 释放。它比单条 UPDATE 更接近 Async Task Worker 的核心工作循环。

测试环境与方法

项目配置
Redis本地 Docker 单节点,127.0.0.1:6379
MySQL本地 MySQL 5.7.44,127.0.0.1:3306
生命周期任务数2,000
并发读取数10,000
Worker 线程数8
MySQL 连接池HikariCP,最大连接数 10
数据内容最小化序列化 Async Task
运行隔离每个后端在独立 Maven JVM 中运行

创建阶段串行写入 2,000 个任务;生命周期和读取阶段使用 8 个线程并发执行。吞吐量按阶段整体耗时计算,p50、p95 和 p99 来自单次操作的延迟样本。

每轮压测使用唯一的 Redis Key Prefix 或 MySQL Table Prefix,并在结束后自动删除数据。本次验证没有出现 CAS 错误、重复领取或任务丢失;2,000 个任务全部进入终态,压测结束后 Redis 残留键和 MySQL 残留压测表均为 0。

压测结果

后端操作吞吐量p50p95p99
RedisCreate340.3 ops/s1.886 ms5.019 ms7.245 ms
MySQLCreate275.7 ops/s2.798 ms5.682 ms12.184 ms
RedisClaim + complete133.2 ops/s26.635 ms51.965 ms65.502 ms
MySQLClaim + complete157.2 ops/s45.024 ms84.019 ms134.753 ms
RedisLoad2,238.6 ops/s2.663 ms8.010 ms13.920 ms
MySQLLoad2,126.6 ops/s3.094 ms7.560 ms12.895 ms

从结果看实现差异

创建:Redis 吞吐和延迟同时占优

Redis 创建吞吐量约高 23%,p50 从 MySQL 的 2.798 ms 降至 1.886 ms,p99 从 12.184 ms 降至 7.245 ms。对于突发提交或需要快速持久化大量异步任务的入口,这一差异有助于减少创建阶段的排队。

生命周期:吞吐量与延迟需要分开看

MySQL 在本轮 Claim + complete 中完成 157.2 ops/s,比 Redis 的 133.2 ops/s 高约 18%。如果目标是让固定数量的 Worker 在单位时间内完成更多批量状态转换,MySQL 的这一结果值得关注。

但单任务延迟呈现相反结论:Redis p50 为 26.635 ms,MySQL 为 45.024 ms;Redis p99 为 65.502 ms,MySQL 达到 134.753 ms。Redis 的 p99 约低 51%,说明它在本次并发调度下响应更稳定。

吞吐量与延迟并不矛盾。领取操作按批次返回任务,线程并发、批次摊销、事务和连接池等待都会影响阶段总吞吐与单任务样本。需要快速唤醒单个任务时应优先看延迟;关注长时间批处理能力时则应结合吞吐量、积压增长率和资源利用率判断。

读取:总体接近

Redis 读取吞吐量约高 5%,p50 略低;MySQL p95 和 p99 略低。这个差异小于创建和生命周期阶段,不足以单独决定选型。实际轮询系统还应评估热点任务、缓存命中、任务 payload 大小和网络延迟。

如何选择

场景建议原因
高频提交、快速查询调度、关注 p99Redis创建和生命周期延迟更低
单个任务需要尽快被 Worker 推进Redis本次测试的领取与完成延迟更稳定
长时间批处理,优先阶段总吞吐先验证 MySQL本轮生命周期吞吐更高,但需确认尾延迟可接受
已有成熟 MySQL 高可用、备份和审计体系JDBC + MySQL可复用关系型数据库治理能力
需要 SQL 关联任务与业务数据JDBC + MySQL查询和数据集成更直接
真实任务包含较大请求或结果重新压测最小化 payload 无法代表序列化和网络成本

选择 Store 时还应考虑供应商调用时长、轮询周期、Lease 配置、任务积压峰值和故障恢复目标。供应商 HTTP 请求往往比 Store 操作慢得多,此时稳定性和可运维性可能比几%的 Store 吞吐差异更重要。

测试边界

本次压测有以下限制:

  • Redis 和 MySQL 都运行在本机单节点环境,没有外部网络延迟。
  • 使用最小化任务对象,没有覆盖大型请求参数、结果对象和业务 DTO。
  • 没有比较 Redis AOF/RDB、MySQL 刷盘等级等持久化策略。
  • 没有覆盖 Redis Cluster、哨兵、MySQL 主从复制或跨可用区网络。
  • 没有模拟供应商 HTTP 调用、准入策略拒绝、延迟提交和多类查询任务混合负载。
  • 测试时间较短,不代表数据持续增长、GC、连接波动和资源饱和后的稳态性能。
  • 压测路径验证了无重复领取和任务丢失,但不能替代取消竞态、Lease 过期、故障恢复等契约测试。

因此,本文数字只用于同机、同参数下的相对比较。生产部署应使用真实任务数据和网络,逐步增加 Worker、任务量和运行时间,同时监控 CPU、内存、连接池、Redis 延迟和 MySQL 锁等待。

复现测试

基准类位于对应 Store 模块的测试源码中,类名不匹配默认 Surefire 扫描规则,需要通过 -Dtest 显式运行。

Redis:

bash
mvn -pl agents-flex-async-task-store/agents-flex-async-task-store-redis -am \
  -Dtest=RedisAsyncTaskStoreBenchmark \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -Dredis.test.uri=redis://127.0.0.1:6379 \
  -Dstore.benchmark.tasks=2000 \
  -Dstore.benchmark.workers=8 \
  -Dstore.benchmark.reads=10000 test

MySQL 数据库需要预先创建。密码通过环境变量传入:

bash
export MYSQL_TEST_PASSWORD='<password>'
mvn -pl agents-flex-async-task-store/agents-flex-async-task-store-jdbc -am \
  -Dtest=MysqlAsyncTaskStoreBenchmark \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -Dmysql.test.url='jdbc:mysql://127.0.0.1:3306/agents_flex_jdbc_it?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC' \
  -Dmysql.test.user=root \
  -Dstore.benchmark.tasks=2000 \
  -Dstore.benchmark.workers=8 \
  -Dstore.benchmark.reads=10000 test

Redis 与 MySQL 应分别运行,并重复多轮观察中位结果,避免 JVM 预热、GC 和两个后端争用本机资源影响结论。

结论

本次真实 Store 压测没有得出“一个后端全面胜出”的结论。Redis 在任务创建和生命周期延迟上更好,尤其将生命周期 p99 控制在 MySQL 的约一半;MySQL 则在这轮生命周期阶段取得约 18% 的吞吐优势。读取性能基本接近。

对延迟敏感、调度频繁的 Async Task 系统,Redis 更符合本次结果体现出的性能特征。对于强调批量吞吐、事务持久化、SQL 查询和现有数据库运维集成的系统,MySQL 仍然合适,但应确认更高的 p95/p99 不会放大任务调度抖动。最终决策应在生产等价环境中,用真实 payload 和目标并发再次验证。

配置、CAS 和 Lease 契约详见 Store 持久化