如何用好redis pipeline
编者注:pipeline是Redis的一个提高吞吐量的机制,适用于多key读写场景,比如同时读取多个key的value,或者更新多个key的value。工作过程中发现挺多小伙伴都对pipeline多少有些了解,但是更深入的理解或者说有哪些坑就不知道了,下面咱们就一起分析下redis pipeline机制,揭开它的神秘面纱。
Redis本身是基于Request/Response协议(停等机制)的,正常情况下,客户端发送一个命令,等待Redis返回结果,Redis接收到命令,处理后响应。在这种情况下,如果同时需要执行大量的命令,那就是等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求。为了提升效率,这时候pipeline出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果,这和网络的Nagel算法有点像(TCP_NODELAY选项)。pipeline不仅减少了RTT,同时也减少了IO调用次数(IO调用涉及到用户态到内核态之间的切换)。
要支持Pipeline,其实既要服务端的支持,也要客户端支持。对于服务端来说,所需要的是能够处理一个客户端通过同一个TCP连接发来的多个命令,可以理解为,这里将多个命令切分,和处理单个命令一样(之前老生常谈的黏包现象),Redis就是这样处理的。而客户端,则是要将多个命令缓存起来,缓冲区满了或者达到发送条件就发送出去,最后才处理Redis的应答。
注意:Redis的Pipeline和Transaction(Redis事务)不同,Transaction会存储客户端的命令,最后一次性执行,而Pipeline则是处理一条(批次),响应一条,从二者的不同处理机制来看,Redis事务中命令的执行是原子的(注意,其中一部分命令出现错误后续命令会继续执行,这里的原子说的是命令执行是完整的,中间不会被其他Redis命令所打断),而pipeline中命令的执行不一定是原子的。但是这里却有一点不同,就是pipeline机制中,客户端并不会调用read去读取socket里面的缓冲数据(除非已经发完pipeline中所有命令),这也就造成了,如果Redis应答的数据填满了该接收缓冲(SO_RECVBUF),那么客户端会通过ACK,WIN=0(接收窗口)来控制服务端不能再发送数据,那样子,数据就会缓冲在Redis的客户端应答缓冲区里面。所以需要注意控制Pipeline的大小。如下图:
这里可以设想一下,如果客户端通过ACK,WIN=0(接收窗口)来控制服务端不能再发送数据,那么数据就会堆积在服务端socket发送缓冲区中,如果服务端socket发送缓冲区也满了,那么此时服务端调用write(socket)就会阻塞或者失败。
既然提到了tcp/ip的滑动窗口概念,这里就简单总结下滑动窗口:
滑动窗口在TCP中的作用是提供TCP的可靠性和流控特性,滑动窗口可分为发送窗口和接收窗口,它们分别对应于发送缓冲区和接收缓冲区。发送窗口的大小是根据客户端接收缓冲区的大小而设定的(三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息)。
发送窗口中包含的内容是已发送但还未收到Ack的数据和未发送但对端允许发送的数据。
TCP接收缓冲区中包含应用为读取数据、已接收数据(已回复ACK)、待接收,其中待接收空间可称为接收窗口。
使用pipeline过程中,要注意控制一次pipeline中的命令总大小,不能使响应结果撑爆socket接收缓冲区。这里我们思考一个问题,还有没有其他方式提高pipeline的处理性能呢?理论上是有的,比如可以使用数据压缩机制,进一步减小数据传输的总大小,不过这需要客户端和服务端提供解压缩机制,同时会耗费一定量服务器CPU。
欢迎小伙伴关注【TopCoder】阅读更多精彩好文。
如何用好redis pipeline的更多相关文章
- redis pipeline
redis pipeline 简而言之就是把多个redis命令打包,一起发送给redis server,并且一起返回结果,减少客户端和服务器之间的多次“折返跑”
- 【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 ...
- 说说 Redis pipeline
更多技术文章,请关注我的个人博客 www.immaxfang.com 和小公众号 Max的学习札记. Redis 客户端和服务端之间是采用 TCP 协议进行通信的,是基于 Request/Respon ...
- (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协议的,正常情况 ...
随机推荐
- Linux 删除命令rm
Linux rm命令用于删除一个文件或者目录. 语法:rm [options] name... 参数: 1.-i 删除前逐一询问确认. 2.-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认. 3 ...
- CentOS 安装lsof命令
1.在控制台上输入:# yum install lsof,安装过程中按y进行确认 2.使用lsof -i :port 可以产看端口的进程信息
- 深度解密Go语言之反射
目录 什么是反射 为什么要用反射 反射是如何实现的 types 和 interface 反射的基本函数 反射的三大定律 反射相关函数的使用 代码样例 未导出成员 反射的实际应用 json 序列化 De ...
- 【福利】离散&C++&硬件一笔记合集
离散 C++ 硬件
- 学习VBA
学习VBA VBA 就是 (Visual basic for Application) 用的比较多的是在Excel中处理数据,可以方便快捷地使用编程方式来对数据进行操作. VBA 数据类型 Integ ...
- spring源码分析系列2:Bean与BeanDefinition关系
接口表示一种能力,实现了一个接口,即拥有一种能力. BeanDefinition与Bean的关系, 就好比类与对象的关系. 类在spring的数据结构就是BeanDefinition.根据BeanDe ...
- Spring Boot(四) Mybatis-MySql
Spring Boot(四) Mybatis-MySql 0.准备数据库表 -- ---------------------------- -- Table structure for person ...
- JDK 1.8 之 Map.merge()
Map 中ConcurrentHashMap是线程安全的,但不是所有操作都是,例如get()之后再put()就不是了,这时使用merge()确保没有更新会丢失. 因为Map.merge()意味着我们可 ...
- C# 8 的模式匹配
C# 7 里面的Pattern Mathing is 模式 switch 和 when C# 8 里面的Pattern Matching 使用Deconstructor 和 位置匹配模式 下面两个类T ...
- link 和 @import 的区别是什么?
link语法结构: <link href="url" rel="stylesheet" type="text/css"> @im ...