《Redis官方文档》 Pipelining – 请求应答模式和往返延时

 Redis是一个CS结构的TCP服务器,使用”请求-应答”的模式。,客户端发起一个请求是这样的步骤:

  • 客户端发送一个请求给服务器,然后等待服务器的响应,一般客户端使用阻塞模式来等待服务器响应。
  • 服务器收到请求并处理完毕后,发送结果给客户端。

  举个例子,发送下面4个命令大概就是这样的顺序:

  • 客户端发送: INCR X
  • 服务器响应: 1
  • 客户端发送: INCR X
  • 服务器响应: 2
  • 客户端发送: INCR X
  • 服务器响应: 3
  • 客户端发送: INCR X
  • 服务器响应: 4

  客户端和服务器通过网络连接,网速可以非常快, 也可以非常慢。不管是快还是慢,消息包从客户端到服务器,再从服务器返回到客户端,总是要需要时间的。这个时间被称之为RTT(Round Trip Time,往返延时)。显然,当客户端需要发送多条请求时(比如往一个list中加很多元素,或者往一个数据库中填充很多keys),这个往返延时会影响到性能。假设网络非常慢,往返延时达到250毫秒,就算服务器每秒可以处理10万个请求,客户端也只能每秒处理4个请求。就算使用环回接口,往返延时非常小,如果需要执行很多写的操作, 也是要浪费许多时间的。

  幸好我们有办法改进这种情况。

Redis Pipelining

      “请求-响应”模式的服务器在处理完一个请求后就开始处理下一个请求,不管客户端是否读取到前一个请求的响应结果。这让客户端不需要发一个请求等一个响应的串行,可以一次发送多个请求,再最后一次性读取所有响应。这就叫piplining(管道化),这种技术几十年来广泛的使用。比如很多POP3协议支持这个特性,大大的加速了从服务器上下载新邮件的速度。

    Redis在很早的版本就支持pipeling,所以无论你用的是什么版本的redis,都可以用pipeling。下面是一个使用netcat的演示例子:

$ (printf "PING\r\nPING\r\nPING\r\n"; sleep 1) | nc localhost 6379
+PONG
+PONG
+PONG

  我们的第一个例子,如果使用pipeline,客户端的请求和服务器的响应顺序就是如下:

  • 客户端发送: INCR X
  • 客户端发送: INCR X
  • 客户端发送: INCR X
  • 客户端发送: INCR X
  • 服务器响应: 1
  • 服务器响应: 2
  • 服务器响应: 3
  • 服务器响应: 4

  注意:当客户端使用pipelining发送很多请求时,服务器将在内存中使用队列存储这些指令的响应。所以批量发送的指令数量,最好在一个合理的范围内,比如每次发1万条指令,读取完响应后再发送另外1万条指令。2万条指令,一次性发送和分2次发送,对客户端来说速度是差不多的,但是对服务器来说,内存占用差了1万条响应的大小。

性能测试

  下面是我们用Redis Ruby客户端测试使用pipelining带来的性能改进:

require 'rubygems'
require 'redis'

def bench(descr)
    start = Time.now
    yield
    puts "#{descr} #{Time.now-start} seconds"
end

def without_pipelining
    r = Redis.new
    10000.times {
        r.ping
    }
end

def with_pipelining
    r = Redis.new
    r.pipelined {
        10000.times {
            r.ping
        }
    }
end

bench("without pipelining") {
    without_pipelining
}
bench("with pipelining") {
    with_pipelining
}

    在我的Mac OS X系统中运行上面的脚本,由于使用环回接口往返延时非常小,这样pipeling带来的优化非常小。可以得到下面的结果:

without pipelining 1.185238 seconds
with pipelining 0.250783 seconds

  从结果可以看到,使用pipelining技术,我们的传输速度提高了5倍。

管道化 VS 脚本

    大部分使用pipelining的情况都可以用Redis脚本(2.6或高于2.6的版本才支持)来代替,使之更高效的在服务器端执行。使用脚本的最大好处是,在最小的延迟下可以读和写,比如可以:让“读,计算,写”这样一个流程非常快(pipeling不能处理这种情景,因为客户端需要得到响应之后才能计算和写)。有时候,应用程序可能需要在一个pipeline中发送多个EVAL或EVALSHA指令,redis的SCRITP LOAD指令能很好的满足这种需求(它保证了EVALSHA不会有调用失败的风险)。

时间: 2024-07-31 07:50:29

《Redis官方文档》 Pipelining – 请求应答模式和往返延时的相关文章

《Redis官方文档》翻译邀请

并发编程网定期组织翻译官方指南,十一月组织翻译Redis官方文档, 官方地址,有兴趣的同学可以通过评论领取,每次领取一节,翻译完后再领取其他章节.如果翻译超过10篇文章,并发网会赠送一本作者签名的<JAVA并发编程的艺术>. 如何交稿?直接在并发网注册账号后点新建文章,参考我要投稿. 介绍 admin.md     (ethfoo领取) benchmarks.md   (looyup已领取) clients.md  (mircle123领取) cluster-spec.md  (carlvin

《Redis官方文档 》sentinel

原文链接 Redis Sentinel 文档 Redis Sentinel为Redis提供了高可用解决方案.实际上这意味着使用Sentinel可以部署一套Redis,在没有人为干预的情况下去应付各种各样的失败事件. Redis Sentinel同时提供了一些其他的功能,例如:监控.通知.并为client提供配置. 下面是Sentinel的功能列表: 监控(Monitoring):Sentinel不断的去检查你的主从实例是否按照预期在工作. 通知(Notification):Sentinel可以通

《Redis官方文档》用Redis构建分布式锁

原文链接  译者:yy-leo   校对:方腾飞(红体标记重点) 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简单的实现其实只需采用稍微增加一点复杂的设计就可以获得更好的可靠性. 这篇文章的目的就是尝试提出一种官方权威的用Redis实现分布式锁管理器的算法,我们把这个算法称为RedLock,我们相信这个算法会比一般的普通方法更加安全可靠.我们也

《Redis官方文档》Redis集群教程

原文链接 译文链接 译者: tiffany 这篇教程是Redis集群的简要介绍,而非讲解分布式系统的复杂概念.它主要从一个使用者的角度介绍如何搭建.测试和使用Redis集群,至于Redis集群的详细设计将在"Redis集群规范"中进行描述. 本教程以redis使用者的角度,用简单易懂的方式介绍Redis集群的可用性和一致性. 注意: 本教程要求redis3.0或以上的版本. 如果你打算部署redis集群,你可以读一些关于集群的详细设计,当然,这不是必须的.由这篇教程入门,先大概使用一下

《Redis官方文档》主从复制

原文链接       译文连接  译者:adeline   校对:方腾飞(重点地方标成了粗体,方便大家阅读) Redis主从复制的配置十分简单,它可以使从服务器是主服务器的完全拷贝.下面是关于Redis主从复制的几点重要内容: Redis使用异步复制.但从Redis 2.8开始,从服务器会周期性的应答从复制流中处理的数据量. 一个主服务器可以有多个从服务器. 从服务器也可以接受其他从服务器的连接.除了多个从服务器连接到一个主服务器之外,多个从服务器也可以连接到一个从服务器上,形成一个图状结构 R

《Redis官方文档》持久化

原文链接 译者:Alexandar Mahone 这篇文章从技术层面描述了Redis持久化,建议所有读者阅读.如果希望更多了解Redis持久化和持久性保障,建议阅读Redis持久化揭秘. Redis 持久化 提供了多种不同级别的持久化方式: RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集. AOF 文件中的命令全部以 Redis 协议的格

《Redis官方文档》使用Redis作为LRU缓存

原文链接  译者:boyhou (WeChat:HouYongBo923) 如果你使用redis作为缓存,当添加新数据时,若有内存大小等限制,系统默认会根据一定的规则自动清理旧数据.这种处理方式在开发社区中众所周知,因为它也是非常流行的缓存系统 memcached 的默认处理方式. LRU(LRU全称是Least Recently Used,即最近最久未使用)实际上只是Redis支持的内存回收策略中的一种.这篇文章将要讲述Redis的 maxmemory 配置选项,该配置选项用来限制 Redis

《Redis官方文档》Redis调试指南

原文链接      译者:Adeline Redis开发过程中十分注重其稳定性:我们尽一切努力来保证每一个版本的稳定,不出现突然崩溃等情况.但是即使在我们百分百的努力下,仍然没办法保证百分百的无bug. Redis出现崩溃时,会生成一个详细的报告来描述当时的情景,但是有时候只看报告还不够,而且Redis的核心开发团队可能也没办法独立重现你出现崩溃时候的场景:在这种情况下,我们需要用户能够重现这个情景来帮助我们. 这个指南讲解了如何使用GDB来获得Redis开发者可能用到的信息. GDB是什么?

《Spark官方文档》集群模式概览

Spark 1.6.0  译者:dlbrant 集群模式概览 本文简要描述了Spark在集群中各个组件如何运行.想了解如何在集群中启动Spark应用,请参考application submission guide . 组件 Spark应用在集群上运行时,包括了多个独立的进程,这些进程之间通过你的主程序(也叫作驱动器,即:driver)中的SparkContext对象来进行协调. 特别要指出的是,SparkContext能与多种集群管理器通信(包括:Spark独立部署时自带的集群管理器,Mesos