草庐IT

说说 Redis pipeline

maxfang 2023-03-28 原文

更多技术文章,请关注我的个人博客 www.immaxfang.com 和小公众号 Max的学习札记

Redis 客户端和服务端之间是采用 TCP 协议进行通信的,是基于 Request/Response 这种一问一答的模式,即请求一次响应一次。

普通模式

我们先来看下普通模式下,一条 Redis 命令的简要执行过程:

  • 客户端发送一条命令给 redis-server,阻塞等待 redis-server 应答
  • redis-server 接收到命令,执行命令
  • redis-server 将结果返回给客户端


下面我们来简要了解下一个完整请求的交互过程。

  1. 客户端调用 write() 将消息写入操作系统为 socket 分配的 send buffer 中
  2. 操作系统将 send buffer 中的内容发送到网卡,网卡通过网关路由把内容发送到服务器网卡
  3. 服务器网卡将接受到的消息写入操作系统为 socket 分配的 recv buffer
  4. 服务器进程调用 read() 从 recv buffer 中读取消息进行处理
  5. 处理完成之后,服务器调用 write() 将响应内容发送的 send buffer 中
  6. 服务器将 send buffer 中的内容通过网卡,发送到客户端
  7. 客户端操作系统将网卡中的内容放入 recv buffer 中
  8. 客户端进程调用 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的更多相关文章

  1. 简单说说量化交易接口有哪些用途? - 2

    量化交易应该大家都知道是什么回事,但是量化交易接口又是个什么玩意呢?今日我们就来说说量化交易接口的一些用途。其实,量化交易接口的用途很明确,就是为量化交易服务的,具体来讲,它可以帮助量化投资者获取实时和历史行情数据、批量委托下单撤单、获取五档/十档报价,甚至还可以进行融资融券交易还款等等,也有一些量化交易接口可以进行交易策略编写,对于想做自动化交易的投资者来讲,量化交易接口可以说是必不可少的。名称功能基本函数InitAPI初始化DeinitAPI反初始化Logon登录交易账户Logoff登出交易账户QueryData查询各类交易数据QueryHistoryData查询各类历史数据SendOrd

  2. 春招面试阿里,面试官让我说说Java8的新特性 - 2

    文章目录一、Lambda表达式和函数式接口二、接口的默认方法和静态方法三、方法引用四、重复注解五、更好的类型推断六、拓宽注解的应用场景七、Optional八、Streams九、Date/TimeAPI(JSR310)十、Base64十一、并行数组十二、并发性十三、JVM的新特性Java8是Java自Java5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。Java8新特性官网一、Lambda表达式和函数式接口Lambda表达式(也称为闭包)是Java8中最大和最令人期待的语言改变。它允许我们将

  3. 无觅科技推荐: TikTok直播专线怎么选?说说TikTok直播加速的4种方案 - 2

    目前做TikTok直播的跨境电商卖家越来越多了,大家普遍遇到的问题有几个:1、TikTok直播账号容易被限流降权,导致观众少,没转化;2、TikTok直播的时候比较卡顿,画面模糊,影响直播效果:3、海外直播观众地区偏离。比如本来是马来西亚的直播,系统却推的是其他国家的观众。以上问题怎么解决呢?今天跟大家系统化地讲讲实现TikTok直播加速的4种方案方案一:购买现成的TikTok海外代理节点该方案成本较低,一个月一般只要几十块钱。但是由于该方案的ip往往不是独享的,且不能保证是海外固定ip,所以很容易造成TikTok账号被限流,以及观众地区偏离的情况。目前市面上也有一些对外宣传是TkTok独立i

  4. 简单说说ES - 2

    ES是ELK中的E,即elasticsearch全文搜索引擎,它的英文原意是富有弹性的搜索.它的功能类似一个数据库,能高效的从大量数据中搜索匹配指定关键字的内容,它也将数据保存在硬盘中.它本质上可以理解为一个java项目,使用它进行数据的增删改查就是访问这个项目的控制器方法(url路径).es和redis/mysql一样,不仅服务于java语言,其他语言也可以使用.ES的底层技术ES使用了java的一套名为Lucene的API,这个API提供了全文搜索引擎核心操作的接口,相当于搜索引擎的核心支持,ES在Lucene的基础上进行完善,实现了开箱即用的搜索引擎软件.市面上和ES功能类似的软件还有S

  5. 说说他的好(二) - 2

    今天中午和高中同学通电话,说起我们考事业编的时候,她老公的一些举动让她至今想起来还笑话他。原来,第二天是我们考事业编面试的日子,她热情好客的老公却忙着去招待客人,还喝多了,陪客人在酒店住下,第二天醒来时已经十点。而我要面试的同学却是由她哥哥送去考场的,为了安全,他还把女儿反锁在家里,而她老公是她快面试完的时候才赶到考点。如果换作我,我爱人这样操作,我会发飙的。我同学纵然脾气比我好很多,也至今忘不掉这件事情,偶尔还会跟她爱人提起来。所以说,关键时候一定不要掉链子。我爱人让我炸毛的时候也很多,但是我同学说的面试前后的事情,他做得很好。那年我们县的事业编考试由每年的七月延期到十二月进行,笔试那天是在

  6. 面试题:说说地址栏输入 URL 敲下回车后发生了什么? - 2

    一、简单分析简单的分析,从输入URL到回车后发生的行为如下:URL解析DNS查询TCP连接HTTP请求响应请求页面渲染二、详细分析1.URL解析首先判断你输入的是一个合法的URL还是一个待搜索的关键词,并且根据你输入的内容进行对应操作URL的解析第过程中的第一步,一个url的结构解析如下:2.DNS查询DNS(DomainNamesSystem),域名系统,是互联网一项服务,是进行域名和与之相对应的IP地址进行转换的服务器。最终,获取到了域名对应的目标服务器IP地址3.TCP连接tcp是一种面向有连接的传输层协议在确定目标服务器服务器的IP地址后,则经历三次握手建立TCP连接,流程如下:4.发

  7. 我的秋招结束了,有些话想说说。 - 2

    利益相关:江西师范大学计算机信息工程学院14级网络工程本科生。前几天收到网易的offer邮件,于是立马在协会群里和各位大佬分享了喜讯。后来听学弟说打算在17级小鲜肉军训结束之后开一个纳新的宣讲会,问我去不去做个分享。由于14级的几个老油条都出去实习并要准备收割offer,就剩我一条咸鱼一直呆在学校,所以答应了到时候参加宣讲会。但是让我做分享的话,还真是不知道从哪里讲起。于是打算写一篇博客出来帮助自己捋清思路,也算是以文字的形式总结一下自己前三年的大学生活。阅读指南:本文基本结构为按时间顺序的方式进行推进,中间可能会穿插一些我的认知过程的变化。我的思维比较混乱,文笔也不太好,如果出现了时间混乱、

  8. 尴尬的面试现场:说说你们系统有多大QPS?系统到底怎么抗住高并发的? - 2

    目录1、尴尬的面试现场:第一幕2、尴尬的面试现场:第二幕3、别让你学的技术成为空中楼阁4、想方设法的“虐虐”自己这篇文章,给大家说一个同样是很多人都很迷惑的问题,因为实在是太多同学来问我类似的问题了,所以写一篇文章给大家来说一下。事情的起因是这样子的:很多好学的同学,都会自己平时研究很多的技术,比如常见的就是买书看书,参加在线培训课程,购买一些知识付费的专栏,或者购买一些视频课程。但是这些好学的同学在学了很多东西之后,出去面试都遇到了这样的一个痛点问题:这些同学简历上写了很多高大上的技术,但是其实自己可能没机会,或者还没来得及在自己手头负责的项目里用过,而且自己负责的项目好像也没很么用户量和并

  9. C++ | 说说类中的static成员 - 2

    【概念】:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化文章目录一、面试题引入二、static特性细述三、疑难解惑四、在线OJ实训五、有关static修饰变量的一些注意要点一、面试题引入💬面试题:实现一个类,计算程序中创建出了多少个类对象上面这个是曾经一家公司的面试题,要你用一个类去计算创建出多少个对象。分析一下可以知道我们去实例化出一个对象的时候,无非是调用构造或者是拷贝构造,或者是通过一些传参返回的方式去构造对象那第一时间就会想到在全局定义一个count,然后

  10. C++ | 说说类中的static成员 - 2

    【概念】:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化文章目录一、面试题引入二、static特性细述三、疑难解惑四、在线OJ实训五、有关static修饰变量的一些注意要点一、面试题引入💬面试题:实现一个类,计算程序中创建出了多少个类对象上面这个是曾经一家公司的面试题,要你用一个类去计算创建出多少个对象。分析一下可以知道我们去实例化出一个对象的时候,无非是调用构造或者是拷贝构造,或者是通过一些传参返回的方式去构造对象那第一时间就会想到在全局定义一个count,然后

随机推荐