说说 Redis pipeline
更多技术文章,请关注我的个人博客 www.immaxfang.com 和小公众号
Max的学习札记。
Redis 客户端和服务端之间是采用 TCP 协议进行通信的,是基于 Request/Response 这种一问一答的模式,即请求一次响应一次。
普通模式
我们先来看下普通模式下,一条 Redis 命令的简要执行过程:
- 客户端发送一条命令给 redis-server,阻塞等待 redis-server 应答
- redis-server 接收到命令,执行命令
- redis-server 将结果返回给客户端

下面我们来简要了解下一个完整请求的交互过程。
- 客户端调用 write() 将消息写入操作系统为 socket 分配的 send buffer 中
- 操作系统将 send buffer 中的内容发送到网卡,网卡通过网关路由把内容发送到服务器网卡
- 服务器网卡将接受到的消息写入操作系统为 socket 分配的 recv buffer
- 服务器进程调用 read() 从 recv buffer 中读取消息进行处理
- 处理完成之后,服务器调用 write() 将响应内容发送的 send buffer 中
- 服务器将 send buffer 中的内容通过网卡,发送到客户端
- 客户端操作系统将网卡中的内容放入 recv buffer 中
- 客户端进程调用 read() 从 recv buffer 中读取消息
普通模式的问题
我们来想一下,这种情况下可能导致什么问题。
如果同时执行大量的命令,那对于每一个命令,都要按上面的流程走一次,当前的命令需要等待上一条命令执行应答完毕之后,才会执行。这个过程中会有多次的 RTT ,也还会伴随着很多的 IO 开销,发送网络请求等。每条命令的发送和接收的过程都会占用两边的网络传输。
简单的来说,每个命令的执行时间 = 客户端发送耗时 + 服务器处理耗时 + 服务器返回耗时 + 一个网络来回耗时。
在这里,一个 网络来回耗时(RTT) 是不好控制的,也是不稳定的。它的影响因素很多,比如客户端到服务器的网络线路是否拥堵,经过了多少跳。还有就是 IO 系统调用也是耗时的,一个 read 系统调用,需要从用户态,切换到内核态。上文我们讲述一个命令的请求过程时多次降到 read 和 write 系统调用。
可以说一个命令的执行时间,很大程度上受到它们的限制。
pipeline 模式
有没有什么方法来解决这种问题呢。
第一种方法,就是利用多线程机制,并行执行命令。
第二种方法,调用批量命令,例如 mget等,一次操作多个键。
很多时候我们要执行的命令并不是一样的命令,而是一组命令,这个时候就无法使用类似 mget这样的批量命令了。那还有其他的方法吗?
回想一下,我们初学编程的时候,老手都会告诉我们,不要在循环里面做查询。我有一个 books 列表数据,要根据 book_id 查询它们的 price,如果我们循环 books 列表,在每次循环里面取查询单个 book_id 的 price,那性能肯定是不理想的。一般我们的优化方式是将多个 book_id 取出来,一次性去查多个 book_id 的 price,这样性能就有明显的提示。即将多次小命令中的耗时操作合并到一次,从而减少总的执行时间。
类似的,Redis pipeline 出现了,一般称之为管道。它允许客户端一次可以发送多条命令,而不用像普通模式那样每次执行一个小命令都要等待前一个小命令执行完,服务器在接收到一堆命令后,会依次执行,然后把结果打包,再一次性返回给客户端。
这样可以避免频繁的命令发送,减少 RTT,减少 IO 调用次数。前面已经介绍了,IO 调用会涉及到用户态和内核态之间的切换,在高性能的一些系统中,我们都是尽可能的减少 IO 调用。
简要流程如下图:
- pipeline 的优点
- 减少 RTT
- 减少 IO 调用次数
- 基本使用
Pipeline pipeline =jedis.pipelined();
for(int i = 0; i < 100; i++){
pipeline.rpush("rediskey", i + "");
}
pipeline.sync()
总结一下 pipeline 的核心,就是客户端将一组 Redis 命令进行组装,通过一次 RTT 发送给服务器,同时服务器再将这组命令的执行结果按照顺序一次返回给客户端。
pipeline 注意问题
虽然 pipeline 在某些情况下会带来不小的性能提升,但是,我们在使用的时候也需要注意。
- pipeline 中的命令数量不宜过多。
客户端会先将多个命令写入内存 buffer 中(打包),命令过多,如果是超过了客户端设置的 buffer 上限,被客户端的处理策略处理了(不同的客户端实现可能会有差异,比如 jedis pipeline ,限制每次最大的发送字节数为 8192,缓冲区满了就发送,然后再写缓冲,最后才处理 Redis 服务器的应答)。如果客户端没有设置 buffer 上限或不支持上限设置,则会占用更多的客户端机器内存,造成客户端瘫痪。官方推荐是每次 10k 个命令。
建议做好规范,遇到一次包含大量命令的 pipeline,可以拆分成多个稍小的 pipeline 来完成。
- pipeline 一次只能运行在一个 Redis 节点上,一些集群或者 twemproxy 等中间件使用需要注意。
在集群环境下,一次 pipeline 批量执行多个命令,每个命令需要根据 key 计算槽位,然后根据槽位去特定的节点上去执行命令,这样一次 pipeline 就会使用多个节点的 redis 连接,这种当前也是不支持的。
- pipeline 不保证原子性,如要求原子性,不建议使用 pipeline
它仅是将多个命令打包发送出去而已,如果中间有命令执行异常,也会继续执行剩余命令。
pipeline 与批量操作 mget 等区别
其实 meget和 pipeline 优化的方向是一致的,即多个命令打包一次发送,减少网络时间。但是也是有区别的。
mget等的场景是一个命令对应多个键值对,而 pipeline 一般是多条命令(不同的命令)mget操作是一个原子操作,而 pipeline 不是原子操作mget是服务端实现,而 pipeline 是客户端和服务端共同实现
pipeline 与事务的区别
这两者关注和解决的问题不是一个东西,原理也不一样。
- pipeline 是一次请求,服务端顺序执行,一次返回。而事务是多次请求(先 multi,再多个操作命令,最后 exec),服务端顺序执行,一次返回
- pipeline 关注的是 RTT 时间和 IO 调用,事务关注的是一致性问题
总结
本文主要讲了多命令执行时耗时问题,以及 pipeline 的解决方法,和其简单的原理,以及注意点。今天的学习就到这里,改天我们接着肝。
说说 Redis pipeline的更多相关文章
- redis pipeline
redis pipeline 简而言之就是把多个redis命令打包,一起发送给redis server,并且一起返回结果,减少客户端和服务器之间的多次“折返跑”
- 如何用好redis pipeline
编者注:pipeline是Redis的一个提高吞吐量的机制,适用于多key读写场景,比如同时读取多个key的value,或者更新多个key的value.工作过程中发现挺多小伙伴都对pipeline多少 ...
- 【spring boot】spring boot 基于redis pipeline 管道,批量操作redis命令
spring boot 2.x 使用RedisTemplate 操作 =================================== 1.pom.xml <!--spring2.0集成r ...
- laravel中redis pipeline用法说明
$res = Redis::pipeline(function($pipe) use($params) { for ($i = 0; $i < 1000; $i++) { $pipe->g ...
- redis 学习(11)-- redis pipeline
redis pipeline 什么是流水线(pipeline) 首先来看 redis 执行一次操作所需要的时间: 1 次时间 = 1 次网络时间 + 1次命令时间 执行 n 次就需要: n 次时间 = ...
- 等待 Redis 应答 Redis pipeline It's not just a matter of RTT
小结: 1.When pipelining is used, many commands are usually read with a single read() system call, and ...
- (7)redis pipeline
redis是一个cs模式的tcp server,使用和http类似的请求响应协议.一个client可以通过一个socket连接发起多个请求命令.每个请求命令发出后client通常 会阻塞并等待redi ...
- Redis pipeline and list
Redis Redis 是一个开源的基于内存的数据结构存储器.通常可作为数据库,缓存和消息中介.它支持的数据结构有:字符串.哈希表.列表.集合.支持范围查询的有序集合.位图.hyperloglogs和 ...
- Redis Pipeline原理分析
转载请注明出处:http://www.cnblogs.com/jabnih/ 1. 基本原理 1.1 为什么会出现Pipeline Redis本身是基于Request/Response协议的,正常情况 ...
随机推荐
- powershell 执行策略
前言 上一篇博文,我介绍了一下powershell和cmd的对比.通过学习,我发现powershell的确比cmd更加power,也更加适应现在的使用场景. 那么本文将继续介绍一个powershell ...
- JVM 系列(4)一看就懂的对象内存布局
请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...
- Luogu2343 宝石管理系统(平衡树)
平衡树维护总第K大:插入 #include <iostream> #include <cstdio> #include <cstring> #include < ...
- Mybatis的ResultMap与limit分页查询
ResultMap主要解决的是:属性名和字段不一致 如果在pojo中设置的是一个名字,在数据库上又是另一个名字,那么查询出来的结果或者其他操作的结果就为null. //在pojo中 private S ...
- 【PMP学习笔记】第5章 项目范围管理
一.规范管理的内涵 项目范围管理:包括确保项目做且只做所需的全部工作,以成功完成项目的各个过程. 项目范围:为交付具有规定特性与功能的产品.服务或成果而必须完成的工作. 预测型:开始时定义可交付成果, ...
- KingbaseES R6集群归档备份故障分析解决案例
案例说明: 在使用ps工具查看主库进程,发现主库'archiver'进程失败,检查sys_log日志可以发现归档失败的信息.通过sys_log日志提取归档语句手工执行归档操作,提示"当前数据 ...
- KingbaseFlySync 专用机版本升级
关键字: KingbaseFlySync.Linux.x86_64.mips64el.aarch64.Java 专线机版本升级 1.备份kfs配置文件和rename问题,kufl目录 fsrepctl ...
- 全能成熟稳定开源分布式存储Ceph破冰之旅-上
@ 目录 概述 定义 传统存储方式及问题 优势 生产遇到问题 架构 总体架构 组成部分 CRUSH算法 数据读写过程 CLUSTER MAP 部署 部署建议 部署版本 部署方式 Cephadm部署 前 ...
- 干货分享!JAVA诊断工具Arthas在Rainbond上实践~
别再担心线上 Java 业务出问题怎么办了,Arthas 帮助你解决以下常见问题: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 ...
- 接口测试神器Apifox,亲测好用!
自己关注的公众号比较多,之前有收到过有关 Apifox 的文章,自己也是大致看看,还没有用过它! 最近看到比较多有关 Apifox 的文章,所以自己就花了点时间去研究它,使用完后发现确实比Postma ...