宝哥软件园

NET客户端在Redis中实现管道和事务

编辑:宝哥软件园 来源:互联网 时间:2021-09-05

前言

Redis中的PipeLine特性:简要描述Redis如何一次从客户端发送多个命令,以及服务器如何一次响应来自客户端的多个命令。

Redis使用基于客户机-服务器模型和请求/响应协议的TCP服务器,这意味着一个请求可以通过以下步骤完成:1。客户端向服务器发送查询命令,然后通常会以阻塞的方式等待服务器响应。2.服务器处理查询命令并将其发送回客户端。这样,它将通过网络连接。如果是本地环回接口,可以很快响应。但是如果去外网,甚至在外网上做一系列的逐层转发,就会特别痛苦。无论网络延迟是多少,都会占用整体响应时间。这样,如果一次发送一个命令,网络延迟是100毫秒,所以我们必须这样做。那么,如果一次发送1000条命令,100*1000ms的网络延迟是非常难以容忍的。

为了解决上述问题,Redis从2.6版本开始就提供了Pipeline功能。他可以让客户端处理新的请求,而不读取旧的响应。这样,可以向服务器发送多个命令,而无需等待回复,直到在最后一步中读取回复。这被称为PipeLine,它已经被广泛使用了几十年。例如,许多POP3协议实现已经支持该功能,这大大加快了从服务器下载新电子邮件的过程。

那么交易这个词就经常遇到,所以没有太多的唧唧喳喳。有同一个目标就好,那就是如何让一组操作变成原子操作,让他不能走到最后又回到原点。

线鲨抓取工具简介

为了让大家对管道有一个更直观的感受,在这一节中,我们来说说Wireshark包抓取工具,它会让你看到redis命令通过tcp协议从客户端发送到服务器端的过程和细节。

Wireshark可以捕获系统发送和接收的每一条消息,所以我们在这里只对过滤做一些简单的描述。下图是他的样子。打开后可以探究他的用法。

简要描述几个过滤规则:

1.ip过滤:目标ip过滤:ip.dst==172.18.8.11,源ip地址过滤:IP . src==192 . 168 . 1 . 12;

2.端口过滤:tcp.port==80。此规则使用80过滤掉源端口和目标端口。使用tcp.dstport==80只过滤目的端口为80的数据包,使用tcp.srcport==80只过滤源端口为80的数据包;

3.协议过滤:直接在fiter框中输入协议名称,如http、tcp、udp、

4.http模式过滤器:过滤器get包,http.request.method=='GET ',过滤器post包,http . request . method==' post ';

5.如果使用多条件筛选,则需要添加连接符号,以及。例如IP.src==192.168.1.12和http.request.method==' post '和TCP.srcport==80

StackExchange。Redis实现Redis管道

最后两张图的流水线一目了然。

如果客户端向redis服务器发出多个请求,一般模式如下

如果客户端向redis服务器发出多个请求,管道模式如下所示

通用模式我们编码:

public static void getnopipeline(){ for(var I=0;I 3;I){ var key=' name : ' I;Db。StringAppend(键,‘张龙浩’);} }

检查tcp请求消息的数据

在自己动手的过程中,可以看到我圈出的三个tcp请求的键分别是:name: 0,name:1,name:2。

然后我们使用管道模式

public static void GetStreaming(){ var batch=db。create batch();for(int I=0;I 3;I){ var key=' mename : ' I;批次。StringAppendAsync(键,‘张龙浩’);}批次。execute();}再次查看请求

这样,很明显,一个请求已经发出,多个命令已经发出。那么我们就可以在没有createBatch()的情况下达到这个效果。

var a=db .StringAppendAsync('zlh:1 ','张龙豪1 ');var b=db .StringAppendAsync('zlh:2 ','张龙豪2 ');var c=db .StringAppendAsync('zlh:3 ','张龙豪3 ');var aa=db .等待(a);var bb=db .等待(a);var cc=db .等待(a);在接下来我们做一个简单的性能比较。代码如下:

静态void Main(字符串[]个参数){ 0秒表手表=新秒表();秒表手表1=新的秒表();看着start();GetNoPipelining控制台WriteLine(“”一般循环耗时:'看着elapsedmirisseconds秒);看着stop();观察1。start();getstreaming();控制台。写线('流水线插入耗时:' watch1 .elapsedmirisseconds秒);观察1。stop();控制台ReadLine();} public static void getnopipeline(){ for(var I=0;I 5000 I){ var key=' name : ' I;db .StringAppend(键,)张龙豪');} } public static void GetStreaming(){ var batch=db .创建批处理();for(int I=0;I 5000 I){ var key=' mename : ' I;批次. StringAppendAsync(键,)张龙豪');}批次execute();}结果如下:

到此我还要说一下StackExchange .Redis的三种命令模式,其中使用2和3的模式发送命令,会默认被封装在管道中,不信的话,你可以做个小演示测试下:

1、同步:同步模式,会直接阻塞调用者,但不会阻塞其他线程。

2、异步:异步模式,使用工作模型封装。

3、欲罢不能:发送命令,然后完全不关心最终什么时候完成命令操作。在先开火后忘记模式下,所有命令都会立即得到返回值,该值都是该返回值类型的默认值,比如操作返回类型是弯曲件将会立即得到假的,因为false=默认值(嘘声)。

此节参考redis官方文档与StackExchange .Redis官方文档,连接如下:

https://redis.io/topics/pipelining

https://github.com/StackExchange/StackExchange . redis/blob/master/Docs/pipeline多路复用器。医学博士

StackExchange .Redis实现Redis事务(交易)

这个看官方文档,我只能说实现的很奇怪吧。我先描述下我的环境,就是准备一个空redis库,然后一步一步往下走,我们写代码看结果,来搞一搞这个事务。

静态void Main(字符串[]个参数){ var tran=db .create TransAction();特兰。添加条件(条件listindenoteqal(' zlh :1 ',0,' Hao ');特兰listerrightpushasync(' zlh :1 ',昊');布尔承诺=交易execute();控制台WriteLine(已提交);控制台ReadLine();}执行结果为:真的。数据库中结果如下,说明我们插入成功。

即:如果键为:zlh:1的目录集合在索引0初的价值!张龙浩的话,我们从链表右侧插入一条数据键为zlh:1值为张龙浩,成功。因为第一次操作为空库。0处确实不为张龙豪。

数据不清空,继续上代码。

静态void Main(字符串[]个参数){ var tran=db .create TransAction();特兰。添加条件(条件listindenoteqal(' zlh :1 ',0,' Hao ');特兰listerrightpushasync(' zlh :1 ',豪1 ');布尔承诺=交易execute();控制台WriteLine(已提交);控制台ReadLine();}结果为假的,数据库没有增减数据。已久与上图的数据保持一致。

原因分析:0处此时为张龙浩,所以listindenoteqal(' zlh :1 ',0 '张龙浩)为假命题,直接回滚,不执行下面的插入命令。

数据不清空,继续上代码:

静态void Main(字符串[]个参数){ var tran=db .create TransAction();特兰。添加条件(条件listindeequal(' zlh :1 ',0 '张龙浩');特兰listerrightpushasync(' zlh :1 ',豪1 ');布尔承诺=交易execute();控制台WriteLine(已提交);控制台ReadLine();}结果为没错,数据结果如下,增长一条值为张龙浩一的数据:

原因分析:listindeequal(' zlh :1 ',0 '张龙浩)为真命题,执行下面的操作,提交事物。

继续编码而不删除数据:

静态void Main(字符串[] args) { var tran=db。create TransAction();特兰。添加条件(条件。listindeequal(' zlh :1 ',0,'张龙浩');特兰。listerrightpushasync(' zlh :1 ',' Zhang long Hao 2 ');特兰。添加条件(条件。listindenoteqal(' zlh :1 ',0,' Zhang long Hao ');特兰。listerrightpushasync(' zlh :1 ',' Zhang long Hao 3 ');布尔承诺=交易。execute();控制台。WriteLine(已提交);控制台。ReadLine();}结果为假,数据库数据与上述数据长期一致,没有增减。

分析原因:条件。listindequal ('zlh:1 ',0,'张龙浩')为真,但下面的listindenoteqal(' zlh :1 ',0,'张龙浩')为假。因此,整个事情的操作都是回滚而不执行的,所以数据库中没有变化。

在这一点上,我不会写多余的代码,但我想说几点注意事项:

1.执行命令的操作应该是异步的。

2.在一个事物中执行的任何命令都不会直接看到结果,所以这个结果不能用来判断下面的代码,因为当前的异步命令在execute()之前不会对数据库产生任何影响。

3.参考文件:https://github.com/stack exchange/stack exchange . redis/blob/master/docs/transactions . MD

以上就是本文的全部内容。希望本文的内容能给大家的学习或工作带来一些帮助,也希望多多支持我们!

更多资讯
游戏推荐
更多+