请求/响应协议和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. Android 点击事件,4种回调。

    1.  继承监听接口. 2.  xml方式 : 设置 android:onClick 3. 内部类 4. 匿名类 ------------------------------------------- ...

  2. jQuery 遍历同胞(siblings)

    同胞拥有相同的父元素. 通过 jQuery,您能够在 DOM 树中遍历元素的同胞元素. 在 DOM 树中水平遍历 有许多有用的方法让我们在 DOM 树进行水平遍历: siblings() next() ...

  3. 通过css实现文本超出部分以省略号(......)代替

    一.单行溢出 1,固定宽度(非常容易) text-overflow: ellipsis; 2,不固定宽度 思路:想让这个区域成为块元素,然后不换行,溢出隐藏. display: block; whit ...

  4. 由C到C++的学习 ----Essential C++

    一.array[] 与 vector<int> vector1 1 array[] <- 此中要填写数组的大小,而且array[]自己是不知道自己的大小的 2.1 vector< ...

  5. boost::bind实践2——来自《Beyond the C++ Standard Library ( An Introduction to Boost )》

    直接代码: 代码段1: #include <iostream> #include <string> #include <boost/bind/bind.hpp> c ...

  6. android入门到熟练(三)----UI界面

    1.TextView 以下只是一部分属性,还有很多属性需要在用到时候再说 <TextView android:textSize="24sp"//文字大小 android:te ...

  7. div section article aside的理解

    div 是一个大的容器 内部可以包含header main nav aside footer等标签 没有语义,多用于为脚本添加样式 section的语义比div语义强些,用于主题性比较强的内容,比如一 ...

  8. WPF布局容器综合展示

    Border控件,以及几个重要要的属性:Background:背景的 Brush 对象BorderBrush:用来绘制边框BorderThickness: Border 边框的宽度,设置边框每一边的线 ...

  9. codevs 1557 热浪

    传送门 题目描述 Description 德克萨斯纯朴的民眾们这个夏天正在遭受巨大的热浪!!!他们的德克萨斯长角牛吃起来不错,可是他们并不是很擅长生產富含奶油的乳製品.Farmer John此时以先天 ...

  10. Android Learning:多线程与异步消息处理机制

    在最近学习Android项目源码的过程中,遇到了很多多线程以及异步消息处理的机制.由于之前对这块的知识只是浅尝辄止,并没有系统的理解.但是工程中反复出现让我意识到这个知识的重要性.所以我整理出这篇博客 ...