Redis是一种采用客户端-服务器(C/S)模型的TCP服务器,这种模型也被称作请求/响应协议。

这就意味着,一个请求通常需要经过以下步骤才能完成:

客户端会向服务器发送一个查询请求,然后从套接字(socket)读取服务器的响应数据,通常以一种阻塞的方式。

服务器会处理请求的命令,然后将响应数据发送回客户端。

例如,一个包含四条命令的序列如下所示:

客户端请求:INCR X

服务器响应:1

客户端请求:INCR X

服务器响应:2

客户端请求:INCR X

服务器响应:3

客户端请求:INCR X

服务器响应:4

客户端和服务器通过网络建立连接。这种网络链接可能非常快速或非常缓慢(在互联网上建立的网络链接,可能会在两台主机之间存在很多跳数)。无论网络延迟有多小,客户端将数据包发送至服务器,然后服务器再将响应数据发送回客户端,这都需要花费一定时间的。

这段时间被称为往返时间(RTT:Round Trip Time)。当一个客户端需要连续执行很多请求时,就很容易看出往返时间是如何影响系统性能的(例如,将很多元素添加至同一个列表,或者向一个数据库写入很多键)。例如,如果往返时间是250毫秒(例如,在互联网上建立的慢速网络链接),即使Redis服务器每秒钟能处理100k个请求,我们也只能每秒钟最多处理四个请求。

如果使用的网络接口是一个回环接口,那么往返时间会非常短(例如,在我的电脑上对127.0.0.1地址执行ping命令,得到的往返时间是0.044毫秒),但是如果你需要连续执行很多次写入操作,往返时间对于系统性能的消耗仍然非常大。

幸运的是,现在有办法可以改善上述用例的性能。

一、Redis管道

可以实现一种请求/响应服务器,即使当客户端尚未读取稍早的响应数据,这个服务器都能够继续处理新的请求。通过这种方法,客户端就可以向服务器发送多个命令,而根本不用等待任何返回数据,最后会在一个单独的步骤中读取所有的返回数据。

这种方式被称为管道,这种技术已经广泛使用了几十年。例如,很多POP3协议的实现已经支持这项功能特性,显著增加了从服务器下载新邮件的处理速度。

Redis在很久以前就已经支持管道了。因此,无论你正在运行的Redis版本是什么,你都可以使用Redis的管道功能。使用原生的netcat工具的示例如下所示:

这次我们还会执行三个命令,但是不会在每个命令调用时都有往返时间的消耗,而只会消耗一次往返时间。

为了能够清晰地理解管道的概念,当使用管道时,本文首个示例的操作顺序将如下所示:

Client:INCR X

Client:INCR X

Client:INCR X

Client:INCR X

Server:1

Server:2

Server:3

Server:4

重要提示:虽然客户端会使用管道发送多个命令,但是服务器会被强制使用内存来缓存返回数据。因此,如果你需要使用管道发送很多条命令,最好是将它们作为具有合理编号的批次进行发送。例如,先发送一批10k条命令,然后读取返回数据,然后再发送另一批10k条命令,如此往复。不同批次命令的处理速度几乎是相同的,但是为了缓存每个批次的10k条命令的返回数据,管道功能会额外占用Redis服务器的内存。

二、基准测试

在下面的基准测试中,我们将会使用Redis的Java客户端(Jedis),这个客户端支持管道功能,可用来测试管道功能带来的性能改善。基准测试的源码如下所示:

importredis.clients.jedis.Jedis;

importredis.clients.jedis.Pipeline;

publicclassJedisPipeline{

publicstaticvoidmain(String[]args){

withoutPipelining();

withPipeLining();

}

privatestaticvoidwithoutPipelining(){

Jedisjedis=newJedis("192.168.21.135",6379);

longstart=System.currentTimeMillis();

for(inti=0;i<10000;i++){

jedis.ping();

}

longend=System.currentTimeMillis();

System.out.printf("without pipelining %f seconds ...\n",(end-start)/1000.0);

jedis.close();

}

privatestaticvoidwithPipeLining(){

Jedisjedis=newJedis("192.168.21.135",6379);

Pipelinepipeline=jedis.pipelined();

longstart=System.currentTimeMillis();

for(inti=0;i<10000;i++){

pipeline.ping();

}

pipeline.syncAndReturnAll();

longend=System.currentTimeMillis();

System.out.printf("with pipelining %f seconds ...\n",(end-start)/1000.0);

jedis.close();

}

}

上述的基准测试程序较为简单,它会连接到一个操作系统为CentOS 6.6的Redis服务器,这个服务器和运行基准测试程序的主机位于相同的局域网之内,因此单次的往返时间会非常小。运行结果如下图所示:

正如测试结果所示,使用管道,我们可以获得接近18倍的性能提升。

三、管道和脚本

通过Redis的脚本功能(Redis 2.6版本或更高版本可用),管道的很多用例都可以利用脚本获得更高的执行效率,这些脚本会执行服务器端需要的很多工作。脚本功能有一个很大的优势,它读写数据只会有最少的延迟,这样便会使得诸如读取、计算和写入等操作变得非常快速(在这个场景之中,管道不会有明显的效果,因为客户端在调用写入命令之前,需要先获得读取命令的返回数据)。

应用程序有时候可能需要通过管道发送EVAL或EVALSHA命令。这种情况是完全有可能的,Redis可以通过SCRIPT LOAD命令提供显式地支持(这条命令可以保证EVALSHA命令肯定会被调用,而且不会有执行失败的风险)。

客户和服务器之间响应的序列,Redis的请求/响应协议和往返时间详解相关推荐

  1. linux主从服务器不能同步,Linux下redis的持久化、主从同步与哨兵详解

    摘要: 1.0 redis持久化Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种持久化... 1.0 redis持久化 Redis是一种内 ...

  2. java redis expire 1_redis 下key的过期时间详解 :expire

    Redis是一个开源的Key-Value数据缓存,和Memcached类似. Redis多种类型的value,包括string(字符串).list(链表).set(集合).zset(sorted se ...

  3. Redis入门 - 数据类型:5种基础数据类型详解

    Redis所有的key(键)都是字符串.我们在谈基础数据结构时,讨论的是存储值的数据类型,主要包括常见的5种数据类型,分别是:String.List.Set.Zset.Hash Redis入门 - 数 ...

  4. 明日之后服务器什么时候维护结束,明日之后什么时候合区 合区时间详解[多图]...

    明日之后官方会将一些活跃人数不多的区进行合区,来增加大区的活跃,玩家们对这个合区的时间很关注,下面安族小编给大家介绍一下合区时间详解. 明日之后最新合服时间公告 老区会有2个区合成在一起,这个叫做数据 ...

  5. Redis(十)——HyperLogLog 基数统计和 Bitmap位图场景详解

    文章目录 Redis(十)--HyperLogLog 基数统计和 Bitmap位图场景详解 1.HyperLogLog 基数统计 2.Bitmap位图场景详解 Redis(十)--HyperLogLo ...

  6. 客户和服务器之间响应的序列,网络编程-第五讲-TCP客户-服务器程序例子.pdf-原创力文档...

    网络编程 第五讲TCP客户-服务器程序例子 多进程并发服务器基本架构 pid_t pid; int listenfd, connfd; listenfd = Socket( ... ); /* fil ...

  7. 叛乱联机服务器未响应,叛乱沙漠风暴怎么开服 叛乱沙漠风暴开服操作指南详解 安装准备-游侠网...

    叛乱沙漠风暴怎么开服?游戏一款多人联机操作游戏,在开服前期要做好相应的准备工作,也就是设置一些选项,这里给大家带来了"xudong162"分享的叛乱沙漠风暴开服操作指南详解,详情一 ...

  8. 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...

  9. Redis为什么变慢了?一文详解Redis性能问题 | 万字长文

    Redis 作为优秀的内存数据库,其拥有非常高的性能,单个实例的 OPS 能够达到 10W 左右.但也正因此如此,当我们在使用 Redis 时,如果发现操作延迟变大的情况,就会与我们的预期不符. 你也 ...

最新文章

  1. 地面标识检测与识别算法
  2. sql查询 关联帖子_从零学会sql,复杂查询
  3. 50个常用的sql语句
  4. 新兴IT企业特斯拉(八)——自动辅助驾驶
  5. 内蒙古农业大学微型计算机,内蒙古农业大学微机原理重点
  6. Javascript Eclipse 自动代码规范化
  7. 音视频常见播放器框架分析
  8. uni-app 商城源码
  9. javascript 设为首页 | 加入收藏夹 JS代码
  10. 【Jmeter+ant+Jenkins自动化持续集成】
  11. CVPR2022论文速递(2022.3.24)!共11篇含表情识别/deepfake检测/插帧等
  12. git回退版本 简单易懂
  13. 电脑从硬盘启动计算机,电脑怎么设置第一启动项为硬盘
  14. HTML文本框内容发生变化时引发事件执行
  15. 和菲利普•科特勒的《营销管理》一样,这些都是比较好的市场营销书籍
  16. 一个刚毕业程序员试用期工作内容
  17. Android 高德地图 自定义Location小蓝点
  18. Integer的equals方法
  19. 模型预测控制系列讲解(二):模型预测控制算法发展进程
  20. html语义化标签是什么,HTML语义化标签探析

热门文章

  1. UVA10929 You can say 11【大数模除】
  2. 《程序设计技术》课程辅助学习资料
  3. CCF NOI100002 取数游戏
  4. CCF NOI1024 因子个数
  5. I00013 鸡兔同笼
  6. MySQL 基础 —— 字符串处理
  7. 域名与DNS(域名解析服务器)
  8. 如何将 hadoop1.1.2/1.2.1 源码关联到 Eclipse
  9. “表达式必须包含 bool 类型(或可转换为 bool)”
  10. python编程入门书籍-程序员大佬,给Python零基础入门书籍教程的一些建议!