使用 Pipeline 提高 Redis 批量操作性能

embedded/2025/3/5 22:39:53/

使用 Pipeline 提高 Redis 批量操作性能

在 Redis 中,Pipeline(管道) 是一种用于提高批量操作性能的技术。它允许客户端一次性发送多个命令到 Redis 服务器,而不需要等待每个命令的单独响应,从而减少了**网络往返(RTT, Round Trip Time)**的影响,显著提升性能。


为什么使用 Pipeline?

通常,在 Redis 客户端执行命令时,每条命令都需要:

  1. 客户端发送请求给 Redis 服务器。
  2. 服务器处理请求并返回结果。
  3. 客户端接收结果后,再发送下一条命令。

当需要执行大量命令时,传统的逐条请求方式会产生大量的 网络往返延迟(RTT)。例如,在 100ms 的网络延迟下,每秒最多只能执行 10 条命令(1000ms / 100ms)。

使用 Pipeline,可以:

  • 批量发送命令,减少网络往返次数。
  • 更快地执行大量命令,特别适用于写入操作(如 SET)。
  • 降低 CPU 和 I/O 开销,提高吞吐量。

如何使用 Pipeline

Pipeline 的使用方法因编程语言的不同而有所区别,下面以 Python(redis-py)和 Node.js(ioredis)为例进行详细讲解。


1. 在 Python 中使用 Pipeline

Python 使用 redis-py 客户端,提供 pipeline() 方法来执行批量命令。

示例 1:基本 Pipeline 操作

import redis# 连接 Redis
r = redis.Redis(host='localhost', port=6379, db=0)# 创建 Pipeline
pipe = r.pipeline()# 批量执行 SET 命令
pipe.set("key1", "value1")
pipe.set("key2", "value2")
pipe.set("key3", "value3")# 执行 Pipeline(发送到 Redis 服务器并执行)
pipe.execute()# 验证是否成功
print(r.get("key1"))  # b'value1'
print(r.get("key2"))  # b'value2'
print(r.get("key3"))  # b'value3'

解释:

  1. pipeline() 创建一个 Pipeline 对象。
  2. pipe.set() 添加多个 SET 命令到 Pipeline,但并未立即执行。
  3. pipe.execute() 统一发送到 Redis 服务器执行,提高性能。

示例 2:带返回值的 Pipeline

Pipeline 支持批量获取返回值:

pipe = r.pipeline()pipe.set("key4", "value4")
pipe.get("key4")
pipe.incr("counter")  # 递增操作results = pipe.execute()print(results)  # [True, b'value4', 1]

解释:

  • pipe.get("key4") 会返回 b'value4'
  • pipe.incr("counter") 返回递增后的值。
  • execute() 返回所有命令的执行结果。

示例 3:批量写入

在处理大量数据时,Pipeline 可以显著提升效率:

pipe = r.pipeline()
for i in range(10000):pipe.set(f"key:{i}", f"value:{i}")
pipe.execute()

普通方式 vs Pipeline:

  • 普通方式:每次 SET 需要一次请求,10000 次请求开销很大。
  • Pipeline:只需要很少的网络交互,提高吞吐量。

redis_Pipeline_94">2. 在 Node.js(ioredis)中使用 Pipeline

Node.js 中 ioredis 提供了 pipeline() 方法,可以高效地批量执行 Redis 命令。

示例 1:基本 Pipeline 操作

const Redis = require("ioredis");
const redis = new Redis();const pipeline = redis.pipeline();pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.get("key1");pipeline.exec((err, results) => {console.log(results); // [[null, 'OK'], [null, 'OK'], [null, 'value1']]
});

解释:

  1. redis.pipeline() 创建 Pipeline。
  2. pipeline.set()pipeline.get() 只是加入队列,并未立即执行。
  3. exec() 发送所有命令,返回结果。

示例 2:批量写入

const pipeline = redis.pipeline();
for (let i = 0; i < 10000; i++) {pipeline.set(`key:${i}`, `value:${i}`);
}
pipeline.exec().then(results => {console.log("Pipeline 批量写入完成");
});

普通方式 vs Pipeline:

  • 普通方式:每次 set 都会等待 Redis 响应,网络延迟大。
  • Pipeline:减少网络请求次数,提高吞吐量。

3. Pipeline vs. MULTI/EXEC(事务)

Pipeline 不是事务,它只减少了网络往返次数,而 MULTI/EXEC 是 Redis 事务机制。

pipe = r.pipeline()
pipe.multi()  # 开始事务
pipe.set("keyA", "valueA")
pipe.set("keyB", "valueB")
pipe.execute()  # 事务内命令原子执行

区别:

特性PipelineMULTI/EXEC
作用批量减少网络往返保证事务原子性
是否保证原子性
适用场景高吞吐批量操作严格事务要求

4. Pipeline vs. Lua 脚本

如果 多个操作之间有逻辑依赖,Pipeline 可能不适用。可以使用 Lua 脚本 代替:

script = '''
redis.call('SET', KEYS[1], ARGV[1])
redis.call('SET', KEYS[2], ARGV[2])
return redis.call('GET', KEYS[1])
'''
result = r.eval(script, 2, "keyX", "keyY", "valueX", "valueY")
print(result)  # "valueX"

Lua 脚本 vs Pipeline

  • Lua 脚本:原子执行,适用于有逻辑依赖的场景。
  • Pipeline:适用于独立的批量操作。

5. Pipeline 性能测试

import redis
import timer = redis.Redis(host='localhost', port=6379, db=0)# 普通方式
start = time.time()
for i in range(10000):r.set(f"key:{i}", f"value:{i}")
end = time.time()
print(f"普通方式耗时: {end - start:.3f} 秒")# Pipeline 方式
start = time.time()
pipe = r.pipeline()
for i in range(10000):pipe.set(f"key:{i}", f"value:{i}")
pipe.execute()
end = time.time()
print(f"Pipeline 耗时: {end - start:.3f} 秒")

测试结果(示例):

普通方式耗时: 1.543 秒
Pipeline 耗时: 0.120 秒

Pipeline 速度提升了 10 倍以上!


总结

方法适用场景优势劣势
Pipeline高吞吐批量操作减少网络往返,提高性能不能保证原子性
事务(MULTI/EXEC)需要原子操作的场景保证事务原子性仍有网络延迟
Lua 脚本有逻辑依赖的复杂操作原子执行,性能高代码复杂度较高

最佳实践

  • 批量写入时,使用 Pipeline
  • 需要原子操作时,使用 事务(MULTI/EXEC)
  • 复杂逻辑依赖时,使用 Lua 脚本

这样,你可以高效地使用 Redis Pipeline 来优化你的应用! 🚀

文章来源:https://blog.csdn.net/maply/article/details/145360557
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/embedded/158627.html

相关文章

C++,STL 简介:历史、组成、优势

文章目录 引言一、STL 的历史STL 的核心组成三、STL 的核心优势四、结语进一步学习资源&#xff1a; 引言 C 是一门强大且灵活的编程语言&#xff0c;但其真正的魅力之一在于其标准库——尤其是标准模板库&#xff08;Standard Template Library, STL&#xff09;。STL 提供了…

14-6-2C++STL的list

(一&#xff09;list对象的带参数构造 1.list&#xff08;elem);//构造函数将n个elem拷贝给本身 #include <iostream> #include <list> using namespace std; int main() { list<int> lst(3,7); list<int>::iterator it; for(itlst.begi…

Android-音频采集

前言 音视频这块&#xff0c;首先是要先采集音频。今天我们就来深入探讨一下 Android 音频采集的两大类型&#xff1a;Mic 音频采集和系统音频采集。 Mic音频采集 Android提供了两个API用于实现录音功能&#xff1a;android.media.AudioRecord、android.media.MediaRecorder。…

tomcat的accept-count、max-connections、max-threads三个参数的含义

tomcat的accept-count、max-connections、max-threads三个参数的含义 tomcat的accept-count、max-connections、max-threads三个参数的含义 max-connections&#xff1a;最大连接数 最大连接数是指&#xff0c;同一时刻&#xff0c;能够连接的最大请求数 需要注意的是&#x…

Oracle迁移DM数据库

Oracle迁移DM数据库 本文记录使用达梦官方数据迁移工具DTS&#xff0c;将Oracle数据库的数据迁移至达梦数据库。 1 数据准备 2 DTS工具操作步骤 2.1 创建工程 打开DTS迁移工具&#xff0c;点击新建工程&#xff0c;填写好工程信息&#xff0c;如图&#xff1a; 2.2 新建迁…

Debezium Schema History Recovery 机制详解

Debezium Schema History Recovery 机制详解 1. 概述 在 Debezium 中,准确地恢复和维护数据库的 schema 历史记录对于确保数据捕获的正确性至关重要。本文将详细介绍 Debezium 如何实现这一机制。 2. 为什么需要 Schema History? 在数据库变更数据捕获(CDC)过程中,schem…

1.CSS的三大特性

css有三个非常重要的三个特性&#xff1a;层叠性、继承性、优先级 1.1 层叠性 想通选择器给设置想听的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一个冲突的样式。层叠性主要是解决样式冲突的问题。 <!DOCTYPE html> <html lang"en&…

Excel 技巧21 - Excel中整理美化数据实例,Ctrl+T 超级表格(★★★)

本文讲Excel中如何整理美化数据的实例&#xff0c;以及CtrlT 超级表格的常用功能。 目录 1&#xff0c;Excel中整理美化数据 1-1&#xff0c;设置间隔行颜色 1-2&#xff0c;给总销量列设置数据条 1-3&#xff0c;根据总销量设置排序 1-4&#xff0c;加一个销售趋势列 2&…