Redis是基于TCP协议的服务器/客户端模式,使用了请求/响应协议模式。
这意味完成一个请求,需要以下步骤:
l 客户端发送查询指令到服务端,并且通过阻塞模式读取soket中服务端影响的数据。
l 服务端处理指令,并且将响应信息返回给客户端。
例如四个指令的队列如下:
l Client: INCR X
l Server: 1
l Client: INCR X
l Server: 2
l Client: INCR X
l Server: 3
l Client: INCR X
l Server: 4
客户端和服务端通过网络连接,可能这个链接网络很好或者很差。但是无论延迟如何,服务端和客户端交互,还是需要不少开销的。
例如假设RTT为250ms,redis服务端处理速度可以达到1w个指令每秒,那么顺序发送、处理并返回结果上面4个指令,一共需要1s,那么redis的处理速度只有4个指令每秒。
而使用管道,执行如下:
l Client: INCR X
l Client: INCR X
l Client: INCR X
l Client: INCR X
l Server: 1
l Server: 2
l Server: 3
l Server: 4
则是一次性发送4个指令,然后一次性接收4个指令处理结果,那么只需要走一次网络,开销是250ms,那么redis的处理速度是16个指令每秒。效率提升了4倍。
重要提示:
使用管道时,尽量控制每次发送的指令的数量和频率。例如通过管道发送10k个指令,那么服务端需要缓存这10k个指令的执行结果,然后返回。若是频率太快、每次指令较多,则服务器可能是会缓存执更多执行结果到响应队列,导致占用大量内存。所以建议发送一定量的指令,然后等待读取完服务器的响应后,再进行下一个批次指令的发送。
一些基准测试如下:
以下基准是基于Ruby的redis客户端做,支持管道。
require 'rubygems'require 'redis'def bench(descr)start = Time.nowyieldputs "#{descr}#{Time.now-start} seconds"enddef without_pipeliningr = Redis.new10000.times {r.ping}enddef with_pipeliningr = Redis.newr.pipelined {10000.times {r.ping}}endbench("without pipelining") {without_pipelining}bench("with pipelining") {with_pipelining}测试结果如下:without pipelining 1.185238 secondswithpipelining 0.250783 seconds