一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 Redis 实现篇
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 修改部分配置。
#!/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; //连接实例锁。 , ); //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 } }
一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 Redis 实现篇的更多相关文章
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之 Http 请求客户端
一个技术汪的开源梦 —— 目录 想必大家在项目开发的时候应该都在程序中调用过自己内部的接口或者使用过第三方提供的接口,咱今天不讨论 REST ,最常用的请求应该就是 GET 和 POST 了,那下面开 ...
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之序列化
一个技术汪的开源梦 —— 目录 想必大家在项目中都接触过 JSON 或者 XML 吧,为了将对象在网络上传输或者将其持久化必须将其序列化为一个字符串然后进行后续操作.常见的就是将其序列化成 JSON ...
- 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之目录结构
一个技术汪的开源梦 —— 目录 这篇文章是开源公共组件的开篇那就先说说项目的 Github 目录结构和 .Net Core 的项目结构. 1. GitHub 目录结构和相关文件 - src 源码项目目 ...
- 一个技术汪的开源梦 —— 基于 .Net Core 的组件 Nuget 包制作 &; 发布
一个技术汪的开源梦 —— 目录 微软的 ASP.Net Core 强化了 Nuget 的使用,所有的 .Net Core 组件均有 Nuget 管理,所以有必要探讨一下 .Net Core 组件制作 ...
- 一个技术汪的开源梦 —— 微信开发工具包(WeixinSDK)
由于春节的关系 WeixinSDK 这个开源项目的进展比预期推迟了大约一个月的时间,值得高兴的是到目前为止该项目的重要模块已经开发完毕. - 关于项目 该项目的背景是现在微信公众号.微信服务号乃至微 ...
- Net Core 的公共组件之 Http 请求客户端
Net Core 的公共组件之 Http 请求客户端 想必大家在项目开发的时候应该都在程序中调用过自己内部的接口或者使用过第三方提供的接口,咱今天不讨论 REST ,最常用的请求应该就是 GET 和 ...
- 开源Word读写组件DocX 的深入研究和问题总结
一. 前言 前两天看到了asxinyu大神的[原创]开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX. 我也把它融入到我的项目当中并进 ...
- Caf.CMS是一个免费的、 开源,功能齐全的CMS
Caf.CMS(疯狂蚂蚁CMS) 是一个免费的. 开源,功能全面的CMS(内容管理系统).定位CMS也有点狭义呢,因为Caf.CMS是基于国外SmartStore.NET 开源商城源码的基础上改造而成 ...
- dnc开源梦之队2018 开源项目精选集
dnc开源梦之队2018 dnc开源项目选择标准 dnc = .NET Core.dotnet core 1.支持dnc 2.x,Github star数量100以上,最近2月活跃更新 2.轻量级.示 ...
随机推荐
- MUI APP关于页面之间的传值,plusready和自定义事件
最近在用MUI开发这个APP,发现有时候这个plusready不起作用,表现在,这个页面如果重复打开,这个plusready就进不去,然后上一个页面传过来的值,就没法接收了.这个经过MUI官方确认,是 ...
- 调试D2JS
D2JS 最终加载运行于 nashorn 上,目前能调试 nashorn js 的 IDE 只有一款:NetBeans.eclipse 没有计划,神器号称支持 nashorn,对于简单类型可以观察,对 ...
- PHP对redis操作详解【转】
/*1.Connection*/ $redis = new Redis(); $redis->connect('127.0.0.1',6379,1);//短链接,本地host,端口为6379,超 ...
- Windows下安装scikit-learn
Windows下安装scikit-learn 准备工作 Python (>= 2.6 or >= 3.3), Numpy (>= 1.6.1) Scipy (>= 0.9), ...
- Jade之属性
属性 所有的html(5)标签在jade中均支持如下写法.jade中省去了html<>和标签的关闭等写法,并将属性写在括号之中.若存在多个属性,可以将其分为多行. jade: a(href ...
- 用Perl编写Apache模块续二 - SVN动态鉴权实现SVNAuth 禅道版
代码地址:https://code.csdn.net/x3dcn/svnauth 以禅道项目管理系统的数据库结构为标准,实现了可用的svn authz验证功能. 以用户名.密码.项目的acl开发程度o ...
- BZOJ3067 : Hyperdrome
设f[i][j]表示前i个字母中字母j出现的次数对2取模的结果. 若[l,r]经过重组可以形成回文串,则需满足f[l-1][j]与f[r][j]至多有1位不同. 将f[i]用一个long long表示 ...
- 2012 #3 Arcane Numbers
Arcane Numbers 1 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Su ...
- PPPOE拨号演练
搭建PPPOE服务器,拓扑如下 PPP-Server配置如下: (config)#bba-group pppoe global (config-bba-group)#virtual-template ...
- Windows Phone 动态改变ListBox样式
使用ListBox时通常会借助ItemTemplate帮助我们实现更复杂多样的样式显示,体现了Xaml的灵活.如何动态改变变ListBox的样式,实现类似电脑资源管理器中列表显示和图标显示形式的替换. ...