Redis的使用難嗎?不難,Redis用好容易嗎?不容易。Redis的使用雖然不難,但與業務結合的應用場景特別多、特別緊,用好並不容易。我們希望通過一篇文章及Demo,即可輕鬆、快速入門並學會應用。 一、Redis 簡介 Redis是一個開源的Key-Value存儲,但又不僅僅是Key-Value存 ...
Redis的使用難嗎?不難,Redis用好容易嗎?不容易。Redis的使用雖然不難,但與業務結合的應用場景特別多、特別緊,用好並不容易。我們希望通過一篇文章及Demo,即可輕鬆、快速入門並學會應用。
一、Redis 簡介
Redis是一個開源的Key-Value存儲,但又不僅僅是Key-Value存儲,用官網上的話來說,Redis是一個數據結構存儲,可用作資料庫、緩存和消息中間件。相對於傳統的Key-Value存儲Memcached來說,Redis具有如下特點:
- 速度快
- 豐富的數據結構,除String之外,還有List、Hash、Set、Sorted Set
- 單線程,避免了線程切換和鎖的性能消耗
- 原子操作
- 可持久化(RDB與AOF)
- 發佈/訂閱
- 支持Lua腳本
- 分散式鎖
- 事務
- 主從複製與高可用(Redis Sentinel)
- 集群(3.0版本以上)
( 備註:
Redis中數據存儲模式有2種:cache-only,persistence:
cache-only:即只做為“緩存”服務,不持久數據,數據在服務終止後將消失,此模式下也將不存在“數據恢復”的手段,是一種安全性低/效率高/容易擴展的方式;
persistence:即為記憶體中的數據持久備份到磁碟文件,在服務重啟後可以恢復,此模式下數據相對安全;
對於persistence持久化存儲,Redis提供了兩種持久化方法:
Redis DataBase(簡稱RDB)
Append-only file(簡稱AOF)
RDB:是在某個時間點將數據寫入一個臨時文件,持久化結束後,用這個臨時文件替換上次持久化的文件,達到數據恢復。
1)優點:使用單獨子進程來進行持久化,主進程不會進行任何IO操作,保證了redis的高性能
2)缺點:RDB是間隔一段時間進行持久化,如果持久化之間redis發生故障,會發生數據丟失。所以這種方式更適合數據要求不嚴謹的時候
AOF:將“操作 + 數據”以格式化指令的方式追加到操作日誌文件的尾部,在append操作返回後(已經寫入到文件或者即將寫入),才進行實際的數據變更,“日誌文件”保存了歷史所有的操作過程;當server需要數據恢復時,可以直接replay此日誌文件,即可還原所有的操作過程。AOF相對可靠,它和mysql中bin.log、apache.log、zookeeper中txn-log簡直異曲同工。AOF文件內容是字元串,非常容易閱讀和解析。
1)優點:可以保持更高的數據完整性,如果設置追加file的時間是1s,如果redis發生故障,最多會丟失1s的數據;且如果日誌寫入不完整支持redis-check-aof來進行日誌修複;AOF文件沒被rewrite之前(文件過大時會對命令進行合併重寫),可以刪除其中的某些命令(比如誤操作的flushall)。
2)缺點:AOF文件比RDB文件大,且恢復速度慢。
)
二、Redis 數據結構
1、String
這是最簡單的Redis類型。如果只使用這種類型,Redis就像一個可持久化的Memcached伺服器。
2、List
Redis的List是基於雙向鏈表實現的,可以支持反向查找和遍歷。
常用案例:聊天系統、社交網路中獲取用戶最新發表的帖子、簡單的消息隊列、新聞的分頁列表、博客的評論系統。
3、Hash
Hash是一個String類型的field和value之間的映射表,請見下圖,類似於.NET中的Hashtable和Dictionary。主要用來存儲對象,可以避免序列化的開銷和併發修改控制的問題。
4、Set
Set也是一個列表,不過它的特殊之處在於它是可以自動排重的:當需要存儲一個列表數據,而又不希望出現重覆的時候,Set是一個很好的選擇(比如ID的集合)。並且Set提供了判斷某個成員是否在一個Set集合內的介面,這也是List所沒有的。
5、Sorted Set
Sorted Set和Set的使用場景類似,區別是Sorted Set會根據提供的score參數來進行自動排序。當你需要一個有序的並且不重覆的集合列表,那麼就可以選擇Sorted Set數據結構。常用案例:游戲中的排行榜。
三、 Redis 重要特性
以下特性請重點看管道和事務。
1、管道
Redis管道是指客戶端可以將多個命令一次性發送到伺服器,然後由伺服器一次性返回所有結果。管道技術在批量執行命令的時候可以大大減少網路傳輸的開銷,提高性能。
2、事務
Redis事務是一組命令的集合。一個事務中的命令要麼都執行,要麼都不執行。如果命令在運行期間出現錯誤,不會自動回滾。
管道與事務的區別:管道主要是網路上的優化,客戶端緩衝一組命令,一次性發送到伺服器端執行,但是並不能保證命令是在同一個事務裡面執行;而事務是原子性的,可以確保命令執行的時候不會有來自其他客戶端的命令插入到命令序列中。
3、分散式鎖
分散式鎖是控制分散式系統之間同步訪問共用資源的一種方式。在分散式系統中,常常需要協調他們的動作,如果不同的系統或是同一個系統的不同主機之間共用了一個或一組資源,那麼訪問這些資源的時候,往往需要互斥來防止彼此干擾來保證一致性,在這種情況下,便需要使用到分散式鎖。
4、地理信息
從Redis 3.2版本開始,新增了地理信息相關的命令,可以將用戶給定的地理位置信息(經緯度)存儲起來,並對這些信息進行操作。
四、 使用方法
步驟1、在需要使用Redis的項目中引用FxCommon.dll和Redis.dll。
步驟2、在App.config或Web.config文件中添加如下配置:
1 <add key="RedisServerIP" value="redis:[email protected]:4125"/>
2 <!-- 提供的 Redis 環境是單機版配置。如果 Redis 是主從配置,則還需設置 RedisSlaveServerIP-->
3 <!--<add key="RedisSlaveServerIP" value="redis:[email protected]:4125"/>-->
4
5 <!--Redis 資料庫。如果不需要指定 Redis 資料庫,就配置預設值 0-->
6 <add key="RedisDefaultDb" value="0"/>
步驟 3、使用 PooledRedisClientManager 類創建 Redis 連接池:
1 // 讀取 Redis 主機 IP 配置信息
2 string[] redisMasterHosts = ConfigurationManager.ConnectionStrings["RedisServerIP"].ConnectionString.Split(',');
3
4 // 如果 Redis 伺服器是主從配置,那麼還需要讀取 Redis Slave 機的 IP 配置信息
5 string[] redisSlaveHosts = null;
6 var slaveConnection = ConfigurationManager.ConnectionStrings["RedisSlaveServerIP"];
7 if (slaveConnection != null && !string.IsNullOrWhiteSpace(slaveConnection.ConnectionString))
8 {
9 string redisSlaveHostConfig = slaveConnection.ConnectionString;
10 redisSlaveHosts = redisSlaveHostConfig.Split(',');
11 }
12
13 // 讀取 RedisDefaultDb 配置
14 int defaultDb = 0;
15 string defaultDbSetting = ConfigurationManager.AppSettings["RedisDefaultDb"];
16 if (!string.IsNullOrWhiteSpace(defaultDbSetting))
17 {
18 int.TryParse(defaultDbSetting, out defaultDb);
19 }
20
21 var redisClientManagerConfig = new RedisClientManagerConfig
22 {
23 MaxReadPoolSize = 50,
24 MaxWritePoolSize = 50,
25 DefaultDb = defaultDb
26 };
27
28 // 創建 Redis 連接池
29 Manager = new PooledRedisClientManager(redisMasterHosts, redisSlaveHosts, redisClientManagerConfig)
30 {
31 PoolTimeout = 2000,
32 ConnectTimeout = 500
33 };
步驟4、通過PooledRedisClientManager的實例獲取Redis客戶端,然後就可以開始通過Redis客戶端的API進行操作。
五、其它
5.1、 Redis Key命名規範
Redis Key命名規範:AppID:KeyName。
可能有很多人習慣用英文狀態的點號來作為AppID和KeyName的分隔符,而筆者建議使用冒號作為AppID和KeyName的分隔符,其原因是:這麼寫會使Redis Key會以AppID作為分類顯示在Redis Desktop Manager中,方便你能夠快速查到要查閱的Redis Key對應的Redis Value值,請見下圖:
但如果使用英文狀態的點號來作為分隔符的話,那麼在Redis Desktop Manager中,Redis Key就不會被分類了,請見下圖:
5.2、常見應用問題
- 緩存穿透處理:什麼是緩存穿透?當根據Redis key在緩存中查詢後,不存在對應Value,就應該會在後端系統如DB中去查找,該Key的併發請求量一旦變大,那麼就會對DB造成很大的壓力。解決辦法有:a.前端風險控制,將惡意穿透情況排除在外;b.對查詢結果為空的情況依然進行緩存,但緩存時間會設置得很短,一般是幾分鐘。
- 緩存雪崩處理:什麼是緩存雪崩?當緩存伺服器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給後端系統(比如DB)帶來很大壓力。解決辦法有:後端連接數限制,錯誤閾值限制,超時處理,緩存失效時間均勻分佈,前端永不失效及後端主動更新。
- 緩存時長:策略定位複雜,需要多維度的計算。
- 緩存失效:按時失效,事件失效,後端主動更新。
- 緩存Key:Hash、規則、首碼+Hash,異常情況可人工干預。
- Lua腳本:服務端批量處理及事務能力,有條件邏輯的可擴展腳本。使用它的好處有:減少網路開銷、原子操作、可復用。
- Limit:可滑動時間視窗,如應用於Session,Memcached需每次傳Key和Value。
六、Demo 下載及更多資料
- RedisDemo下載地址:https://github.com/das2017/RedisDemo
- RedisDesktopManage下載地址:https://redisdesktop.com/
- Redis官網:https://redis.io/
- ServiceStack.Redis客戶端:https://github.com/ServiceStack/ServiceStack.Redis
- Redis命令大全:http://www.redis.cn/commands.html