一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 Redis 实现篇
2017-01-02 17:25
701 查看
Redis 安装 & 配置
本测试环境将在 CentOS 7 x64 上安装最新版本的 Redis。
1. 运行以下命令安装 Redis
如果 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
3) 打开 redisd 修改部分配置。
其中第二行 # chkconfig: 2345 90 10 需要另行添加。
- REDISPORT Redis 运行端口号;
- EXEC Redis 服务器命令文件路径(根据实际情况修改);
- CLIEXEC Redis 客户端命令文件路径(亦根据实际情况修改);
- CONF Redis 配置文件。
4)设置开机启动 & 启动、停止服务
主:如果外部机器还访问不到 Redis 服务器,请将 6379 端口号加防火墙例外即可。
代码实现:
Common 包 接口定义 & 分布式缓存实例获取和配置
- App 类
- AppBuilder 类
分布式缓存 Redis 实现
- RedisCache 类
本测试环境将在 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 修改部分配置。
#!/bin/sh # chkconfig: 2345 90 10 # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. REDISPORT=6379 EXEC=/usr/local/bin/redis-server CLIEXEC=/usr/local/bin/redis-cli PIDFILE=/var/run/redis_${REDISPORT}.pid 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 接口
using System; namespace Wlitsoft.Framework.Common.Core { /// <summary> /// 分布式缓存接口。 /// </summary> public interface IDistributedCache { /// <summary> /// 获取缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <returns>获取到的缓存。</returns> T Get<T>(string key); /// <summary> /// 设置缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="value">要缓存的对象。</param> void Set<T>(string key, T value); /// <summary> /// 设置缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="value">要缓存的对象。</param> /// <param name="expiredTime">过期时间。</param> void Set<T>(string key, T value, TimeSpan expiredTime); /// <summary> /// 判断指定键值的缓存是否存在。 /// </summary> /// <param name="key">缓存键值。</param> /// <returns>一个布尔值,表示缓存是否存在。</returns> bool Exists(string key); /// <summary> /// 移除指定键值的缓存。 /// </summary> /// <param name="key">缓存键值。</param> bool Remove(string key); /// <summary> /// 获取 Hash 表中的缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="hashField">要获取的 hash 字段。</param> /// <returns>获取到的缓存。</returns> T GetHash<T>(string key, string hashField); /// <summary> /// 设置 缓存到 Hash 表。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="hashField">要设置的 hash 字段。</param> /// <param name="hashValue">要设置的 hash 值。</param> void SetHash<T>(string key, string hashField, T hashValue); /// <summary> /// 判断指定键值的 Hash 缓存是否存在。 /// </summary> /// <param name="key">缓存键值。</param> /// <param name="hashField">hash 字段。</param> /// <returns>一个布尔值,表示缓存是否存在。</returns> bool ExistsHash(string key, string hashField); /// <summary> /// 删除 hash 表中的指定字段的缓存。 /// </summary> /// <param name="key">缓存键值。</param> /// <param name="hashField">hash 字段。</param> /// <returns>一个布尔值,表示缓存是否删除成功。</returns> bool DeleteHash(string key, string hashField); } }
- App 类
/// <summary> /// 获取分布式缓存。 /// </summary> public static IDistributedCache DistributedCache { get; internal set; }
- AppBuilder 类
namespace Wlitsoft.Framework.Common { /// <summary> /// 应用 构造。 /// </summary> public class AppBuilder { #region 添加序列化者 /// <summary> /// 添加序列化者。 /// </summary> /// <param name="type">序列化类型。</param> /// <param name="serializer">序列化者接口。</param> public void AddSerializer(SerializeType type, ISerializer serializer) { #region 参数校验 if (serializer == null) throw new ObjectNullException(nameof(serializer)); #endregion App.SerializerService.SetSerializer(type, serializer); } #endregion #region 添加日志记录者 /// <summary> /// 添加日志记录者。 /// </summary> /// <param name="name">日志记录者名称。</param> /// <param name="logger">日志接口。</param> public void AddLogger(string name, ILog logger) { #region 参数校验 if (string.IsNullOrEmpty(name)) throw new StringNullOrEmptyException(nameof(name)); if (logger == null) throw new ObjectNullException(nameof(logger)); #endregion App.LoggerService.SetLogger(name, logger); } #endregion #region 设置分布式缓存 /// <summary> /// 设置分布式缓存。 /// </summary> /// <param name="cache">分布式缓存实例。</param> /// <returns></returns> public AppBuilder SetDistributedCache(IDistributedCache cache) { #region 参数校验 if (cache == null) throw new ObjectNullException(nameof(cache)); #endregion App.DistributedCache = cache; return this; } #endregion } }
分布式缓存 Redis 实现
- RedisCache 类
using System; using System.Linq; using System.Threading; using StackExchange.Redis; using Wlitsoft.Framework.Common.Core; using Wlitsoft.Framework.Common.Extension; using Wlitsoft.Framework.Common.Exception; namespace Wlitsoft.Framework.Caching.Redis { /// <summary> /// Redis 缓存。 /// </summary> public class RedisCache : IDistributedCache { #region 私有属性 //redis 连接实例。 private volatile ConnectionMultiplexer _connection; //redis 缓存数据库实例。 private IDatabase _database; //连接实例锁。 private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(1, 1); //Redis 配置。 internal static RedisCacheConfiguration RedisCacheConfiguration; #endregion #region IDistributedCache 成员 /// <summary> /// 获取缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <returns>获取到的缓存。</returns> public T Get<T>(string key) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); #endregion this.Connect(); string result = this._database.StringGet(key); if (string.IsNullOrEmpty(result)) return default(T); return result.ToJsonObject<T>(); } /// <summary> /// 设置缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="value">要缓存的对象。</param> public void Set<T>(string key, T value) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (value == null) throw new ObjectNullException(nameof(value)); #endregion this.Connect(); this._database.StringSet(key, value.ToJsonString()); } /// <summary> /// 设置缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="value">要缓存的对象。</param> /// <param name="expiredTime">过期时间。</param> public void Set<T>(string key, T value, TimeSpan expiredTime) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (value == null) throw new ObjectNullException(nameof(value)); #endregion this.Connect(); this._database.StringSet(key, value.ToJsonString(), expiredTime); } /// <summary> /// 判断指定键值的缓存是否存在。 /// </summary> /// <param name="key">缓存键值。</param> /// <returns>一个布尔值,表示缓存是否存在。</returns> public bool Exists(string key) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); #endregion this.Connect(); return this._database.KeyExists(key); } /// <summary> /// 移除指定键值的缓存。 /// </summary> /// <param name="key">缓存键值。</param> public bool Remove(string key) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); #endregion this.Connect(); return this._database.KeyDelete(key); } /// <summary> /// 获取 Hash 表中的缓存。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="hashField">要获取的 hash 字段。</param> /// <returns>获取到的缓存。</returns> public T GetHash<T>(string key, string hashField) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (string.IsNullOrEmpty(hashField)) throw new StringNullOrEmptyException(nameof(hashField)); #endregion this.Connect(); string value = this._database.HashGet(key, hashField); if (string.IsNullOrEmpty(value)) return default(T); return value.ToJsonObject<T>(); } /// <summary> /// 设置 缓存到 Hash 表。 /// </summary> /// <typeparam name="T">缓存类型。</typeparam> /// <param name="key">缓存键值。</param> /// <param name="hashField">要设置的 hash 字段。</param> /// <param name="hashValue">要设置的 hash 值。</param> public void SetHash<T>(string key, string hashField, T hashValue) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (string.IsNullOrEmpty(hashField)) throw new StringNullOrEmptyException(nameof(hashField)); if (hashValue == null) throw new ObjectNullException(nameof(hashValue)); #endregion this.Connect(); this._database.HashSet(key, hashField, hashValue.ToJsonString()); } /// <summary> /// 判断指定键值的 Hash 缓存是否存在。 /// </summary> /// <param name="key">缓存键值。</param> /// <param name="hashField">hash 字段。</param> /// <returns>一个布尔值,表示缓存是否存在。</returns> public bool ExistsHash(string key, string hashField) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (string.IsNullOrEmpty(hashField)) throw new StringNullOrEmptyException(nameof(hashField)); #endregion this.Connect(); return this._database.HashExists(key, hashField); } /// <summary> /// 删除 hash 表中的指定字段的缓存。 /// </summary> /// <param name="key">缓存键值。</param> /// <param name="hashField">hash 字段。</param> /// <returns>一个布尔值,表示缓存是否删除成功。</returns> public bool DeleteHash(string key, string hashField) { #region 参数校验 if (string.IsNullOrEmpty(key)) throw new StringNullOrEmptyException(nameof(key)); if (string.IsNullOrEmpty(hashField)) throw new StringNullOrEmptyException(nameof(hashField)); #endregion this.Connect(); return this._database.HashDelete(key, hashField); } #endregion #region 私有方法 /// <summary> /// 连接。 /// </summary> private void Connect() { if (this._connection != null) return; this._connectionLock.Wait(); try { if (this._connection == null) { this._connection = ConnectionMultiplexer.Connect(this.GetConfigurationOptions()); this._database = this._connection.GetDatabase(); } } finally { this._connectionLock.Release(); } } private ConfigurationOptions GetConfigurationOptions() { #region 校验 if (RedisCacheConfiguration == null) throw new ObjectNullException(nameof(RedisCacheConfiguration)); if (!RedisCacheConfiguration.HostAndPoints.Any()) throw new Exception("RedisCahce 的 HostAndPoints 不能为空"); #endregion ConfigurationOptions options = new ConfigurationOptions(); foreach (string item in RedisCacheConfiguration.HostAndPoints) options.EndPoints.Add(item); options.ConnectRetry = RedisCacheConfiguration.ConnectRetry; options.ConnectTimeout = RedisCacheConfiguration.ConnectTimeout; return options; } #endregion #region 析构函数 /// <summary> /// 析构 <see cref="RedisCache"/> 类型的对象。 /// </summary> ~RedisCache() { _connection?.Close(); } #endregion } }
相关文章推荐
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之序列化
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之目录结构
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之 Http 请求客户端
- Jboot集成Redis来实现缓存技术方案
- 12、Spring技术栈-Redis Sentinel实现高可用缓存集群方案实战
- SpringBoot集成Redis来实现缓存技术方案
- 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)
- 怎样使用ListView实现一个带有网络请求,解析,分页,缓存的公共的List页面来大大的提高工作效率
- 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)
- 分布式缓存技术redis学习系列(五)——spring-data-redis与JedisPool的区别、使用ShardedJedisPool与spring集成的实现及一致性哈希分析
- 11、Spring技术栈-整合Redis,通过Redis的Master-Slave实现缓存数据读写分离
- 用java5读写技术实现一个伪缓存技术
- 哪种缓存效果高?开源一个简单的缓存组件j2cache
- 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)
- 分布式缓存技术redis学习系列(五)——spring-data-redis与JedisPool的区别、使用ShardedJedisPool与spring集成的实现及一致性哈希分析
- SpringBoot集成Redis来实现缓存技术方案
- 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)
- 一个技术汪的开源梦 —— 基于 .Net Core 的组件 Nuget 包制作 & 发布
- 【分布式缓存】——-基于redis分布式缓存的实现
- 10、Spring技术栈-整合Redis,使用RedisTemplate实现数据缓存实战