redis之管道
Redis 的消息交互
当我们使用客户端对 Redis 进行一次操作时,如下图所示,客户端将请求传送给服务
器,服务器处理完毕后,再将响应回复给客户端。这要花费一个网络数据包来回的时间。

如果连续执行多条指令,那就会花费多个网络数据包来回的时间。如下图所示。

回到客户端代码层面,客户端是经历了写-读-写-读四个操作才完整地执行了两条指令。

现在如果我们调整读写顺序,改成写—写-读-读,这两个指令同样可以正常完成。

两个连续的写操作和两个连续的读操作总共只会花费一次网络来回,就好比连续的 write
操作合并了,连续的 read 操作也合并了一样。

这便是管道操作的本质,服务器根本没有任何区别对待,还是收到一条消息,执行一条
消息,回复一条消息的正常的流程。客户端通过对管道中的指令列表改变读写顺序就可以大
幅节省 IO 时间。管道中指令越多,效果越好。
管道压力测试
接下来我们实践一下管道的力量。
Redis 自带了一个压力测试工具 redis-benchmark,使用这个工具就可以进行管道测试。
首先我们对一个普通的 set 指令进行压测,QPS 大约 5w/s。
> redis-benchmark -t set -q
SET: 51975.05 requests per second
我们加入管道选项-P 参数,它表示单个管道内并行的请求数量,看下面 P=2,QPS 达到
了 9w/s。
> redis-benchmark -t set -P 2 -q
SET: 91240.88 requests per second
再看看 P=3,QPS 达到了 10w/s。
SET: 102354.15 requests per second
但如果再继续提升 P 参数,发现 QPS 已经上不去了。这是为什么呢?
因为这里 CPU 处理能力已经达到了瓶颈,Redis 的单线程 CPU 已经飙到了 100%,所
以无法再继续提升了。
深入理解管道本质
接下来我们深入分析一个请求交互的流程,真实的情况是它很复杂,因为要经过网络协
议栈,这个就得深入内核了。

上图就是一个完整的请求交互流程图。我用文字来仔细描述一遍:
1、客户端进程调用 write 将消息写到操作系统内核为套接字分配的发送缓冲 send
buffer。
2、客户端操作系统内核将发送缓冲的内容发送到网卡,网卡硬件将数据通过「网际路
由」送到服务器的网卡。
3、服务器操作系统内核将网卡的数据放到内核为套接字分配的接收缓冲 recv buffer。
4、服务器进程调用 read 从接收缓冲中取出消息进行处理。
5、服务器进程调用 write 将响应消息写到内核为套接字分配的发送缓冲 send buffer。
6、服务器操作系统内核将发送缓冲的内容发送到网卡,网卡硬件将数据通过「网际路
由」送到客户端的网卡。
7、客户端操作系统内核将网卡的数据放到内核为套接字分配的接收缓冲 recv buffer。
8、客户端进程调用 read 从接收缓冲中取出消息返回给上层业务逻辑进行处理。
9、结束。
其中步骤 5~8 和 1~4 是一样的,只不过方向是反过来的,一个是请求,一个是响应。
我们开始以为 write 操作是要等到对方收到消息才会返回,但实际上不是这样的。write
操作只负责将数据写到本地操作系统内核的发送缓冲然后就返回了。剩下的事交给操作系统
内核异步将数据送到目标机器。但是如果发送缓冲满了,那么就需要等待缓冲空出空闲空间
来,这个就是写操作 IO 操作的真正耗时。
我们开始以为 read 操作是从目标机器拉取数据,但实际上不是这样的。read 操作只负
责将数据从本地操作系统内核的接收缓冲中取出来就了事了。但是如果缓冲是空的,那么就
需要等待数据到来,这个就是读操作 IO 操作的真正耗时。
所以对于 value = redis.get(key)这样一个简单的请求来说,write 操作几乎没有耗时,直接
写到发送缓冲就返回,而 read 就会比较耗时了,因为它要等待消息经过网络路由到目标机器
处理后的响应消息,再回送到当前的内核读缓冲才可以返回。这才是一个网络来回的真正开
销。
而对于管道来说,连续的 write 操作根本就没有耗时,之后第一个 read 操作会等待一个
网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作
直接就可以从缓冲拿到结果,瞬间就返回了。
redis之管道的更多相关文章
- 第三百零一节,python操作redis缓存-管道、发布订阅
python操作redis缓存-管道.发布订阅 一.管道 redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pi ...
- 【spring boot】spring boot 基于redis pipeline 管道,批量操作redis命令
spring boot 2.x 使用RedisTemplate 操作 =================================== 1.pom.xml <!--spring2.0集成r ...
- redis使用管道pipeline提升批量操作性能(php演示)
Redis是一个TCP服务器,支持请求/响应协议. 在Redis中,请求通过以下步骤完成: 客户端向服务器发送查询,并从套接字读取,通常以阻塞的方式,用于服务器响应. 服务器处理命令并将响应发送回客户 ...
- python学习之-- redis模块管道/订阅发布
redis 模块操作剩余其他常用操作 delete(*names):删除任意的数据类型exists(name):检测redis的name是否存在keys(pattern='*'):根据模型获取redi ...
- redis 使用管道提升写入的性能[pipeline]
看了手册的都知道multi这个命令的作用就好比是mysql的事务的功能,但是大家都知道事务吗,就是在操作的过程中,把整个操作当作一个原子来处理,避免由于中途出错而导致最后产生的数据不一致,而产生BUG ...
- 5. redis管道, 发布订阅, 模拟队列
一. 发布订阅 #订阅scribe 127.0.0.1:6379> SUBSCRIBE "channel_1" Reading messages... (press Ctrl ...
- Redis进阶实践之十八 使用管道模式加速Redis查询
一.引言 学习redis 也有一段时间了,该接触的也差不多了.后来有一天,以为同事问我,如何向redis中批量的增加数据,肯定是大批量的,为了这主题,我从新找起了解决方案.目前 ...
- redis学习(六)redis管道
redis管道 1.redis管道介绍 redis采用的是CS架构,客户端与服务器端通过tcp协议进行连接通信,因此无论是发出请求还是接收响应,都必须经过网络传输.在tcp连接过程中,客户端和服务器端 ...
- Redis管道传输
Redis是一个TCP服务器,并支持请求/响应协议.redis的一个请求完成需要下面的步骤: 客户端发送一个查询到服务器,并从套接字中读取,通常在封闭的方式,对服务器的响应. 服务器处理命令并将响应返 ...
随机推荐
- C++ 变量判定的螺旋法则
C++ 中一个标识符配合着各种修饰界定符,使得标识符的本意不那么直观一眼就能看出,甚至需要仔细分析,才能知道该标识符的具体你含义. 比如: void (*signal(int, void (*fp)( ...
- js控制滚动条在内容更新超出时自动滚到底部
//滚动条在内容更新时自动滚到底部var message = document.getElementById('message');message.scrollTop = message.scroll ...
- vscode中自动补全<?php?>
方法引用自百度知道的一个回答: 但是他这个我用着需要优化一下,我的代码是: "PHP":{ "prefix": "php", "b ...
- Linux6.x 更换国内比较快的yum源-通用版
----------更换国内比较快的yum源----------- ----------163--------- cd /etc/yum.repos.d mv CentOS-Base.repo Cen ...
- 读《深入理解Elasticsearch》点滴-对象类型、嵌套文档、父子关系
一.对象类型 1.mapping定义文件 "title":{ "type":"text" }, "edition":{ ...
- redis-分布式锁-刷新信号量
为什么需要刷新信号量呢,因为信号量有过期时间: 为什么信号量需要过期时间呢,因为需要利用超时特性,解决分布式锁存在的一些固有缺陷. 而对于类似流式API来说,一般10秒的过期时间是远远不够的.因此我们 ...
- 12-z-index
z-index 这个东西非常简单,它有四大特性,每个特性你记住了,页面布局就不会出现找不到盒子的情况. z-index 值表示谁压着谁,数值大的压盖住数值小的, 只有定位了的元素,才能有z-index ...
- 初次接触python时,整理的一些基础操作
1.window下python简单使用 (1).使用工具网址 https://jingyan.baidu.com/article/9f7e7ec0ec2e676f2915545f.html (2).各 ...
- 如何使用CSS实现居中
前言: 这一篇主要是翻译 <how-to-center-anything-with-css>这一篇文章的主要内容,再加上自己的一些概括理解:主要问题是解决垂直居中的问题.我们知道实现水平居 ...
- Angular2+之使用FormGroup、FormBuilder和Validators对象控制表单(取值、赋值、校验和是否可编辑等)
1.要使用Angular自带的表单控制需要先引入相关模块(.ts文件): import { FormGroup, //表单对象类 FormBuilder, //表单生成工具类 Validators} ...