• 一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 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 修改部分配置。

     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 }
  • 相关阅读:
    第十二章,结束练习
    第十一章,表单
    第十章,表格练习
    第九章,跨行跨列的表格
    第八章,表格
    第七章,列表
    第六章,body当中的属性
    第五章,标签的使用
    6. C# 命名规则
    5. c#变量
  • 原文地址:https://www.cnblogs.com/wlitsoft/p/6242765.html
Copyright © 2020-2023  润新知