redis大幅性能提升之使用管道(PipeLine)和批量(Batch)操作

来源:http://www.cnblogs.com/huangxincheng/archive/2016/12/22/6212406.html
-Advertisement-
Play Games

前段時間在做用戶畫像的時候,遇到了這樣的一個問題,記錄某一個商品的用戶購買群,剛好這種需求就可以用到Redis中的Set,key作為productID,value 就是具體的customerid集合,後續的話,我就可以通過productid來查看該customerid是否買了此商品,如果購買了,就可 ...


  

       前段時間在做用戶畫像的時候,遇到了這樣的一個問題,記錄某一個商品的用戶購買群,剛好這種需求就可以用到Redis中的Set,key作為productID,value

就是具體的customerid集合,後續的話,我就可以通過productid來查看該customerid是否買了此商品,如果購買了,就可以有相關的關聯推薦,當然這隻是系統中

的一個小業務條件,這時候我就可以用到SADD操作方法,代碼如下:

        static void Main(string[] args)
        {
            ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");

            var db = redis.GetDatabase();

            var productID = string.Format("productID_{0}", 1);

            for (int i = 0; i < 10; i++)
            {
                var customerID = i;

                db.SetAdd(productID, customerID);
            }
        }

 

一:問題

    但是上面的這段代碼很明顯存在一個大問題,Redis本身就是基於tcp的一個Request/Response protocol模式,不信的話,可以用wireshark監視一下:

從圖中可以看到,有很多次的192.168.23.1 => 192.168.23.151 之間的數據往返,從傳輸內容中大概也可以看到有一個叫做productid_xxx的首碼,

那如果有百萬次區域網這樣的round trip,那這個延遲性可想而知,肯定達不到我們預想的高性能。

 

二:解決方案【Batch】

     剛好基於我們現有的業務,我可以定時的將批量的productid和customerid進行分組整合,然後用batch的形式插入到某一個具體的product的set中去,

接下來我可以把上面的代碼改成類似下麵這樣:

 1         static void Main(string[] args)
 2         {
 3             ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");
 4 
 5             var db = redis.GetDatabase();
 6 
 7             var productID = string.Format("productID_{0}", 1);
 8 
 9             var list = new List<int>();
10 
11 
12             for (int i = 0; i < 10; i++)
13             {
14                 list.Add(i);
15             }
16 
17             db.SetAdd(productID, list.Select(i => (RedisValue)i).ToArray());
18         }

 

從截圖中傳輸的request,response可以看到,這次我們一次性提交過去,極大的較少了在網路傳輸方面帶來的尷尬性。。

 

三:再次提出問題

  product維度的畫像我們可以解決了,但是我們還有一個customerid的維度,也就是說我需要維護一個customerid為key的set集合,其中value的值為

該customerid的各種平均值,比如說“總交易次數”,“總交易金額”。。。等等這樣的聚合信息,然後推送過來的是批量的customerid,也就是說你需要定時

維護一小嘬set集合,在這種情況下某一個set的批量操作就搞不定了。。。原始代碼如下:

 1         static void Main(string[] args)
 2         {
 3             ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");
 4 
 5             var db = redis.GetDatabase();
 6 
 7 
 8             //批量過來的數據: customeridlist, ordertotalprice,具體業務邏輯省略
 9             var orderTotalPrice = 100;
10 
11             var customerIDList = new List<int>();
12 
13             for (int i = 0; i < 10; i++)
14             {
15                 customerIDList.Add(i);
16             }
17 
18             //foreach更新每個redis 的set集合
19             foreach (var item in customerIDList)
20             {
21                 var customerID = string.Format("customerid_{0}", item);
22 
23                 db.SetAdd(customerID, orderTotalPrice);
24             }
25         }

 

四:解決方案【PipeLine】

    上面這種代碼在生產上當然是行不通的,不過針對這種問題,redis早已經提出了相關的解決方案,那就是pipeline機制,原理還是一樣,將命令集整合起來通過

一條request請求一起送過去,由redis內部fake出一個client做批量執行操作,代碼如下:

 1         static void Main(string[] args)
 2         {
 3             ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.23.151:6379");
 4 
 5             var db = redis.GetDatabase();
 6 
 7 
 8             //批量過來的數據: customeridlist, ordertotalprice,具體業務邏輯省略
 9             var orderTotalPrice = 100;
10 
11             var customerIDList = new List<int>();
12 
13             for (int i = 0; i < 10; i++)
14             {
15                 customerIDList.Add(i);
16             }
17 
18             var batch = db.CreateBatch();
19 
20             foreach (var item in customerIDList)
21             {
22                 var customerID = string.Format("customerid_{0}", item);
23 
24                 batch.SetAddAsync(customerID, orderTotalPrice);
25             }
26 
27             batch.Execute();
28         }

 

然後,我們再看下麵的wireshark截圖,可以看到有很多的SADD這樣的小命令,這就說明有很多命令是一起過去的,大大的提升了性能。

 

最後可以再看一下redis,數據也是有的,是不是很爽~~~

192.168.23.151:6379> keys *
 1) "customerid_0"
 2) "customerid_9"
 3) "customerid_1"
 4) "customerid_3"
 5) "customerid_8"
 6) "customerid_2"
 7) "customerid_7"
 8) "customerid_5"
 9) "customerid_6"
10) "customerid_4"

 

好了,先就說到這裡了,希望本篇對你有幫助。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <!doctype html><html><head> <meta charset="UTF-8"> <title>前端Demo常用庫文件鏈接</title> <!--bootstrap--> <link rel="stylesheet" href="http://cdn.bootcss.com/b ...
  • localStorage(本地存儲),可以長期存儲數據,沒有時間限制,一天,一年,兩年甚至更長,數據都可以使用。sessionStorage(會話存儲),只有在瀏覽器被關閉之前使用,創建另一個頁面時同意可以使用,關閉瀏覽器之後數據就會消失。 HTML5 的本地存儲 API 中的 localStora ...
  • 1、Math.random():返回 0 ~ 1 之間的隨機數。2、Math.ceil():返回值:返回大於或等於x,並且與之最接近的整數(如果x是正數,則把小數“入”;如果x是負數,則把小數“舍”)。3、Math.round():四捨五入取整。4、Math.floor():返回值:返回小於或等於x ...
  • 僅記錄一些我工作中常用的自定義js函數。 1、獲取URL請求參數 調用方式:var id = GetQueryString("id"); 2、在文本框中游標位置插入文本值 調用方式:這裡使用了easyui中的combobox控制項和ueditor富文本控制項 easyui-combobox代碼: $(" ...
  • 第一種方法: 第二種方法: ...
  • Observer協處理器通常在一個特定的事件(諸如Get或Put)之前或之後發生,相當於RDBMS中的觸發器。Endpoint協處理器則類似於RDBMS中的存儲過程,因為它可以讓你在RegionServer上對數據執行自定義計算,而不是在客戶端上執行計算。 本文是以上兩者的簡單實例,使用的環境:環境 ...
  • MongoDB提供了備份和恢復的功能,分別是MongoDB下載目錄下的mongodump.exe和mongorestore.exe文件 1.備份數據使用下麵的命令: >mongodump -h dbhost -d dbname -o dbdirectory -h:MongDB所在伺服器地址,例如:1 ...
  • 1.創建集合有兩種方式,顯示創建和隱式創建 顯示創建可以使用命令 db.createCollection(“集合名稱") 隱式創建可以使用命令 db.集合名稱.insert({}),指創建集合併同時向集合中插入數據,例如:db.customer.insert({name:”jack”}) 刪除集合使 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...