序言

Redis中的管道(PipeLine)特性:简述一下就是,Redis如何从客户端一次发送多个命令,服务端到客户端如何一次性响应多个命令。

Redis使用的是客户端-服务器模型和请求/响应协议的TCP服务器,这就意味着一个请求要有以下步骤才能完成:1、客户端向服务器发送查询命令,然后通常以阻塞的方式等待服务器相应。2、服务器处理查询命令,并将相应发送回客户端。这样便会通过网络连接,如果是本地回环接口那么就能特别迅速的响应,但是如果走外网,甚至外网再做一系列的层层转发,那就显的格外蛋疼。无论网络延时是多少,那么都将占用整体响应的时间。这样一来如果一次发送1个命令,网络延时为100ms,我们不得不做。那么如果1次发1000个命令,那么网络延时100*1000ms就很难容忍啦。

针对与上面的问题,Redis在2.6版本以后就都提供啦管道(Pipeline)功能。他可以使客户端在没有读取旧的响应时,处理新的请求。这样便可以向服务器发送多个命令,而不必等待答复,直到最后一个步骤中读取答复。这被称为管线(PipeLine),并且是几十年来广泛使用的技术。例如,许多POP3协议实现已经支持此功能,大大加快了从服务器下载新电子邮件的过程。

那么事务这个词汇,经常遇到,就不多唧唧啦,目标要一致就好,便是一组操作怎么做成原子性操作,使他去不了终点,回到原点。

简述wireshark抓包工具

为啦让大家对管线有更形象的感观,这一节我们先说说Wireshark抓包工具,他会让你看到客户端到服务器通过tcp协议发送的redis命令的过程与详细。

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、如果使用多条件过滤,则需要加连接符号,and。比如 ip.src==192.168.1.12 and http.request.method=="POST" and tcp.srcport==80

StackExchange.Redis实现Redis管线(Pipeline)

上两张图片管线便一目了然啦。

客户端对redis服务器进行多次请求的话,一般普通模式是这样子的

客户端对redis服务器进行多次请求的话,管道模式是这样子的

一般模式我们上代码:

 public static void GetNoPipelining(){for (var i = 0; i < 3; i++){var key = "name:" + i;db.StringAppend(key, "张龙豪");}}

查看tcp请求报文的data

这样你自己做的过程中,可以看到我圈起来的3个tcp请求的key分别为name:0,name:1,name:2这样子。

那么我们使用管道模式

 public static void GetPipelining(){var batch = db.CreateBatch();for (int i = 0; i < 3; i++){var key = "mename:" + i;batch.StringAppendAsync(key, "张龙豪");}batch.Execute();}

再来看下请求

这样很明显就能看出来是1个请求发送出来啦多个命令。那么我们不用createBatch()也是可以实现这样的效果的。

            var a = db.StringAppendAsync("zlh:1", "zhanglonghao1");var b = db.StringAppendAsync("zlh:2", "zhanglonghao2");var c = db.StringAppendAsync("zlh:3", "zhanglonghao3");var aa = db.Wait(a);var bb = db.Wait(a);var cc = db.Wait(a);

在接下来我们做一个简单的性能比较。代码如下:

  static void Main(string[] args){Stopwatch watch = new Stopwatch();Stopwatch watch1 = new Stopwatch();watch.Start();GetNoPipelining();Console.WriteLine("一般循环耗时:" + watch.ElapsedMilliseconds);watch.Stop();watch1.Start();GetPipelining();Console.WriteLine("Pipelining插入耗时:" + watch1.ElapsedMilliseconds);watch1.Stop();Console.ReadLine();}public static void GetNoPipelining(){for (var i = 0; i < 5000; i++){var key = "name:" + i;db.StringAppend(key, "张龙豪");}}public static void GetPipelining(){var batch = db.CreateBatch();for (int i = 0; i < 5000; i++){var key = "mename:" + i;batch.StringAppendAsync(key, "张龙豪");}batch.Execute();}

结果如下:

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

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

2、async:异步模式,使用task模型封装。

3、fire-and-forget:发送命令,然后完全不关心最终什么时候完成命令操作。在Fire-and-Forget模式下,所有命令都会立即得到返回值,该值都是该返回值类型的默认值,比如操作返回类型是bool将会立即得到false,因为false = default(bool)。

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

https://redis.io/topics/pipelining

https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/PipelinesMultiplexers.md

StackExchange.Redis实现Redis事务(Transactions)

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

 static void Main(string[] args){var tran = db.CreateTransaction();tran.AddCondition(Condition.ListIndexNotEqual("zlh:1",0,"zhanglonghao"));        tran.ListRightPushAsync("zlh:1", "zhanglonghao"); bool committed = tran.Execute();Console.WriteLine(committed);Console.ReadLine();}

执行结果为:true。数据库中结果如下,说明我们插入成功。

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

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

 static void Main(string[] args){var tran = db.CreateTransaction();tran.AddCondition(Condition.ListIndexNotEqual("zlh:1",0,"zhanglonghao"));        tran.ListRightPushAsync("zlh:1", "zhanglonghao1");           bool committed = tran.Execute();Console.WriteLine(committed);Console.ReadLine();}

结果为false,数据库没有增减数据。已久与上图的数据保持一致。

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

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

 static void Main(string[] args){var tran = db.CreateTransaction();tran.AddCondition(Condition.ListIndexEqual("zlh:1",0,"zhanglonghao"));        tran.ListRightPushAsync("zlh:1", "zhanglonghao1");           bool committed = tran.Execute();Console.WriteLine(committed);Console.ReadLine();}

结果为true,数据结果如下,增长一条值为zhanglonghao1的数据:

原因分析:ListIndexEqual("zlh:1",0,"zhanglonghao")为真命题,执行下面的操作,提交事物。

数据不删继续上代码:

static void Main(string[] args){var tran = db.CreateTransaction();tran.AddCondition(Condition.ListIndexEqual("zlh:1",0,"zhanglonghao"));        tran.ListRightPushAsync("zlh:1", "zhanglonghao2");tran.AddCondition(Condition.ListIndexNotEqual("zlh:1", 0, "zhanglonghao"));tran.ListRightPushAsync("zlh:1", "zhanglonghao3");bool committed = tran.Execute();Console.WriteLine(committed);Console.ReadLine();}

结果为false,数据库数据已久与上面的保持一致,不增不减。

分析原因:Condition.ListIndexEqual("zlh:1",0,"zhanglonghao")为true,但是到下面的ListIndexNotEqual("zlh:1", 0, "zhanglonghao")为false。故整个事物的操作回滚,不予执行,故数据库没有变化。

到此,我就不写多余的代码啦,但我要说几个注意点:

1、执行命令的操作需为异步操作。

2、在事物中执行的命令,都不会直接看到结果,故此结果也不能用于下面代码做判断,因为当前的异步命令在Execute()之前是不会对数据库产生任何影响的。

3、参考文档:https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/Transactions.md

总结

接下来是大家最喜欢的总结内容啦,内容有二,如下:

1、希望能关注我其他的文章。

2、博客里面有没有很清楚的说明白,或者你有更好的方式,那么欢迎加入左上方的2个交流群,我们一起学习探讨。

转载于:https://www.cnblogs.com/knowledgesea/p/6552799.html

.NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)相关推荐

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

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

  2. python redis pipeline使用方法_Redis中的管道Pipeline操作

    点击上方蓝色字体,选择"设为星标" 回复"资源"获取更多资源 点击右侧关注,大数据开发领域最强公众号! 点击右侧关注,暴走大数据! Redis默认每次执行请求都 ...

  3. redis中multi和pipeline区别以及效率(推荐使用pipeline)

    手册得知 pipeline 只是把多个redis指令一起发出去,redis并没有保证这些指定的执行是原子的:multi相当于一个redis的transaction的,保证整个操作的原子性,避免由于中途 ...

  4. Redis中的管道有什么用?

    一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应.这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复. 这就是管道(pipelining),是一种几十年来广泛使用 ...

  5. php怎么用redisson,Redis中RedisTemplate和Redisson管道的使用

    当对Redis进行高频次的命令发送时,由于网络IO的原因,会耗去大量的时间.所以Redis提供了管道技术,就是将命令一次性批量的发送给Redis,从而减少IO. 一.Jedis对redis的管道进行操 ...

  6. Redis的管道pipeline

    本文来说下Redis的管道pipeline 文章目录 概述 Redis管道技术 SpringDataRedis使用管道 使用管道技术的注意事项 本文小结 概述 Redis提供了一个称为管道(Pipel ...

  7. Redis 中常见的 15个坑,你踩过几个?

    Redis 是我们系统开发中必须要用到的一个组件,那它都有哪些需要主要的地方呢?本文我们就来盘点一下 Redis 中常见的一些坑: 明明一个 key 设置了过期时间,怎么变成不过期了? 使用 O(1) ...

  8. redis中的事务、lua脚本和管道的使用场景

    https://blog.csdn.net/fangjian1204/article/details/50585080 事务 redis中的事务并不像mysql中那么完美,只是简单的保证了原子性.re ...

  9. redis管道pipeline的运用

    Redis使用的是客户端-服务器(CS)模型和请求/响应协议的TCP服务器.这意味着通常情况下一个请求会遵循以下步骤: 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服 ...

  10. Python中使用Redis的批处理工具pipeline(这种方法从底层思考效率还是低于“订阅发布机制”)

    一.pipeline出现的原因 1.Redis执行命令的过程 redis客户端执行一条命令的过程: 发送命令-〉命令排队-〉命令执行-〉返回结果 使用python给redis发送命令时的过程: 客户端 ...

最新文章

  1. Openstack-M版(双节点)热迁移记录
  2. oracle 压测工具 ld,Oracle压力测试工具使用说明
  3. python多维数组运用_使用Python将文件读入多维数组
  4. 【转】医学影像处理相关知识整理(一)
  5. OP和DBA相关的一些有用资源
  6. 阿特拉斯开发协议--与ATLAS 扭力控制器交互
  7. 如何安装虚拟光驱大学计算机考试,用虚拟光驱安装win10专业版的方法
  8. iOS网络编程-iCloud文档存储编程实例
  9. 论文阅读笔记(Region Proposal by Guided Anchoring)
  10. 压缩包解压后的文件名是乱码怎么解决
  11. qq群文件安全检测未通过最完美解决办法
  12. [讲座论坛] 竹资源培育与中国竹产业
  13. EasyUI(修改删除)
  14. 习题 5.12 编写一程序,将两个字符串连接起来,结果取代第一个字符串。
  15. 2020-2025年四大数字技术对数字经济的影响
  16. python抓取网站访客手机号_电商 生意参谋 抓取 访客数据 Python版
  17. 我的漫漫程序人生路(上)
  18. Stack和Queue:后进先出和先进先出
  19. nvidia平台重新安装sdkmanager运行不生效问题
  20. matlab 实现2048游戏

热门文章

  1. redis数据结构存储Linked List设计细节(redis的设计与实现笔记)
  2. chkconfig用法
  3. 【DIOCP开源项目】实际应用案例
  4. Spring或Hibernate其实都提供了透明处理Clob的方法
  5. hibernate入门二之单表操作
  6. Luogu P4403 [BJWC2008]秦腾与教学评估【二分答案】By cellur925
  7. 最全解析如何正确学习JavaScript指南,必看!
  8. CMS4.0——后知后觉
  9. 使用Json.Net处理json序列化和反序列化接口或继承类
  10. java笔记--查看和修改线程名称