Redis管道(Pipeline)详解

在讲解管道前,我们首先来了解一下redis的交互,redis的一次交互是由客户端发起,由服务端接收,那么我们连续操作一些指令,如下图所示:

客户端请求一个指令到服务器到服务器返回数据这个过程非常复杂,既要保证数据能够快速传到也要保证不丢包,那么每次请求响应这个过程中数据传输和客户端接收数据的网络消耗非常大,那么我们怎么来提升这个性能呢?

上面说了,我们来回几次消耗大,那么可以一次性请求,一次性接收吗?当然是可以的,redis可以利用管道来提高性能。

Redis客户端与服务器之间使用TCP协议进行通信,并且很早就支持管道(pipelining)技术了。Redis 管道 (Pipeline) 本身并不是 Redis 服务器直接提供的技术,这个技术本质上是由客户端提供的,跟服务器没有什么直接的关系。

这里值得注意的是,管道空间也有上限,合理利用才是最好的选择。

管道压力测试 

接下来我们测试一下管道的性能,Redis自带了一个压力测试工具redis-benchmark,使用这个工具就可以进行管道测试。 

首先我们对一个普通的set指令进行压测,QPS大约5w/s。 

> redis-benchmark -t set -q SET: 53975.05 requests per second 

我们加入管道选项-P参数,它表示单个管道内并行的请求数量,看下面 P=2,QPS达到了9w/s。 

> redis-benchmark -t set -P 2 -q SET: 94240.88 requests per second 

再看看 P=3,QPS达到了 10w/s。 

> redis-benchmark -t set -P 2 -q 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、结束。 

我们开始以为write操作是要等到对方收到消息才会返回,但实际上不是这样的。write操作只负责将数据写到本地操作系统内核的发送缓冲然后就返回了。剩下的事交给操作系统内核异步将数据送到目标机器。但是如果发送缓冲满了,那么就需要等待缓冲空出空闲空间来,这个就是写操作IO操作的真正耗时。我们开始以为read操作是从目标机器拉取数据,但实际上不是这样的。read操作只负责将数据从本地操作系统内核的接收缓冲中取出来就了事了。

所以对于value=redis.get(key)这样一个简单的请求来说,write操作几乎没有耗时,直接写到发送缓冲就返回,而read就会比较耗时了,因为它要等待消息经过网络路由到目标机器处理后的响应消息,再回送到当前的内核读缓冲才可以返回。这才是一个网络来回的真正开销。 而对于管道来说,连续的write操作根本就没有耗时,之后第一个read操作会等待一个网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作直接就可以从缓冲拿到结果,瞬间就返回了。 

这就是管道的本质了,它并不是服务器的什么特性,而是客户端通过改变了读写的顺序带来的性能的巨大提升。 

 

 

一名正在抢救的coder

笔名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章