Redis 7.x 系列【19】管道

有道无术,术尚可求,有术无道,止于术。

本系列Redis 版本 7.2.5

源码地址:https://gitee.com/pearl-organization/study-redis-demo

文章目录

    • [1. 往返时间](#1. 往返时间)
    • [2. 管道技术](#2. 管道技术)
    • [3. 代码演示](#3. 代码演示)
    • [4. 其他批处理](#4. 其他批处理)
      • [4.1 原生批处理命令](#4.1 原生批处理命令)
      • [4.2 事务](#4.2 事务)
      • [4.3 脚本](#4.3 脚本)

1. 往返时间

官方文档

Redis 是一种基于 CS 模型以及请求/响应 协议的TCP服务。通常情况下一个请求会遵循以下步骤:

  • 客户端向服务端发送一个请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
  • 服务端处理命令,并将结果返回给客户端。

例如,一个客户端发送四次命令的流程如下所示:

客户端和服务端之间通过网络进行连接通信,无论网络延迟如何,数据包从客户端到服务端的传输,以及从服务端回到客户端的响应,都需要一定的时间,这段时间被称为往返时间RTT)。

当客户端需要连续执行许多请求时,例如向同一列表添加多个元素或者将数据库填充多个键,往返时间如何影响性能就很容易理解了。例如,如果往返时间为250毫秒(非常慢的连接),即使服务端能够每秒处理10万个请求,客户端每秒也只能发送四个请求。

2. 管道技术

对于上述问题,Redis 提供了管道(Plpeline)技术,允许客户端将多个命令一次性发送给服务器,而不需要等待每个命令的回复。这样可以减少每条命令的网络延迟时间,特别适合需要发送大量命令的场景。

执行流程如下所示:

管道技术不仅减少了 RTT ,并且极大地提升了在 Redis 服务器上每秒可以执行的操作数量。

使用注意事项:

  • 使用管道时,命令只是会依次以行,不保证原子性,如果其中某个命令令发生异常,将会继续执行
  • 组装的命令个数不能太多,不然数据量太大时,客户端阻塞的时间可能过久,同时服务端此时也被迫回复一个队列答复,占用很多内存
  • 需要发送大量的命令时,需要按照合理数量分批次的处理,例如一次发送10K的命令,读取回复后,后再发送另一个10k的命令。

3. 代码演示

下面代码中,使用 Jedis 插入 10000Key

java 复制代码
    public static void main(String[] args) {
        // 创建连接池
        JedisPool pool = new JedisPool("localhost", 6379,"default","123456");
        // 获取客户端
        try (Jedis jedis = pool.getResource()) {

            // 1. 不使用管道, 插入 10000 个 Key
            long startTime = System.currentTimeMillis();
            for (int i = 10000; i > 0; i--) {
                jedis.set("key" + i, String.valueOf(i));
            }
            System.out.println("不使用管道执行时间:" + ( System.currentTimeMillis()-startTime)+"毫秒");

            // 2. 使用管道
            startTime = System.currentTimeMillis();
            Pipeline pipelined = jedis.pipelined();
            for (int i = 10000; i > 0; i--) {
                pipelined .set("key" + i, String.valueOf(i));
            }
            System.out.println("使用管道执行时间:" + ( System.currentTimeMillis()-startTime)+"毫秒");
        }
    }

可以看到,在使用了管道后,执行时间缩短了近 30 倍:

java 复制代码
不使用管道执行时间:793毫秒
使用管道执行时间:26毫秒

对于查询命令,当然也可以使用管道,不过结果值是批量返回的:

java 复制代码
            Pipeline pipelined = jedis.pipelined();
            for (int i = 10000; i > 0; i--) {
                //pipelined .set("key" + i, String.valueOf(i));
                pipelined.get("key" + i);
            }
            // 获取执行结果
            List<Object> results = pipelined.syncAndReturnAll();

4. 其他批处理

除了管道, Redis 还提供了其他批处理 方式,可以根据具体需求选择合适的方式来操作 Redis

4.1 原生批处理命令

Redis 提供了两个常用的原生命令来处理多个键的操作:

  • MGET: 同时获取多个键的值
  • MSET: 同时设置多个键的值

MGETMSET 命令都是原子操作,即要么全部执行成功,要么全部执行失败。适合于需要一次性获取或设置多个键值对的场景。

示例:

java 复制代码
MGET key1 key2 key3
MSET key1 value1 key2 value2 key3 value3

4.2 事务

通过事务机制,可以将多个命令打包在一起执行,事务中的所有命令要么全部执行,要么全部不执行。

示例:

java 复制代码
MULTI
SET key1 value1
GET key2
INCR key3
EXEC

4.3 脚本

通过 Redis 脚本,可以将多个命令打包成一个原子操作,确保在执行期间不会被其他命令打断。

示例:

bash 复制代码
local result1 = redis.call('SET', KEYS[1], ARGV[1])
local result2 = redis.call('GET', KEYS[2])
local result3 = redis.call('INCR', KEYS[3])
return {result1, result2, result3}
相关推荐
Code apprenticeship17 分钟前
怎么利用Redis实现延时队列?
数据库·redis·缓存
百度智能云技术站20 分钟前
广告投放系统成本降低 70%+,基于 Redis 容量型数据库 PegaDB 的方案设计和业务实践
数据库·redis·oracle
装不满的克莱因瓶23 分钟前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
fpcc2 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
Ewen Seong2 小时前
mysql系列5—Innodb的缓存
数据库·mysql·缓存
安全二次方security²2 小时前
SMMU软件指南SMMU编程之虚拟机结构和缓存
缓存·cache·smmu·arm安全架构·系统mmu·虚拟机结构·vms
黄名富4 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
G_whang5 小时前
centos7下docker 容器实现redis主从同步
redis·docker·容器
.生产的驴5 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
我叫啥都行8 小时前
计算机基础复习12.22
java·jvm·redis·后端·mysql