Redis 为什么要引入 Pipeline机制?

在 Redis 中有一种 Pipeline(管道)机制,其目的是提高数据传输效率和吞吐量。那么,Pipeline是如何工作的?它又是如何提高性能的?Pipeline有什么优缺点?我们该如何使用 Pipeline?

1、Redis Pipeline是什么?

Redis Pipeline 是一种批量执行命令的技术,允许客户端在不等待服务器响应的情况下,一次性发送多个命令到 Redis 服务器。传统的请求-响应模式中,客户端每发送一个命令,就需要等待服务器响应后才能发送下一个命令,这种模式在高延迟网络环境下,严重影响 Redis 的性能表现。

Pipeline 通过消除或减少网络往返次数(Round-Trip Time, RTT),能够显著提高命令执行的吞吐量,客户端可以将多个命令打包发送,服务器则依次执行这些命令并将结果返回给客户端,从而有效地提升了网络利用率和整体性能。

2、为什么引入 Pipeline?
在了解 Redis为什么引入 Pipeline之前,我们先来了解传统请求-响应模式,在传统的请求-响应模式中,客户端与服务器之间的通信流程如下:

  • 客户端发送一个命令到服务器。
  • 服务器接收命令并执行。
  • 服务器将执行结果返回给客户端。
  • 客户端接收结果后,发送下一个命令。

在这里插入图片描述

在这种传统的模式下,每个命令都需要经历完整的 RTT,这在高延迟网络环境下会导致显著的性能瓶颈。

而 Pipeline的核心思想是“命令打包,高效传输”。其工作流程可以总结成下面 5个步骤:

  • 打包命令: 客户端将多个 Redis 命令按照特定的格式打包成一个请求包。
  • 发送命令: 将打包好的请求一次性发送给 Redis 服务器。
  • 执行命令: Redis 服务器按顺序执行接收到的所有命令。
  • 接收响应: 服务器将所有命令的执行结果按顺序返回给客户端。
  • 解析响应: 客户端解析接收到的响应,并将结果对应到各个命令。

在这里插入图片描述

这种方式通过减少网络往返次数,有效降低网络延迟对性能的影响,特别适合于需要执行大量 Redis 命令的高并发场景。

尽管 Pipeline带来了性能的提升,但它也有一些缺点:

  • 资源消耗: 发送大量命令一次性执行,可能会消耗较多的服务器资源,导致 Redis 其他操作的响应时间增加。
  • 错误处理复杂: 在批量执行命令时,单个命令的错误处理可能变得复杂,需要逐一检查每个命令的执行结果。
  • 顺序依赖: 如果命令之间存在顺序依赖,Pipeline 的批量执行需要确保正确的命令顺序。
  • 不支持事务功能: Pipeline 只是批量执行命令的工具,不具备事务的原子性和隔离性。
  • 客户端支持: 不同的 Redis 客户端对 Pipeline 的支持程度不同,使用时需考虑所选客户端库的特性和限制。

3、源码分析
在 Java中,常见的 Redis 客户端库有 Jedis 和 Lettuce两种,下面我们将分别分析这两个库实现 Pipeline功能。

3.1 使用 Jedis 库
Jedis 是一个简单、直观的 Redis 客户端,支持 Pipeline 功能。下面的示例展示如何使用 Jedis实现 Pipeline操作。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;import java.util.ArrayList;
import java.util.List;publicclass JedisPipelineExample {public static void main(String[] args) {// Redis 连接参数String redisHost = "localhost";int redisPort = 6379;String redisPassword = null; // 若有密码,填写密码// 连接 Redistry (Jedis jedis = new Jedis(redisHost, redisPort)) {if (redisPassword != null && !redisPassword.isEmpty()) {jedis.auth(redisPassword);}// 批量设置键值对batchSet(jedis);// 批量获取键值对batchGet(jedis);} catch (Exception e) {e.printStackTrace();}}/*** 使用 Pipeline 批量设置键值对** @param jedis Jedis 实例*/public static void batchSet(Jedis jedis) {System.out.println("开始批量设置键值对...");Pipeline pipeline = jedis.pipelined();int numCommands = 1000;for (int i = 0; i < numCommands; i++) {pipeline.set("key-" + i, "value-" + i);}// 执行所有命令pipeline.sync();System.out.println("批量设置完成,共设置 " + numCommands + " 个键值对。");}/*** 使用 Pipeline 批量获取键值对*/public static void batchGet(Jedis jedis) {System.out.println("开始批量获取键值对...");Pipeline pipeline = jedis.pipelined();int numCommands = 1000;List<Response<String>> responses = new ArrayList<>(numCommands);for (int i = 0; i < numCommands; i++) {Response<String> response = pipeline.get("key-" + i);responses.add(response);}// 执行所有命令pipeline.sync();// 处理结果for (int i = 0; i < numCommands; i++) {String value = responses.get(i).get();System.out.println("key-" + i + " = " + value);}System.out.println("批量获取完成,共获取 " + numCommands + " 个键值对。");}
}

代码解析

上面的代码主要总结为 4个步骤:

1、连接 Redis:

使用 Jedis 类连接 Redis 服务器。如果 Redis 服务器设置了密码,需要调用 jedis.auth 进行认证。

2、批量设置键值对:

  • 调用 jedis.pipelined() 获取一个 Pipeline 对象。
  • 使用循环将多个 set 命令添加到 Pipeline 中。
  • 调用 pipeline.sync() 发送所有命令并等待执行结果。
  • 通过 Pipeline 一次性提交所有命令,减少了网络往返次数。

3、批量获取键值对:

  • 同样使用 pipelines 获取 Pipeline 对象。
  • 使用 pipeline.get 方法批量添加 get 命令,并将 Response 对象保存到列表中。
  • 调用 pipeline.sync() 发送所有命令并等待执行结果。
  • 遍历 Response 对象列表,获取每个键的值。

4、关闭连接:

使用 try-with-resources 语法自动关闭 Jedis 连接,确保资源的正确释放。

3.2 使用 Lettuce 库
Lettuce 是一个基于 Netty 的可伸缩、多线程的 Redis 客户端,支持异步和反应式编程模型,同样支持 Pipeline 功能。

以下示例展示如何使用 Lettuce 实现 Pipeline 操作,包括批量设置和获取键值对。

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.api.sync.SyncCommands;
import io.lettuce.core.api.sync.RedisScriptingCommands;
import io.lettuce.core.api.sync.RedisClusterCommands;import java.util.ArrayList;
import java.util.List;publicclass LettucePipelineExample {public static void main(String[] args) {// Redis 连接参数String redisHost = "localhost";int redisPort = 6379;String redisPassword = null; // 若有密码,填写密码// 创建 RedisURIRedisURI redisURI = RedisURI.Builder.redis(redisHost).withPort(redisPort).withPassword(redisPassword != null ? redisPassword.toCharArray() : null).build();// 创建 RedisClientRedisClient redisClient = RedisClient.create(redisURI);// 建立连接try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {RedisCommands<String, String> syncCommands = connection.sync();// 批量设置键值对batchSet(syncCommands);// 批量获取键值对batchGet(syncCommands);} catch (Exception e) {e.printStackTrace();} finally {// 关闭客户端redisClient.shutdown();}}/*** 使用 Lettuce 的 Pipeline 批量设置键值对** @param syncCommands 同步命令接口*/public static void batchSet(RedisCommands<String, String> syncCommands) {System.out.println("开始批量设置键值对...");int numCommands = 1000;for (int i = 0; i < numCommands; i++) {syncCommands.set("key-" + i, "value-" + i);}// 批量执行所有命令syncCommands.getStatefulConnection().flushCommands();System.out.println("批量设置完成,共设置 " + numCommands + " 个键值对。");}/*** 使用 Lettuce 的 Pipeline 批量获取键值对** @param syncCommands 同步命令接口*/public static void batchGet(RedisCommands<String, String> syncCommands) {System.out.println("开始批量获取键值对...");int numCommands = 1000;List<String> keys = new ArrayList<>(numCommands);for (int i = 0; i < numCommands; i++) {keys.add("key-" + i);}List<String> values = syncCommands.mget(keys.toArray(new String[0])).stream().map(res -> res.getValue()).toList();for (int i = 0; i < numCommands; i++) {System.out.println(keys.get(i) + " = " + values.get(i));}System.out.println("批量获取完成,共获取 " + numCommands + " 个键值对。");}
}

代码解析

上面的代码主要总结为 4个步骤:

1、连接 Redis:

使用 RedisClient 创建连接,RedisURI 封装了连接参数。如果 Redis 服务器设置了密码,需要在 RedisURI 中指定。

2、批量设置键值对:

  • 使用 syncCommands.set 方法批量添加 set 命令。
  • 调用 flushCommands() 方法将所有积累的命令一次性发送到服务器。

注:Lettuce 的 Pipeline 支持隐式的 Pipeline,即没有显式的 Pipeline API,通过积累命令并调用 flushCommands() 实现批量发送。

3、批量获取键值对:

使用 mget 方法一次性获取多个键的值,这是 Lettuce 提供的批量获取命令,天然支持 Pipeline。
mget 返回一个包含每个键值的 List,通过流处理提取值。

4、关闭连接:

使用 try-with-resources 语法自动关闭连接,最后调用 redisClient.shutdown() 关闭 Redis 客户端。

尽管 Lettuce 支持 Pipeline,但其 API 不如 Jedis 那样显式。要实现更细粒度的 Pipeline 控制,可以使用 Lettuce 的命令缓冲机制或异步 API。上述示例中展示的是同步方式,适用于简单的批量操作。

4、使用场景

  • 批量设置键值对: 将大量键值对一次性写入 Redis,适用于数据初始化或大规模更新。
  • 批量获取键值对: 在需要同时获取多个键的值时,通过 Pipeline 减少请求次数,提高效率。
  • 分布式计数器: 高并发情况下,使用 Pipeline 聚合多个计数操作,提升吞吐量。
  • 缓存预热: 在应用启动或重启时,通过 Pipeline 将常用数据加载到缓存中,提高应用启动性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/67057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

游戏引擎学习第78天

Blackboard: Position ! Collision “网格” 昨天想到的一个点&#xff0c;可能本来就应该想到&#xff0c;但有时反而不立即思考这些问题也能带来一些好处。节目是周期性的&#xff0c;每天不需要全程关注&#xff0c;通常只是在晚上思考&#xff0c;因此有时我们可能不能那么…

使用 C# 制作图像的特写窗口

许多网站都会显示一个特写窗口&#xff0c;其中显示放大的图像部分&#xff0c;以便您可以看到更多细节。您在主图像上移动鼠标&#xff0c;它会在单独的图片中显示特写。此示例执行的操作类似。&#xff08;示例使用的一些数学运算非常棘手&#xff0c;因此您可能需要仔细查看…

Python学习(三)基础入门(数据类型、变量、条件判断、模式匹配、循环)

目录 一、第一个 Python 程序1.1 命令行模式、Python 交互模式1.2 Python的执行方式1.3 SyntaxError 语法错误1.4 输入和输出 二、Python 基础2.1 Python 语法2.2 数据类型1&#xff09;Number 数字2&#xff09;String 字符串3&#xff09;List 列表4&#xff09;Tuple 元组5&…

【MySQL】SQL菜鸟教程(一)

1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…

力扣257(关于回溯算法)二叉树的所有路径

257. 二叉树的所有路径 一.问题描述 已解答 简单 相关标签 相关企业 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,null,5…

Redis有哪些常用应用场景?

大家好&#xff0c;我是锋哥。今天分享关于【Redis有哪些常用应用场景&#xff1f;】面试题。希望对大家有帮助&#xff1b; Redis有哪些常用应用场景&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 是一个高性能的开源键值对&#xff08;Key-Va…

【2024年华为OD机试】(A卷,100分)- 处理器问题(Java JS PythonC/C++)

一、问题描述 题目描述 某公司研发了一款高性能AI处理器。每台物理设备具备8颗AI处理器&#xff0c;编号分别为0、1、2、3、4、5、6、7。 编号0-3的处理器处于同一个链路中&#xff0c;编号4-7的处理器处于另外一个链路中&#xff0c;不通链路中的处理器不能通信。 如下图所…

设计模式-结构型-组合模式

1. 什么是组合模式&#xff1f; 组合模式&#xff08;Composite Pattern&#xff09; 是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。换句话说&#xff0c;组合模式允…

HQChart使用教程30-K线图如何对接第3方数据44-DRAWPIE数据结构

HQChart使用教程30-K线图如何对接第3方数据44-DRAWPIE数据结构 效果图DRAWPIEHQChart代码地址后台数据对接说明示例数据数据结构说明效果图 DRAWPIE DRAWPIE是hqchart插件独有的绘制饼图函数,可以通过麦语法脚本来绘制一个简单的饼图数据。 饼图显示的位置固定在右上角。 下…

Proser:升级为简易的通讯调试助手软件

我本来打算将Proser定位为一个直观的协议编辑、发送端模拟软件&#xff0c;像下面这样。 但是按耐不住升级的心理&#xff0c;硬生生的把即时收发整合了进去&#xff0c;就像这样&#xff01; 不过&#xff0c;目前针对即时收发还没有发送历史、批量发送等功能&#xff0c;…

PyTorch环境配置常见报错的解决办法

目标 小白在最基础的环境配置里一般都会出现许多问题。 这里把一些常见的问题分享出来。希望可以节省大家一些时间。 最终目标是可以在cmd虚拟环境里进入jupyter notebook&#xff0c;new的时候有对应的环境&#xff0c;并且可以跑通所有的import code。 第一步&#xff1a;…

【Linux系列】Curl 参数详解与实践应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Web基础-分层解耦

思考&#xff1a;什么是耦合&#xff1f;什么是内聚&#xff1f;软件设计原则是什么&#xff1f; 耦合&#xff1a;衡量软件中各个层 / 各个模块的依赖关联程度。 内聚&#xff1a;软件中各个功能模块内部的功能联系。 软件设计原则&#xff1a;高内聚低耦合。 那我们该如何实现…

算法题(33):长度最小的子数组

审题: 需要我们找到满足元素之和大于等于target的最小子数组的元素个数&#xff0c;并返回 思路&#xff1a; 核心&#xff1a;子数组共有n种起点&#xff0c;nums数组的每个元素都可以充当子数组的首元素&#xff0c;我们只需要先确定子数组的首元素&#xff0c;然后往后查找满…

网络数据通信基本流程

1.基本概念 网络通信就是发送数据、接收数据、处理数据的过程&#xff0c;发送数据时要读数据进行处理&#xff08;封装&#xff09;&#xff0c;接收数据时也要对数据进行处理&#xff08;分用&#xff09;&#xff0c; 1&#xff09;封装 对数据进行加工处理&#xff0c;如…

科创驱动 | 华望系统科技荣膺西湖区年度前沿创新新锐企业

2025年1月3日&#xff0c;由中共西湖区党委、西湖区人民政府主办的“新年第一会”—西湖区科技创新大会在杭州隆重举行。大会现场揭晓了西湖区年度科技创新团队与项目&#xff0c;并发布了“2024西湖区科技十大事件”与“西湖区五大年度科技榜单”。杭州华望系统科技有限公司榜…

Java Web开发基础:HTML的深度解析与应用

文章目录 前言&#x1f30d;一.B/S 软件开发架构简述&#x1f30d;二.HTML 介绍❄️2.1 官方文档❄️2.2 网页的组成❄️2.3 HTML 是什么❄️2.4html基本结构 &#x1f30d;三.HTML标签1.html 的标签/元素-说明2. html 标签注意事项和细节3.font 字体标签4.标题标签5.超链接标签…

点亮一个esp32 的led

最近入了一个ESP32 兄弟们&#xff0c;这玩意还可以&#xff0c;买来肯定是给它点亮啊对吧 我就是点灯侠&#x1f387; &#x1f62d;千万不要不接天线啊&#xff0c;不然你会一直找不到你的wifi 1.点灯第一步你得有IDE Arduino 就是这个绿东西 可是怎么下载安装呢&#xff…

CI/CD 流水线

CI/CD 流水线 CI 与 CD 的边界CI 持续集成CD&#xff08;持续交付/持续部署&#xff09;自动化流程示例&#xff1a; Jenkins 引入到 CI/CD 流程在本地或服务器上安装 Jenkins。配置 Jenkins 环境流程设计CI 阶段&#xff1a;Jenkins 流水线实现CD 阶段&#xff1a;Jenkins 流水…

HTB:Bastion[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用enum4linux…