Redis到底該如何利用?

来源:https://www.cnblogs.com/supersnowyao/archive/2018/01/01/8167850.html
-Advertisement-
Play Games

Redis是個好東西,經過上兩個星期的研究和實踐,目前正在項目里大規模的替換掉原來的本地記憶體cache。但是替換過程中卻發現,Redis這東西高端,大氣上檔次,似乎不是我想象里的使用方法。 在沒有深入Redis之前,在我的概念里,緩存,就是key-value。而使用方式肯定不需要改動多少代碼,一切都 ...


    Redis是個好東西,經過上兩個星期的研究和實踐,目前正在項目里大規模的替換掉原來的本地記憶體cache。但是替換過程中卻發現,Redis這東西高端,大氣上檔次,似乎不是我想象里的使用方法。

    在沒有深入Redis之前,在我的概念里,緩存,就是key-value。而使用方式肯定不需要改動多少代碼,一切都是Get/Set。但是實際用的時候卻發現,我錯了,不是所有的場景都是簡單的Get/Set。也不是所有的數據都適合key-Value,於是有了這個問題,Redis到底該如何使用?我問自己,也向園子里的朋友們求助,希望幫忙解答。當然,這篇文章拋磚引玉,先談談我這兩周的感悟。

使用場景

    在我的項目里,有一個提供給Autocomplete的功能,數據量大概在幾萬。這篇文章里我用姓名檢索的例子來說明,列表請戳來自Redis作者的Demo。

    在這樣的列表裡全是用戶名,例如我們的系統里有一個用戶對象:

1 public Class User
2 {
3      public string Id{get; set;}  
4      public string Name {get; set;}
5      ....
6      public string UserHead {get; set;}    
7 }

    系統里需要一個用戶的下拉列表,由於數據量大不能一次顯示完,於是就加上了一個AutoComplete功能。如果是不用Redis這樣的集中式緩存,直接緩存在本機記憶體里,那麼結構很簡單如下:

1 var users = new List<User>{...};//讀到一個用戶列表
2 MemoryCache.Set("capqueen:users", users);//放入記憶體
3 
4 //讀取
5 var users = MemoryCache.Get<List<User>>("capqueen:users");

    因為都是在記憶體里,所以直接存List就可以了,搜索的時候也可以直接的如下:

1 var findUsers = users.Where(user => user.Name.StartWith("A")).ToList();例如輸入的字元是 "A"

    相當簡單,完全不用考慮如何存儲,存儲的數據結構。但是換到了Redis這些集中式緩存服務之後,咱們再來思考,該如何存儲。

    方案一:類似記憶體式的緩存實現。

    本文里使用的Redis鏈接庫是StactkExchange.Redis,出自StackOverFlow的開源產品。

1 var db = redis.GetDataBase();//獲取0資料庫
2 
3 var usersJson = JsonConvert.SerializeObject(users)//序列化
4 
5 db.StringSet("capqueen:users", usersJson);//存儲
6 
7 var usersString = db.StringGet("capqueen:users");
8 var userList = JsonConvert.DeserializeObject<List<User>>(usersString);//反序列化

    上面的方式邏輯上是沒有問題的,編譯也可以通過。但是仔細想一想,Redis作為獨立的緩存服務和appSever是分開來的,這樣的讀取方式對redis伺服器的IO是個負擔,甚至這樣的讀取比本地記憶體緩存慢了太多了。

    那如何解決呢?試想key-value的精髓是在於Key,那麼對於List來說應該要把item分開來存儲。

    方案二:Keys模糊匹配。

    在查看了Redis的命令文檔(見參考資料4)之後,發現了命令Keys,如獲至寶,立馬修改了方案。首先我們需要把要搜索的關鍵詞建立為key,這裡我把key定義為 "capqueen:user:{id}:{name}",其中{}內的是要用item對應屬性替換的。代碼如下:

 1 var redis = ConnectionMultiplexer.Connect("localhost");
 2 var db = redis.GetDatabase();
 3            
 4 var users = new List<User> { 
 5     new User{Id = 6, Name = "aaren", Age=10},
 6     new User{Id = 7, Name = "issy", Age=11},
 7     new User{Id = 8, Name = "janina", Age=13},
 8     new User{Id = 9, Name = "karena", Age=14}
 9 };
10 
11 users.ForEach(item => { 
12    var key = string.Format("capqueen:user:{0}:{1}", item.Id, item.Name);
13    var value = JsonConvert.SerializeObject(item);
14    db.StringSet(key, value);
15 });

    建立好的緩存如下圖所示:

    所有的user都以單獨的Key-Value方式存儲,那麼如何利用Keys搜索呢?我們來看下Redis的Keys命令:

1 KEYS pattern
2 
3 查找所有符合給定模式 pattern 的 key 。
4 
5 KEYS * 匹配資料庫中所有 key 。
6 KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
7 KEYS h*llo 匹配 hllo 和 heeeeello 等。
8 KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
9 特殊符號用 \ 隔開

 

     也就是說Keys能夠進行簡單的模糊匹配,那麼我們這裡的搜索就可以換成如下的方式:

var redis = ConnectionMultiplexer.Connect("192.168.10.178");
var db = redis.GetDatabase();
var server = redis.GetServer("192.168.10.178", 6379);
var keys = server.Keys(pattern: "capqueen:user:*:a*");
var values = db.StringGet(keys.ToArray());

//反序列化
var jsonValues = new StringBuilder("[");
values.ToList().ForEach(item => jsonValues.Append(item).Append(","));
jsonValues.Append("]");
var userList = JsonConvert.DeserializeObject<List<User>>(jsonValues.ToString());

 

    註意以上的代碼里,因為每個value是一個json,為了增加轉化時的效率,我先處理成json arry再進行反序列化。

    這種方案,確實是解決了我目前的問題,然而我註意到了Redis文檔里的一段話:

    KEYS 的速度非常快,但在一個大的資料庫中使用它仍然可能造成性能問題,如果你需要從一個數據集中查找特定的 key ,你最好還是用 Redis 的集合結構(set)來代替。

    這段話換而言之就是慎用Keys搜索的意思,那麼有什麼更好的解決方案呢?由於這篇文章我拖得很久了,這裡留個問題在末尾,期待有大牛能夠幫忙解答,感激不盡。當然還有下一篇內容,我會講講我目前的處理方法。

下篇文章里,我會根據Redis作者的博客(資料1)里的做法以及我最後查到的資料,做一個新的方案,請大家到時指教。

參考資料

  1. Redis作者博客,這是其中一篇講如何基於Redis實現AutoComplete的文章:http://oldblog.antirez.com/post/autocomplete-with-redis.html
  2. Redis 第三方管理工具 For Windows:http://redisdesktop.com/
  3. Redis .NET鏈接工具的Top20:http://nugetmusthaves.com/Tag/Redis
  4. Redis命令中文文檔:http://redisdoc.com/

文章轉自:http://www.cnblogs.com/capqueen/p/HowToUseRedis.html


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

-Advertisement-
Play Games
更多相關文章
  • 之前寫完vue項目後,佈置到伺服器,用nginx反向代理後,一開始進去,進各種路由都是沒問題的,但是一旦f5刷新後就會出現一個nginx404的錯誤。 經過翻閱vue文檔後,發現這是vueHistory 模式下的一個問題,需要後臺配置支持。 History 模式是沒有hash鍵,比如/a/b,f5刷 ...
  • 前言 這裡分享一個博主寫的省市區三級菜單聯動插件 — jQuery Citys,此插件中所有省市區數據均為國家行政區劃代碼,保證數據真實可靠,插件可以根據預設地區代碼或地區名稱進行值的初始化操作。 線上演示地址:https://yangyunhe369.github.io/jQuery Citys ...
  • 無限滾動載入最佳實踐 無限滾動(Infinite scrolling),有時候被稱為無盡滾動(endless scrolling),這種技術允許用戶在大量內容上滾動,眼中看不到結束的地方。這種技術很簡單,就是頁面往下滾動的時候保持刷新。 這項技術使用戶在沒有 打斷 和 額外交互 的情況下滾動列表 — ...
  • Promise API 簡介 譯者註: 到處是回調函數,代碼非常臃腫難看, Promise 主要用來解決這種編程方式, 將某些代碼封裝於內部。 Promise 直譯為“承諾”,但一般直接稱為 Promise; 代碼的可讀性非常重要,因為開發人員支出一般比電腦硬體的支出要大很多倍。 雖然同步代碼更容 ...
  • 在HTML5的規範中,我們可以通過為元素增加`draggable="true"`來設置此元素是否可以進行拖拽操作,其中圖片、鏈接預設是開啟的。 1. 拖拽元素:設置了`draggable="true"`的元素 當拖動某元素時,將依次觸發下列事件: 1. dragstart(按下滑鼠並開始移動滑鼠時, ...
  • 13.Label的作用是什麼?是怎麼用的? label標簽來定義表單控制間的關係,當用戶選擇該標簽時,瀏覽器會自動將焦點轉到和標簽相關的表單事件上。 <label for="Name">Number:</label> <input type="text" name="Name" id="Name"/ ...
  • 開篇 天天逛博客園,就是狠不下心來寫篇博客,忙是一方面,但是說忙能有多忙呢,都有時間逛博客園,寫篇博客的時間都沒有?(這還真不好說) 每次想到寫一篇新的設計模式,我總會問自己: 1,自己理解了嗎? 2,我能以一種簡單且有邏輯的方式把它說出來嗎? 不說做到有的放矢,但是一本正經的胡說八道還是要有吧,起 ...
  • Cache緩存在電腦領域是一個被普遍使用的概念。硬體中CPU有一級緩存,二級緩存, 瀏覽器中有緩存,軟體開發中也有分散式緩存memcache, redis。緩存無處不在的原因是它能夠極大地提高硬體和軟體的運行速度。在項目開發中,性能慢的地方常常是IO操作頻繁的地方,讀取資料庫是我們常見的消耗性能的 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...