您的位置:首页 > 数据库 > Redis

一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 Redis 实现篇

2017-01-02 17:25 701 查看
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;

//连接实例锁。
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
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐