一個技術汪的開源夢 —— 公共組件緩存之分散式緩存 Redis 實現篇

来源:http://www.cnblogs.com/wlitsoft/archive/2017/01/02/6242765.html
-Advertisement-
Play Games

Redis 安裝 & 配置 本測試環境將在 CentOS 7 x64 上安裝最新版本的 Redis。 1. 運行以下命令安裝 Redis 如果 CentOS 上提示 wget 命令未找到,則先安裝 net-tools。 yum install net-tools 2. Redis 配置文件 1)開啟 ...


Redis 安裝 & 配置

本測試環境將在 CentOS 7 x64 上安裝最新版本的 Redis。

1. 運行以下命令安裝 Redis

$ wget http://download.redis.io/releases/redis-3.2.6.tar.gz
$ tar xzf redis-3.2.6.tar.gz
$ cd redis-3.2.6
$ make install

如果 CentOS 上提示 wget 命令未找到,則先安裝 net-tools。

yum install net-tools

2. Redis 配置文件

1)開啟守護程式

    修改 daemonize 節點為 yes。

2)運行外部IP訪問

    配置 bind 節點為 0.0.0.0

 

本次示例只使用 Redis 的緩存 所以配置暫時只修改這兩處即可。

3. 設置 Redis 開機自動啟動

 1)在 Redis 的源碼包中找到 utils 目錄

 2) 將 redis_init_script 文件複製到 /etc/init.d 目錄下並重命名為 redisd

cp redis_init_script /etc/init.d/redisd

 3) 打開 redisd 修改部分配置。

 1 #!/bin/sh
 2 # chkconfig:    2345 90 10
 3 # Simple Redis init.d script conceived to work on Linux systems
 4 # as it does use of the /proc filesystem.
 5 
 6 REDISPORT=6379
 7 EXEC=/usr/local/bin/redis-server
 8 CLIEXEC=/usr/local/bin/redis-cli
 9 
10 PIDFILE=/var/run/redis_${REDISPORT}.pid
11 CONF="/etc/redis/redis_${REDISPORT}.conf"

其中第二行 # chkconfig: 2345 90 10 需要另行添加。

- REDISPORT Redis 運行埠號;

- EXEC Redis 伺服器命令文件路徑(根據實際情況修改);

- CLIEXEC Redis 客戶端命令文件路徑(亦根據實際情況修改);

- CONF Redis 配置文件。

 

4)設置開機啟動 & 啟動、停止服務

#設置為開機自啟動伺服器
chkconfig redisd on
#打開服務
service redisd start
#關閉服務
service redisd stop

 

主:如果外部機器還訪問不到 Redis 伺服器,請將 6379 埠號加防火牆例外即可。

 

代碼實現:

Common 包 介面定義 & 分散式緩存實例獲取和配置

- IDistributedCache 介面
 1 using System;
 2 
 3 namespace Wlitsoft.Framework.Common.Core
 4 {
 5     /// <summary>
 6     /// 分散式緩存介面。
 7     /// </summary>
 8     public interface IDistributedCache
 9     {
10         /// <summary>
11         /// 獲取緩存。
12         /// </summary>
13         /// <typeparam name="T">緩存類型。</typeparam>
14         /// <param name="key">緩存鍵值。</param>
15         /// <returns>獲取到的緩存。</returns>
16         T Get<T>(string key);
17 
18         /// <summary>
19         /// 設置緩存。
20         /// </summary>
21         /// <typeparam name="T">緩存類型。</typeparam>
22         /// <param name="key">緩存鍵值。</param>
23         /// <param name="value">要緩存的對象。</param>
24         void Set<T>(string key, T value);
25 
26         /// <summary>
27         /// 設置緩存。
28         /// </summary>
29         /// <typeparam name="T">緩存類型。</typeparam>
30         /// <param name="key">緩存鍵值。</param>
31         /// <param name="value">要緩存的對象。</param>
32         /// <param name="expiredTime">過期時間。</param>
33         void Set<T>(string key, T value, TimeSpan expiredTime);
34 
35         /// <summary>
36         /// 判斷指定鍵值的緩存是否存在。
37         /// </summary>
38         /// <param name="key">緩存鍵值。</param>
39         /// <returns>一個布爾值,表示緩存是否存在。</returns>
40         bool Exists(string key);
41 
42         /// <summary>
43         /// 移除指定鍵值的緩存。
44         /// </summary>
45         /// <param name="key">緩存鍵值。</param>
46         bool Remove(string key);
47 
48         /// <summary>
49         /// 獲取 Hash 表中的緩存。
50         /// </summary>
51         /// <typeparam name="T">緩存類型。</typeparam>
52         /// <param name="key">緩存鍵值。</param>
53         /// <param name="hashField">要獲取的 hash 欄位。</param>
54         /// <returns>獲取到的緩存。</returns>
55         T GetHash<T>(string key, string hashField);
56 
57         /// <summary>
58         /// 設置 緩存到 Hash 表。
59         /// </summary>
60         /// <typeparam name="T">緩存類型。</typeparam>
61         /// <param name="key">緩存鍵值。</param>
62         /// <param name="hashField">要設置的 hash 欄位。</param>
63         /// <param name="hashValue">要設置的 hash 值。</param>
64         void SetHash<T>(string key, string hashField, T hashValue);
65 
66         /// <summary>
67         /// 判斷指定鍵值的 Hash 緩存是否存在。
68         /// </summary>
69         /// <param name="key">緩存鍵值。</param>
70         /// <param name="hashField">hash 欄位。</param>
71         /// <returns>一個布爾值,表示緩存是否存在。</returns>
72         bool ExistsHash(string key, string hashField);
73 
74         /// <summary>
75         /// 刪除 hash 表中的指定欄位的緩存。
76         /// </summary>
77         /// <param name="key">緩存鍵值。</param>
78         /// <param name="hashField">hash 欄位。</param>
79         /// <returns>一個布爾值,表示緩存是否刪除成功。</returns>
80         bool DeleteHash(string key, string hashField);
81     }
82 }

 - App 類

1 /// <summary>
2 /// 獲取分散式緩存。
3 /// </summary>
4 public static IDistributedCache DistributedCache { get; internal set; }

 - AppBuilder 類

 1 namespace Wlitsoft.Framework.Common
 2 {
 3     /// <summary>
 4     /// 應用 構造。
 5     /// </summary>
 6     public class AppBuilder
 7     {
 8         #region 添加序列化者
 9 
10         /// <summary>
11         /// 添加序列化者。
12         /// </summary>
13         /// <param name="type">序列化類型。</param>
14         /// <param name="serializer">序列化者介面。</param>
15         public void AddSerializer(SerializeType type, ISerializer serializer)
16         {
17             #region 參數校驗
18 
19             if (serializer == null)
20                 throw new ObjectNullException(nameof(serializer));
21 
22             #endregion
23 
24             App.SerializerService.SetSerializer(type, serializer);
25         }
26 
27         #endregion
28 
29         #region 添加日誌記錄者
30 
31         /// <summary>
32         /// 添加日誌記錄者。
33         /// </summary>
34         /// <param name="name">日誌記錄者名稱。</param>
35         /// <param name="logger">日誌介面。</param>
36         public void AddLogger(string name, ILog logger)
37         {
38             #region 參數校驗
39 
40             if (string.IsNullOrEmpty(name))
41                 throw new StringNullOrEmptyException(nameof(name));
42 
43             if (logger == null)
44                 throw new ObjectNullException(nameof(logger));
45 
46             #endregion
47 
48             App.LoggerService.SetLogger(name, logger);
49         }
50 
51         #endregion
52 
53         #region 設置分散式緩存
54 
55         /// <summary>
56         /// 設置分散式緩存。
57         /// </summary>
58         /// <param name="cache">分散式緩存實例。</param>
59         /// <returns></returns>
60         public AppBuilder SetDistributedCache(IDistributedCache cache)
61         {
62             #region 參數校驗
63 
64             if (cache == null)
65                 throw new ObjectNullException(nameof(cache));
66 
67             #endregion
68 
69             App.DistributedCache = cache;
70             return this;
71         }
72 
73         #endregion
74     }
75 }

 

分散式緩存 Redis 實現

 - RedisCache 類

  1 using System;
  2 using System.Linq;
  3 using System.Threading;
  4 using StackExchange.Redis;
  5 using Wlitsoft.Framework.Common.Core;
  6 using Wlitsoft.Framework.Common.Extension;
  7 using Wlitsoft.Framework.Common.Exception;
  8 
  9 namespace Wlitsoft.Framework.Caching.Redis
 10 {
 11     /// <summary>
 12     /// Redis 緩存。
 13     /// </summary>
 14     public class RedisCache : IDistributedCache
 15     {
 16         #region 私有屬性
 17 
 18         //redis 連接實例。
 19         private volatile ConnectionMultiplexer _connection;
 20 
 21         //redis 緩存資料庫實例。
 22         private IDatabase _database;
 23 
 24         //連接實例鎖。
 25         private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(1, 1);
 26 
 27         //Redis 配置。
 28         internal static RedisCacheConfiguration RedisCacheConfiguration;
 29 
 30         #endregion
 31 
 32         #region IDistributedCache 成員
 33 
 34         /// <summary>
 35         /// 獲取緩存。
 36         /// </summary>
 37         /// <typeparam name="T">緩存類型。</typeparam>
 38         /// <param name="key">緩存鍵值。</param>
 39         /// <returns>獲取到的緩存。</returns>
 40         public T Get<T>(string key)
 41         {
 42             #region 參數校驗
 43 
 44             if (string.IsNullOrEmpty(key))
 45                 throw new StringNullOrEmptyException(nameof(key));
 46 
 47             #endregion
 48 
 49             this.Connect();
 50             string result = this._database.StringGet(key);
 51             if (string.IsNullOrEmpty(result))
 52                 return default(T);
 53             return result.ToJsonObject<T>();
 54         }
 55 
 56         /// <summary>
 57         /// 設置緩存。
 58         /// </summary>
 59         /// <typeparam name="T">緩存類型。</typeparam>
 60         /// <param name="key">緩存鍵值。</param>
 61         /// <param name="value">要緩存的對象。</param>
 62         public void Set<T>(string key, T value)
 63         {
 64             #region 參數校驗
 65 
 66             if (string.IsNullOrEmpty(key))
 67                 throw new StringNullOrEmptyException(nameof(key));
 68 
 69             if (value == null)
 70                 throw new ObjectNullException(nameof(value));
 71 
 72             #endregion
 73 
 74             this.Connect();
 75             this._database.StringSet(key, value.ToJsonString());
 76         }
 77 
 78         /// <summary>
 79         /// 設置緩存。
 80         /// </summary>
 81         /// <typeparam name="T">緩存類型。</typeparam>
 82         /// <param name="key">緩存鍵值。</param>
 83         /// <param name="value">要緩存的對象。</param>
 84         /// <param name="expiredTime">過期時間。</param>
 85         public void Set<T>(string key, T value, TimeSpan expiredTime)
 86         {
 87             #region 參數校驗
 88 
 89             if (string.IsNullOrEmpty(key))
 90                 throw new StringNullOrEmptyException(nameof(key));
 91 
 92             if (value == null)
 93                 throw new ObjectNullException(nameof(value));
 94 
 95             #endregion
 96 
 97             this.Connect();
 98             this._database.StringSet(key, value.ToJsonString(), expiredTime);
 99         }
100 
101         /// <summary>
102         /// 判斷指定鍵值的緩存是否存在。
103         /// </summary>
104         /// <param name="key">緩存鍵值。</param>
105         /// <returns>一個布爾值,表示緩存是否存在。</returns>
106         public bool Exists(string key)
107         {
108             #region 參數校驗
109 
110             if (string.IsNullOrEmpty(key))
111                 throw new StringNullOrEmptyException(nameof(key));
112 
113             #endregion
114 
115             this.Connect();
116             return this._database.KeyExists(key);
117         }
118 
119         /// <summary>
120         /// 移除指定鍵值的緩存。
121         /// </summary>
122         /// <param name="key">緩存鍵值。</param>
123         public bool Remove(string key)
124         {
125             #region 參數校驗
126 
127             if (string.IsNullOrEmpty(key))
128                 throw new StringNullOrEmptyException(nameof(key));
129 
130             #endregion
131 
132             this.Connect();
133             return this._database.KeyDelete(key);
134         }
135 
136         /// <summary>
137         /// 獲取 Hash 表中的緩存。
138         /// </summary>
139         /// <typeparam name="T">緩存類型。</typeparam>
140         /// <param name="key">緩存鍵值。</param>
141         /// <param name="hashField">要獲取的 hash 欄位。</param>
142         /// <returns>獲取到的緩存。</returns>
143         public T GetHash<T>(string key, string hashField)
144         {
145             #region 參數校驗
146 
147             if (string.IsNullOrEmpty(key))
148                 throw new StringNullOrEmptyException(nameof(key));
149 
150             if (string.IsNullOrEmpty(hashField))
151                 throw new StringNullOrEmptyException(nameof(hashField));
152 
153             #endregion
154 
155             this.Connect();
156             string value = this._database.HashGet(key, hashField);
157             if (string.IsNullOrEmpty(value))
158                 return default(T);
159             return value.ToJsonObject<T>();
160         }
161 
162         /// <summary>
163         /// 設置 緩存到 Hash 表。
164         /// </summary>
165         /// <typeparam name="T">緩存類型。</typeparam>
166         /// <param name="key">緩存鍵值。</param>
167         /// <param name="hashField">要設置的 hash 欄位。</param>
168         /// <param name="hashValue">要設置的 hash 值。</param>
169         public void SetHash<T>(string key, string hashField, T hashValue)
170         {
171             #region 參數校驗
172 
173             if (string.IsNullOrEmpty(key))
174                 throw new StringNullOrEmptyException(nameof(key));
175 
176             if (string.IsNullOrEmpty(hashField))
177                 throw new StringNullOrEmptyException(nameof(hashField));
178 
179             if (hashValue == null)
180                 throw new ObjectNullException(nameof(hashValue));
181 
182             #endregion
183 
184             this.Connect();
185             this._database.HashSet(key, hashField, hashValue.ToJsonString());
186         }
187 
188         /// <summary>
189         /// 判斷指定鍵值的 Hash 緩存是否存在。
190         /// </summary>
191         /// <param name="key">緩存鍵值。</param>
192         /// <param name="hashField">hash 欄位。</param>
193         /// <returns>一個布爾值,表示緩存是否存在。</returns>
194         public bool ExistsHash(string key, string hashField)
195         {
196             #region 參數校驗
197 
198             if (string.IsNullOrEmpty(key))
199                 throw new StringNullOrEmptyException(nameof(key));
200 
201             if (string.IsNullOrEmpty(hashField))
202                 throw new StringNullOrEmptyException(nameof(hashField));
203 
204             #endregion
205 
206             this.Connect();
207             return this._database.HashExists(key, hashField);
208         }
209 
210         /// <summary>
211         /// 刪除 hash 表中的指定欄位的緩存。
212         /// </summary>
213         /// <param name="key">緩存鍵值。</param>
214         /// <param name="hashField">hash 欄位。</param>
215         /// <returns>一個布爾值,表示緩存是否刪除成功。</returns>
216         public bool DeleteHash(string key, string hashField)
217         {
218             #region 參數校驗
219 
220             if (string.IsNullOrEmpty(key))
221                 throw new StringNullOrEmptyException(nameof(key));
222 
223             if (string.IsNullOrEmpty(hashField))
224                 throw new StringNullOrEmptyException(nameof(hashField));
225 
226             #endregion
227 
228             this.Connect();
229             return this._database.HashDelete(key, hashField);
230         }
231 
232         #endregion
233 
234         #region 私有方法
235 
236         /// <summary>
237         /// 連接。
238         /// </summary>
239         private void Connect()
240         {
241             if (this._connection != null)
242                 return;
243 
244             this._connectionLock.Wait();
245             try
246             {
247                 if (this._connection == null)
248                 {
249                     this._connection = ConnectionMultiplexer.Connect(this.GetConfigurationOptions());
250                     this._database = this._connection.GetDatabase();
251                 }
252             }
253             finally
254             {
255                 this._connectionLock.Release();
256             }
257         

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

-Advertisement-
Play Games
更多相關文章
  • 代碼: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace Common.Utils { /// <summary> /// ...
  • 前言 2017年就這麼悄無聲息的開始了,2017年對我來說又是特別重要的一年。 元旦放假在家寫了個Asp.net Core驗證碼登錄, 做demo的過程中遇到兩個小問題,第一是在Asp.net Core中引用dll,以往我們引用DLL都是直接引用,在Core里這樣是不行的,必須基於NuGet添加,或 ...
  • 本文向大家介紹瞭如何運用C#來創建、安裝、卸載、調試Windows Service程式。有需要的可以參考下,希望對大家有所幫助。 ...
  • 網上看到的很多winform窗體圓角設計代碼都比較累贅,這裡分享一個少量代碼就可以實現的圓角。主要運用了System.Drawing.Drawing2D。 效果圖 代碼如下。 代碼比較簡單,希望有所幫助。 ...
  • var: 初始化必須有賦值,var i;(錯的)。 var類型的對象運行過程中不允許再更改類型。(如:var i=1; i="hello!" 會出錯) var只聲明局部變數。 dynamic: 初始化時可以不賦值。 dynamic類型的對象運行過程中可以給該類型。(如:dynamic i=1; i=... ...
  • 阿裡雲直播SDK的坑 1、直播雲沒有單獨的SDK,直播部分被封裝在CDN的相關SDK當中。 2、針對SDK,沒有相關Demo。 3、針對SDK,沒有相關的文檔說明。 4、針對SDK的說明,官網上的說明與源碼裡面的說明完全不一致,初始化 與源代碼文檔中的 完全不一致。 5、針對SDK沒有封裝哪些是常用 ...
  • hello ...
  • 本文詳細介紹了C#製作簡易屏保的步驟,以及筆者在學習過程中的一些心得,有需要的可以參考下。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...