激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - .NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

2020-04-27 14:26張龍豪 ASP.NET教程

本文主要介紹了.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)的相關知識。具有很好的參考價值,下面跟著小編一起來看下吧

序言

Redis中的管道(PipeLine)特性:簡述一下就是,Redis如何從客戶端一次發送多個命令,服務端到客戶端如何一次性響應多個命令。

Redis使用的是客戶端-服務器模型和請求/響應協議的TCP服務器,這就意味著一個請求要有以下步驟才能完成:1、客戶端向服務器發送查詢命令,然后通常以阻塞的方式等待服務器相應。2、服務器處理查詢命令,并將相應發送回客戶端。這樣便會通過網絡連接,如果是本地回環接口那么就能特別迅速的響應,但是如果走外網,甚至外網再做一系列的層層轉發,那就顯的格外蛋疼。無論網絡延時是多少,那么都將占用整體響應的時間。這樣一來如果一次發送1個命令,網絡延時為100ms,我們不得不做。那么如果1次發1000個命令,那么網絡延時100*1000ms就很難容忍啦。

針對與上面的問題,Redis在2.6版本以后就都提供啦管道(Pipeline)功能。他可以使客戶端在沒有讀取舊的響應時,處理新的請求。這樣便可以向服務器發送多個命令,而不必等待答復,直到最后一個步驟中讀取答復。這被稱為管線(PipeLine),并且是幾十年來廣泛使用的技術。例如,許多POP3協議實現已經支持此功能,大大加快了從服務器下載新電子郵件的過程。

那么事務這個詞匯,經常遇到,就不多唧唧啦,目標要一致就好,便是一組操作怎么做成原子性操作,使他去不了終點,回到原點。

簡述wireshark抓包工具

為啦讓大家對管線有更形象的感觀,這一節我們先說說Wireshark抓包工具,他會讓你看到客戶端到服務器通過tcp協議發送的redis命令的過程與詳細。

wireshark能夠撲捉到系統發送和接受的每一個報文,我們這里只做一些過濾的簡述。下圖就是他的樣子,你打開后可以可以摸索下他的用法。

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

簡述幾個過濾規則:

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服務器進行多次請求的話,一般普通模式是這樣子的

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

客戶端對redis服務器進行多次請求的話,管道模式是這樣子的

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

一般模式我們上代碼:

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

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

查看tcp請求報文的data

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

這樣你自己做的過程中,可以看到我圈起來的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();
        }
 

再來看下請求

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

這樣很明顯就能看出來是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();
        }
 

結果如下:

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

到此我還要說一下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。數據庫中結果如下,說明我們插入成功。

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

即:如果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的數據:

.NET客戶端實現Redis中的管道(PipeLine)與事物(Transactions)

原因分析: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個交流群,我們一起學習探討。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 女人一级一级毛片 | 美女很黄很黄免费的 | 嗯哈~不行好大h双性 | 欧美成人精品一区二区男人小说 | 本站只有精品 | 成年性羞羞视频免费观看无限 | www69xxxxx| 一区二区三区日韩电影 | 成人在线观看免费视频 | 久草在线视频新 | 亚洲网站免费 | 亚洲男人一区 | 国产成人精品一区二区视频免费 | 中文字幕www. | 一级做受毛片免费大片 | 国产免费高清在线 | a一级黄| 国内精品久久久久久久影视红豆 | 一级观看免费完整版视频 | 久久免费视频5 | 九九热视频免费观看 | 日本一级黄色大片 | 娇妻被各种姿势c到高潮小说 | 激情网站在线观看 | 少妇一级淫片免费放播放 | 亚洲二区免费 | 国产高潮好爽好大受不了了 | 欧美成人一区在线观看 | 毛片在线视频观看 | 国产精品7区 | 精品一区二区三区日本 | 久久精品re | 国产在线免 | 超碰人人做人人爱 | 中国一级免费视频 | 久夜tv | 成人精品视频网站 | 影视免费观看 | 2019亚洲日韩新视频 | 91成人在线网站 | 午夜视频在线 |