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 }