Redis之管道解读

news/2024/12/28 12:31:01/

目录

基本介绍

使用例子

管道对比

管道与原生批量命令对比 

管道与事务对比 

使用pipeline注意事项 

基准测试


基本介绍

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务器。

这意味着请求通常按如下步骤处理:

  • 客户端发送一个请求到服务器,并以阻塞的方式从socket读取数据,获取服务端响应 。
  • 服务端处理请求命令并发送响应回给客户端。

以上两步称为:Round Trip Time(简称
 RTT,数据包往返于两端的时间)。

 管道主要解决的就是redis频繁命令往返造成的性能瓶颈 

Clients 和 Servers 通过网络连接. 可以是本地非常快的网络,或者是通过互联网连接很远的网络。不管网络延迟如何,数据包从客户端发给服务端,再从服务端返回给客户端都要花费一个时间。

这个时间叫做 RTT (Round Trip Time往返时间). 所以如果客户端需要连续发送多个请求的情况下,RTT对性能的影响是很严重的。例如在延迟很大的网络中RRT是250ms,即使服务端每秒能处理10万个请求,我们也只能每秒最多处理四个请求。

解决思路

管道(pipeline)可以一次性发送多条命令给服务端,服务端一次处理完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列,先进先出特性是保证数据的顺序性 

一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。

使用例子

 将指令写在cmd.txt文件中,然后发生给redis客户端。

Redis 很早就开始支持 pipelining , 所以不管什么版本的Redis都能使用 pipelining 命令。下面是使用netcat命令的例子:

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

特别注意: 当客户端使用管道 pipelining发送命令时,服务器端需要消耗内存来存放响应,所以如果你需要发送大量的命令,最好分批发送,例如一次发送1万个,读取回报,再循环发剩余的命令。速度上几乎无差异,但是内存最大消耗1万个命令回复结果的内存。 

管道对比

管道与原生批量命令对比 

  • 原生批量命令是原子性的,例如:mget、mset。pipeline是非原子性的
  • 原生批量命令一次只能执行一种命令,但是pipeline支持一次执行多中命令。
  • 原生批量命令是服务端实现的,而pipeline需要服务端与客户端共同完成。

管道与事务对比 

  • 事务里面的命令是在服务端缓存,当发出exec命令的时候,服务端就会判断并执行事务命令。
  • 管道里面的命令是在客户端缓存,当客户端结束管道后一次发送到服务端,服务端读取后按照先后顺序先后执行。所以事务的命令是一条一条发的,而管道的是一次性发送到服务端的。执行事务时会阻塞其他命令的执行,而执行管道中的命令时不会。
  • 事务中出现语法错误会导致事务不被执行,而管道出现语法错误,依然会执行其他命令。

使用pipeline注意事项 

pipeline缓冲的命令只是会依次执行,不保证原子性,如果执行过程中发生异常,将会继续执行后续的命令。

使用pipeline组装的命令个数不能太多,不然数据量过大,客户端阻塞的时间可能过久,同时服务端此时也被迫恢复一个队列答复,占用很多内存。

基准测试

下面使用的是Redis Ruby客户端,来测试 pipelining 对速度的提升:

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
}

在mac上执行上面的脚本得到如下输出,因为是本机访问,提升并不明显,本机环境下RTT已经很小:

不用pipelining 1.185238 seconds
使用 pipelining 0.250783 seconds

使用pipelining,我们能大概提高5倍速度。


http://www.ppmy.cn/news/1075208.html

相关文章

CTFhub--文件上传--%00截断

首先查看网页源代码 允许上传文件格式 白名单 jpg png gif 用哥斯拉生成一木马文件,名字为 1.jpg 上传 用burp 抓包 在 “upload/” 后门添加 1.php%00 提交 用蚁剑连接 ctfhub{4fea5ea72c40690444354890}

获得硬盘ID(序列号、机器码)的C++代码源码

本篇文章属于《518抽奖软件开发日志》系列文章的一部分。 我在开发《518抽奖软件》(www.518cj.net)的时候,在软件的注册部分,需要获得硬盘的序列号(ID/机器码)。在网上找了一些代码,很多不好用,最后选了下面…

Kotlin,解决调用了函数但是函数体内没有执行的问题,什么时候使用invoke

fun main() {listOf(1,2,3).forEach{ foo(it)} } fun foo(a:Int) {print(a) }这段代码按照代码逻辑来说打印的是 123 但是没有这个打印 把foo函数转成java的代码如下 JvmStaticNotNullpublic static final Function0 foo(final int var0) {return (Function0)(new Function0 ()…

Java如何随机获取List中的元素?实现代码一次搞定!

推荐阅读 AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI绘画、AI讲话、翻译,GPU点亮AI想象空间 资源分享 AI绘画 stable diffusion Midjourney 官方GPT文档 AIGC百科全书资料收集 史上最全文档AI绘画stablediffus…

高频面试题:如何分别用三种姿势实现三个线程交替打印0到100

最近面试遇到的一道题,需要三个线程交替打印0-100,当时对多线程并不是很熟悉因此没怎么写出来,网上搜了之后得到现 synchronized wait/notifyAll 实现思路:判断当前打印数字和线程数的取余,不等于当前线程则处于等待…

ue5 c++ interface 接口

https://docs.unrealengine.com/5.2/en-US/interfaces-in-unreal-engine/ 1 纯c 接口 没有ufunction #pragma once#include "CoreMinimal.h" #include "UObject/Interface.h" #include "ALWorldWeatherConfig.h" #include "AL_WeatherInt…

面试系列-Springboot 自定义starter使用详解

Spring Boot是一个用于快速构建基于Spring框架的应用程序的工具。它通过提供预配置的默认设置和开箱即用的特性,简化了Spring应用程序的开发流程。其中,Spring Boot Starter是一种通过提供一组预配置的依赖项来简化特定功能开发的机制。 Spring Boot Starter提供了一种方便的…

设计模式的使用——模板方法模式+动态代理模式

一、需求介绍 现有自己写的的一套审批流程逻辑,由于代码重构,需要把以前的很多业务加上审批的功能,再执行完审批与原有业务之后,生成一个任务,然后再统一处理一个任务(本来是通过数据库作业去处理的&#x…