Swoole 5协程Redis批量操作需协程化全链路:用Co\Redis开启pipeline,链式调用后exec一次性发送;单次命令数宜控在100–1000条,设超时防卡死,集群需按slot分组pipeline。

直接用 Swoole 5 协程配合 Redis Pipeline 做批量操作,核心就三点:协程不阻塞、连接复用、命令打包发一次。不是光写 pipeline 就行,得让整个链路都“协程化”——包括连接获取、命令组装、结果解析。
协程 Redis 客户端必须支持 pipeline
Swoole 5 自带 Co\Redis,但它默认不开启 pipeline 模式,需要手动启用并确保使用的是协程安全的连接实例:
- 不能用传统同步 Redis 扩展(如 phpredis),必须用
Co\Redis或兼容协程的第三方客户端(如hyperf/redis) - 每次调用
$redis->set() / get()都是协程挂起点,但 pipeline 要先缓存命令,最后统一执行 - 正确姿势是:调用
$redis->pipeline()获取 pipeline 实例,再链式调用命令,最后exec()一次性发出
批量 get 的典型协程 pipeline 写法
比如要查 5000 个 key 的 value,不用 pipeline 会发 5000 次网络包;用 pipeline 只发 1 次:
use Swoole\Coroutine\Redis;
Co\run(function () {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 开启 pipeline
$pipe = $redis->pipeline();
$keys = array_map(fn($i) => "user:{$i}", range(1, 5000));
foreach ($keys as $key) {
$pipe->get($key); // 仅入队,不发网络请求
}
// 一次性发送全部命令,协程挂起等待响应
$results = $pipe->exec(); // 返回数组,顺序与命令一致
// $results[0] 对应第一个 get($keys[0]) 的结果,nil 表示 key 不存在
var_dump(count(array_filter($results, fn($v) => $v !== false)));
});
注意:$pipe->exec() 是协程让出点,底层走的是非阻塞 socket write + read,不会卡住整个进程。
避免常见坑:分片与超时控制
Pipeline 不是越大越好,尤其在高延迟或弱网环境下:
- 单次 pipeline 命令数建议控制在 100–1000 条之间;超过 2000 条易触发 Redis 输入缓冲区限制(默认 1GB,但实际受
client-output-buffer-limit影响) - 可在
redis.conf中调整:client-output-buffer-limit normal 256mb 128mb 60(防止大 pipeline 响应压爆内存) - Swoole 5 默认 socket 超时是 0(永不超时),生产环境务必设
$redis->set(['timeout' => 3]),否则 pipeline 卡住会导致整个协程无法调度 - 集群环境(如 Redis Cluster)不原生支持跨 slot pipeline,需按 key hash 分组,每组单独 pipeline
和 Hyperf 结合更省心
如果你用 Hyperf 框架,hyperf/redis 已封装好协程 pipeline,且自动管理连接池:
use Hyperf\Redis\Redis;
$redis = make(Redis::class);
$pipe = $redis->pipeline();
foreach ($keys as $key) {
$pipe->get($key);
}
$results = $pipe->exec(); // 自动从连接池取连接,执行完归还
它还支持 pipeline + Lua 脚本混合使用,适合需要原子性又想批量的场景(例如:批量读 + 条件更新),但要注意 Lua 脚本本身不能跨 slot。


















