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 } 258 259 private ConfigurationOptions GetConfigurationOptions() 260 { 261 #region 校驗 262 263 if (RedisCacheConfiguration == null) 264 throw new ObjectNullException(nameof(RedisCacheConfiguration)); 265 266 if (!RedisCacheConfiguration.HostAndPoints.Any()) 267 throw new Exception("RedisCahce 的 HostAndPoints 不能為空"); 268 269 #endregion 270 271 ConfigurationOptions options = new ConfigurationOptions(); 272 273 foreach (string item in RedisCacheConfiguration.HostAndPoints) 274 options.EndPoints.Add(item); 275 276 options.ConnectRetry = RedisCacheConfiguration.ConnectRetry; 277 options.ConnectTimeout = RedisCacheConfiguration.ConnectTimeout; 278 279 return options; 280 } 281 282 #endregion 283 284 #region 析構函數 285 286 /// <summary> 287 /// 析構 <see cref="RedisCache"/> 類型的對象。 288 /// </summary> 289 ~RedisCache() 290 { 291 _connection?.Close(); 292 } 293 294 #endregion 295 } 296 }