请求/响应协议和RTT

Redis是一个使用客户端/服务器模型(也被称作请求/响应协议)的TCP服务器。

这说明通常来讲一个一个请求的实现有以下步骤:

  • 客户端发送请求到服务器,并从socket中以堵塞的方式读取服务器的响应数据。
  • 服务器对发动的命令进行处理并把响应数据发回客户端。

比如发送连续四个命令就会像这样:

  • 客户端: INCR X
  • 服务端: 1
  • 客户端: INCR X
  • 服务端: 2
  • 客户端: INCR X
  • 服务端: 3
  • 客户端: INCR X
  • 服务端: 4

客户端和服务端通过网络连接。这个连接可能非常快(本地回环接口)也可能非常慢(互联网上相隔很多跳数的两台主机)。不论网络延迟是多少,数据包从客户端发到服务端并从服务端返回客户端都有一个时间。

这个时间被称作环路时间。显而易见,当客户端需要一次发送很多请求时(比如一次向一个List添加很多元素,或者向一个数据库添加很多Key),这个环路时间会对性能造成非常大的影响。如果环路时间是250毫秒(在网络连接非常慢的情况下),即使服务端能每秒处理10万个请求,我们一秒最大也只能处理四个请求。

即使我们用的是本地回环接口,本地环路时间会短得多(比如在我本机上用ping测试是0.044毫秒),但是如果你要一次进行大量写操作,这个时间依然不少。

幸运的是我们有一种方法来优化这种使用场景。

Redis管道

一个请求/响应服务器能够做到在客户端还没有读取上个返回值的时候就处理新的请求。通过这种方式客户端就可以在不获取每次请求的响应的情况下给服务端一次发送多个命令,并在未来的某个时间一次获得这些所有的响应。

这就叫做管道,这种技术早在多年前就被广泛应用。比如很多POP3协议的实现方案就支持管道,极大的提高了从服务器上下载新邮件的速度

Redis在很早的时候就支持管道,所以无论你现在用的是什么版本,你都可以在Redis中使用管道。以下是一个使用原生netcat工具的例子:

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

这次我们不在每次调用都产生RTT的花销,所有命令加起来只产生一次RTT花销。

To be very explicit, with pipelining the order of operations of our very first example will be the following:

为了显示清楚,第一个例子中我们进行操作如果使用管道就会以下面的顺序执行:

  • 客户端: INCR X
  • 客户端: INCR X
  • 客户端: INCR X
  • 客户端: INCR X
  • 服务端: 1
  • 服务端: 2
  • 服务端: 3
  • 服务端: 4

务必要注意:当客户端使用管道发送多条命令时,服务端会把所有的响应都放入队列,这会带来额外的内存开销。所以如果你想使用管道来一次发送多条命令,最好给定一合理的个命令数上限值,比如10000条命令,之后读取响应,之后再次发送另外的10000条命令并循环往复。这样请求速度不会有大的改变,但是额外内存的使用量只会相当于缓存这10000条回复所需要的上限值。

一些性能指标

以下的性能检测中我们会用到Redis的Ruby客户端,使用管道,来测试管道对于速度的提升:

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 系统上的性能指标,由于延迟只来源于本地回环接口,RTT时间非常短,管道机制只提供了最小的性能提升:

without pipelining 1.185238 seconds
with pipelining 0.250783 seconds

可以看出使用管道后有了五倍的性能提升。

管道VS脚本

由于脚本执行于服务端,所以使用Redis脚本(可用于Redis2.6或以上版本)可以使某些原本使用管道的场景执行得更有效率。脚本一个很大的优势在于它的读写操作的延迟相当小,因此能使如read, compute, write之类的操作执行的非常快(管道在这个场景下表现就差强人意,因为管道在执行写之前需要先得到读请求的响应和返回值)。

有些时候应用希望可以通过管道发送EVLA或者EVALSHA命令。这也是完全可以做的到的并且Redis通过SCRIPT LOAD命令显式支持这种操作(并保证EVALSHA操作不会执行失败)。

Redis教程02——管道(Pipelining)的更多相关文章

  1. .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)

    序言 Redis中的管道(PipeLine)特性:简述一下就是,Redis如何从客户端一次发送多个命令,服务端到客户端如何一次性响应多个命令. Redis使用的是客户端-服务器模型和请求/响应协议的T ...

  2. Redis中的管道(PipeLine)与事物(Transactions)

    Redis中的管道(PipeLine)与事物(Transactions) 序言 Redis中的管道(PipeLine)特性:简述一下就是,Redis如何从客户端一次发送多个命令,服务端到客户端如何一次 ...

  3. [译]Vulkan教程(02)概况

    [译]Vulkan教程(02)概况 这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第2篇. This chapter will start off with ...

  4. 【redis】pipeline - 管道模型

    redis-pipeline 2020-02-10: 因为我把github相关的wiki删了,所以导致破图...待解决.(讲真github-wiki跟project是2个url,真的不好用) 因为用的 ...

  5. Redis教程——检视阅读

    Redis教程--检视阅读 参考 Redis教程--菜鸟--蓝本--3.2.100 Redis教程--w3c--3.2.100 Redis教程--w3c--Redis开发运维实践指南 Redis教程- ...

  6. redis教程

    windows下安装redis: http://jingyan.baidu.com/article/49ad8bce40174f5834d8fa24.html redis教程: http://www. ...

  7. 【Zigbee技术入门教程-02】一图读懂ZStack协议栈的基本架构和工作机理

    [Zigbee技术入门教程-02]一图读懂ZStack协议栈的基本架构和工作机理 广东职业技术学院  欧浩源  ohy3686@foxmail.com Z-Stack协议栈是一个基于任务轮询方式的操作 ...

  8. phpredis 中文手册和redis 教程

    phpredis 中文手册  :   http://www.cnblogs.com/zcy_soft/archive/2012/09/21/2697006.html 手册: http://www.cn ...

  9. 【Zigbee技术入门教程-02】一图读懂ZStack协议栈的核心思想与工作机理

    [Zigbee技术入门教程-02]一图读懂ZStack协议栈的核心思想与工作机理 广东职业技术学院  欧浩源   Z-Stack协议栈是一个基于任务轮询方式的操作系统,其任务调度和资源分配由操作系统抽 ...

随机推荐

  1. CI 笔记7,easyui 异步加载

    在做后台导航时,需要异步加载,pid和id的循环问题,在controller中,建立另外一个方法,嵌套循环,查找是否pid〉1. public function nav_list() { $this- ...

  2. 百度前端技术学院(IFE)2016春季学期总结

    今天(5月16日)作为第八个提交者提交了任务五十:RIA微型问卷管理平台 这样一个综合性的大任务,宣告我的IFE春季学期课程学习顺利完成.其实任务五十并不复杂,现在再让我来做,可能一周不到就写出来了, ...

  3. JS常用的7中跨域方式总结

    javascript跨域有两种情况:  1.基于同一父域的子域之间,如:a.c.com和b.c.com  2.基于不同的父域之间,如:www.a.com和www.b.com  3.端口的不同,如:ww ...

  4. 将requirejs进行到底(一)

    随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求 ...

  5. linux vim 基本操作

    (一定要在英文输入法的状态下才有效)vi:实际上linux 上的 vi 不是真正的 vi,而是 vim;纯的 vi只在某些 unix 系统上还存在纯 的vi里面不支持退格键盘了,当按退格键盘以后,不是 ...

  6. winform程序开机自动启动代码

    几天前头儿要我实现程序能开机自动启动,搞好了,整理起来写下来. private void checkBox1_CheckedChanged(object sender, EventArgs e) { ...

  7. InfoPath本地发布及部署

    前言 最近在接触SharePoint项目,第一次接触,总感觉有些不适应.以前只是听过,现在要遇见了,有些小紧张.今天改了一下表单的东西,也是对sharepoint的慢慢熟悉过程,分享给初学,或者未学者 ...

  8. js 默认的参数、可变的参数、变量作用域

    可以通过arguments对象来实现可变的参数 在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们. arguments是一个数组对象,可以通过下标来实别参数的位置 ...

  9. SSD: Single Shot MultiBox Detector

    By Wei Liu, Dragomir Anguelov, Dumitru Erhan, Christian Szegedy, Scott Reed, Cheng-Yang Fu, Alexande ...

  10. 入门6:PHP 语法基础——循环

    一.for循环 for($i=0;$i<10;$i++){ echo "Hello".$i."</br>"; } 二.while循环 $i = ...