如何使用JMeter对Redis发布订阅系统进行高并发压力测试

星涛吖_4506

星涛吖_4506

2026-10-07

579人浏览

原创

redis pub/sub压测不能用redis data set插件,因其仅支持同步命令,而publish/subscribe是长连接、事件驱动模型,subscribe会阻塞jedis连接导致超时;必须改用jsr223 sampler配合手动线程管理,分离订阅与发布逻辑,并通过latch确保订阅就绪后再发布。

如何使用jmeter对redis发布订阅系统进行高并发压力测试

Redis Pub/Sub 压测不能用 Redis Data Set 插件

因为 Redis Data Set 插件只支持同步命令(如 SET、GET、INCR),底层基于阻塞式 Jedis 连接,而 PUBLISH/SUBSCRIBE 是长连接、事件驱动模型——一旦调用 SUBSCRIBE,连接就进入监听状态,不再返回响应,JMeter 会一直等待超时,最终报 java.net.SocketTimeoutException 或卡死。

所以必须绕过插件,改用 JSR223 Sampler + 手动管理连接生命周期。关键点是:每个线程独占一个 Jedis 实例,且 SUBSCRIBE 必须在独立线程中异步执行,主采样器不能阻塞。

  • 不要在 JSR223 Sampler 中直接写 jedis.subscribe(...) —— 它会阻塞整个线程,导致吞吐量归零
  • 必须用 new Thread(...).start() 启动监听,同时用 vars.put("sub_thread", thread) 持有引用,便于后续清理
  • PUBLISH 可以复用同一连接(或另建短连接),但要注意连接池未启用时频繁新建 Jedis 实例会导致 TIME_WAIT 爆满

如何让每个线程正确启动独立的 SUBSCRIBE 监听

核心是分离「订阅启动」和「发布行为」:一个线程只负责监听,另一个(或多个)线程负责发消息。否则单线程既 SUBSCRIBE 又 PUBLISH 会因连接被占用而失败。

示例(Groovy,放在 JSR223 Sampler 中):

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载
import redis.clients.jedis.Jedis
import java.util.concurrent.CountDownLatch

def host = "127.0.0.1"
def port = 6379
def channel = "test:channel"

// 启动监听线程(后台运行)
def latch = new CountDownLatch(1)
def subThread = new Thread({
    def jedis = new Jedis(host, port)
    try {
        jedis.subscribe(new JedisPubSub() {
            @Override
            void onMessage(String channel, String message) {
                // 可选:记录日志或统计接收数
                log.info("Received: ${message} on ${channel}")
            }
            @Override void onSubscribe(String channel, int subscribedChannels) { latch.countDown() }
        }, channel)
    } catch (Exception e) {
        log.error("Subscribe failed", e)
    } finally {
        jedis.close()
    }
})
subThread.start()

// 等待订阅就绪(避免 publish 早于 subscribe)
latch.await(2, TimeUnit.SECONDS)

// 将监听线程存入变量,供 tearDown 线程组终止
vars.put("sub_thread", subThread)
  • 必须加 latch.await(),否则 PUBLISH 可能发到尚未完成 SUBSCRIBE 的连接上,消息丢失(Redis Pub/Sub 不保证投递)
  • 不要在 onMessage 中做耗时操作(如写文件、调 HTTP),否则积压消息会触发 READONLY 错误或连接中断
  • 监听线程无法通过 JMeter GUI 实时看到“响应”,需靠日志或外部监控(如 redis-cli monitor)验证是否生效

高并发下 PUBLISH 的性能瓶颈与规避方式

真实压测中,PUBLISH 的吞吐量往往受限于网络往返和 Redis 单线程处理能力,而非客户端。当线程数 > 50 且每秒发布 > 1k 条时,容易出现:

  • redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool —— 连接池耗尽,需显式配置 JedisPoolConfig
  • 大量 java.io.IOException: Broken pipe —— 客户端发太快,Redis 内核缓冲区溢出,需调小 tcp-wmem 或加 Thread.sleep() 限速
  • 消息重复或丢失 —— Pub/Sub 本身无 ACK,不适用金融级场景;压测时应关注「接收率」而非「发送率」

推荐做法:

  • 用连接池替代每次新建 Jedis:new JedisPool(new JedisPoolConfig(), host, port),并设 setMaxTotal(200)
  • PUBLISH 采样器中加随机延迟:Thread.sleep(org.apache.jmeter.util.JMeterUtils.getRandomInt(0, 5)),缓解突发冲击
  • 避免在单个 JSR223 Sampler 中混合 SUBSCRIBE 和 PUBLISH —— 分拆为两个线程组:一个只 SUBSCRIBE(设置循环次数为 1),另一个只 PUBLISH(高并发循环)

如何验证 Pub/Sub 压测是否真实生效

不能只看 JMeter 的 Aggregate Report 中的 Throughput,因为 SUBSCRIBE 成功后无返回值,JMeter 默认标记为成功;必须外挂验证手段:

  • 在 Redis 服务端执行 redis-cli --stat,观察 pubsub_channels 和 pubsub_patterns 是否随线程增长而上升
  • 用另一台机器跑 redis-cli -h $HOST -p $PORT SUBSCRIBE test:channel,手动确认能否实时收到消息
  • 在 onMessage 回调里用 props.put("recv_count", props.get("recv_count") as int + 1) 统计接收总数,压测结束后用 BeanShell Sampler 输出全局计数
  • 注意:JMeter 的 View Results Tree 对 Pub/Sub 无效 —— 它只显示采样器返回值,而监听线程不返回任何东西

最易忽略的是连接泄漏:每个 SUBSCRIBE 线程都持有一个长连接,若没在 tearDown Thread Group 中显式 subThread.interrupt() 或关闭 Jedis,压测结束后 Redis 仍维持数百个空闲连接,下次压测可能直接失败。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4329

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

3835

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

6952

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

623

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

736

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

6622

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1160

6

redis的8种数据类型有哪些
redis的8种数据类型有哪些

redis 提供 8 种数据类型:字符串(文本、数字、二进制)、哈希(键值对)、列表(有序集合)、集合(无序唯一元素)、有序集合(按分数排序)、地理空间(地理位置)、hyperloglog(估计大数据基数)和位图(位序列存储)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1036

6

redis主要作用有哪些
redis主要作用有哪些

redis 的主要作用包括:1. 缓存数据,提高访问速度;2. 充当消息队列,实现消息传递;3. 存储各种数据类型,如字符串、散列和集合;4. 管理会话信息,确保可靠性和可用性;5. 限制请求速率,防止服务器超载等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

5878

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习