0.介绍

.NET Core or .NET Framework 4.0+ client for Redis and Redis Sentinel (2.8) and Cluster. Includes both synchronous and asynchronous clients.

本文记录CSRedis在开发过程中的简单使用,可以直接调试样例源码。

1. 参考资料

github https://github.com/2881099/csredis

作者博客 https://www.cnblogs.com/kellynic/p/9952386.html

Redis Runoob教程 https://www.runoob.com/redis/redis-install.html

2.核心内容

  • 使用心得

1.科学使用缓存

  • 从Redis中读取数据

从Redis中读取数据需要考虑"数据存在,但是Redis中过期或者未写入的情况"这时候就需要根据指定Key先获取数据再写入Redis中。

  • 将数据写入Redis

写入Redis需要增加过期时。增加过期时间的时候可以将时间随机,这样可以避免缓存在相同时间过期而引发缓存雪崩。

在高并发的情况下,如果根据key获取的数据不存在,也将null保存至Redis中,而非抽象类(AbstractRedisService)中做删除动作,这样可避免缓存穿透。

我对高并发场景下的缓存使用理解不深,AbstractRedisService抽象类在更新失效值的时候使用了lock,使用lock写法容易造成堵塞,但是如果不使用lock的话,就会出现重复读取再写入Redis的情况,并且在当前情况下如何处理缓存击穿也不是很清楚,希望大家能不吝赐教~

2.在使用CSRedis的时候遇到了多个业务模块都有相识的代码,于是抽取了抽象类AbstractRedisService,在业务模块实现的时候只需要实现RedisGroup 属性与GetKeyByRedisInputKey、GetValueByKey两个方法。

3.在实际应用中,有可能会出现程序与Redis服务连接不稳定的情况,如果Redis服务没有发现问题的话,可以尝试使用下面三种方式解决(参考 https://github.com/2881099/csredis/issues)

  • connectTimeout=30000 设置连接超时时间

  • tryit=3 设置重试次数

  • preheat=100 预热连接数

  • 初始化RedisHelper


// 初始化RedisHelper
RedisHelper.Initialization(CSRedisInstance.GetRedis()); /// <summary>
/// CSRedisClient 单例
/// </summary>
internal class CSRedisInstance
{
private static readonly object _lock = new object();
private static CSRedisClient _csRedis = null; private const string ip = "127.0.0.1";
private const string port = "6379";
private const string preheat = "100"; // 设置预热连接数
private const string connectTimeout = "100"; // 设置连接超时时间
private const string tryit = "1"; // 设置重试次数
private const string prefix = "CSRedisTest."; // 设置前缀
private static readonly string _connectString = $"{ip}:{port}," +
$"preheat={preheat},connectTimeout={connectTimeout},tryit={tryit},prefix={prefix}"; internal static CSRedisClient GetRedis()
{
if (_csRedis == null)
{
lock (_lock)
{
if (_csRedis == null)
{
_csRedis = GetCSRedisClient();
}
}
} return _csRedis;
} private static CSRedisClient GetCSRedisClient()
{
return new CSRedisClient(_connectString);
}
}
  • 业务应用 - 抽象类分享

AbstractRedisService抽象类

/// <summary>
/// Redis抽象类 - 缓存内容根据Key指定刷新
/// </summary>
/// <typeparam name="RedisInputKey">输入Key值</typeparam>
/// <typeparam name="RedisValue">Redis保存的Value值</typeparam>
public abstract class AbstractRedisService<RedisInputKey, RedisValue>
{
private readonly static object _lock = new object();
private const int _expireTime = 3600; /// <summary>
/// 缓存模块
/// </summary>
protected abstract RedisGroup CacheGroup { get; } /// <summary>
/// 根据输入Key值,返回真正RedisKey
/// </summary>
protected abstract string GetKeyByRedisInputKey(RedisInputKey redisInputKey); /// <summary>
/// 根据输入Key值,获取对应Value
/// </summary>
protected abstract RedisValue GetValueByKey(RedisInputKey redisInputKey); public RedisValue GetRedisByRedisInputKey(RedisInputKey redisInputKey)
{
if (!RedisControl.UseRedis())
return default(RedisValue); var result = GetRedisValue(redisInputKey);
// 刷新Redis之后还无法获取正确的值,则记录原因
if (result == null)
{
// 日志输出
}; return result;
} public void NoticeRedisUpdateByKey(RedisInputKey redisInputKey)
{
try
{
UpdateByKey(redisInputKey);
}
catch (Exception e)
{
// 日志输出
}
} /// <summary>
/// 有可能没有Redis服务,则将异常捕捉,并停止使用Redis缓存
/// </summary>
private RedisValue GetRedisValue(RedisInputKey redisInputKey)
{
RedisValue value = default(RedisValue);
string key = GetKeyByRedisInputKey(redisInputKey);
try
{
value = GetRedisValueByKey(key);
if (value != null)
return value; lock (_lock)
{
value = GetRedisValueByKey(key);
if (value == null)
UpdateByKey(redisInputKey);
} value = GetRedisValueByKey(key);
}
catch (Exception e)
{
RedisControl.StopUseRedis();
// 日志输出
} return value;
} private void UpdateByKey(RedisInputKey redisInputKey)
{
var key = GetKeyByRedisInputKey(redisInputKey);
RedisValue value = GetValueByKey(redisInputKey); if (value == null) //删除操作执行更新时,移除掉key
RedisHelper.Del(key);
else
RedisHelper.Set(key, value, _expireTime + 200 * new Random().Next(1, 10));
} private RedisValue GetRedisValueByKey(string key)
{
return RedisHelper.Get<RedisValue>(key);
}
}
1.StudentRedisService实现类
    /// <summary>
/// Redis Student实现类
/// </summary>
public class StudentRedisService : AbstractRedisService<string, Student>,IStudentRedisService
{
protected override RedisGroup CacheGroup => RedisGroup.Student; protected override string GetKeyByRedisInputKey(string redisInputKey) => redisInputKey; protected override Student GetValueByKey(string redisInputKey)
{
return Test.AllStudents.Where(v=>v.Name == redisInputKey).FirstOrDefault();
}
}
2.使用StudentRedisService


private static void AbstractRedisServiceTest()
{
var studentRedisService = new StudentRedisService(); // 一:通过key获取
var mark = studentRedisService.GetRedisByRedisInputKey("Mark"); // 有此数据,获取的时候会写入Redis
var linda = studentRedisService.GetRedisByRedisInputKey("Linda"); // 无数据则返回null // 二:数据变更通知
string markName = "Mark";
// 更新数据
int random = new Random().Next();
Test.AllStudents.Where(v => v.Name == markName).First().Age = random; var mark2 = studentRedisService.GetRedisByRedisInputKey(markName); // 旧值
studentRedisService.NoticeRedisUpdateByKey(markName);// 更新Redis
mark2 = studentRedisService.GetRedisByRedisInputKey(markName);// 新值
}

3.样例源码地址

调试Demo可以先参考Redis Runoob安装教程,部署Redis服务,再进行调试

https://github.com/Impartsoft/Bins/tree/main/CSRedisDemo/CSRedisDemo

.net使用CSRedis操作Redis缓存的简单笔记(新手教程)的更多相关文章

  1. python操作Redis缓存

    python操作Redis缓存 https://www.cnblogs.com/guotianbao/p/8683037.html 学习资料:电子书资源 联系邮箱:gmu1592618@gmail.c ...

  2. 第三百零一节,python操作redis缓存-管道、发布订阅

    python操作redis缓存-管道.发布订阅 一.管道 redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pi ...

  3. 第三百节,python操作redis缓存-其他常用操作,用于操作redis里的数据name,不论什么数据类型

    python操作redis缓存-其他常用操作,用于操作redis里的数据name,不论什么数据类型 delete(*names)根据删除redis中的任意数据类型 #!/usr/bin/env pyt ...

  4. 第二百九十九节,python操作redis缓存-SortSet有序集合类型,可以理解为有序列表

    python操作redis缓存-SortSet有序集合类型,可以理解为有序列表 有序集合,在集合的基础上,为每元素排序:元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值, ...

  5. 第二百九十八节,python操作redis缓存-Set集合类型,可以理解为不能有重复元素的列表

    python操作redis缓存-Set集合类型,可以理解为不能有重复元素的列表 sadd(name,values)name对应的集合中添加元素 #!/usr/bin/env python # -*- ...

  6. 第二百九十七节,python操作redis缓存-List类型,可以理解为列表

    python操作redis缓存-List类型,可以理解为列表,是可以有重复元素的列表 List操作,redis中的List在在内存中按照一个name对应一个List来存储.如图: lpush(name ...

  7. 第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型

    第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型 Hash操作,redis中Hash在内存中的存储格式如下图: hset(name, key, value)name ...

  8. 第二百九十五节,python操作redis缓存-字符串类型

    python操作redis缓存-字符串类型 首先要安装redis-py模块 python连接redis方式,有两种连接方式,一种是直接连接,一张是通过连接池连接 注意:以后我们都用的连接池方式连接,直 ...

  9. redis—Spring中redis缓存的简单使用

    这里使用的是 Spring-4.3 , redis-2.8 的版本   1.添加maven依赖 <dependency> <groupId>redis.clients</ ...

随机推荐

  1. ACCESS数据库偏移注入

    偏移注入主要是针对知道表,但是不知道字段的ACCESS数据库. 比如我们已经知道了表名是 admin 判断字段数: http://192.168.74.136:8002/Production/PROD ...

  2. Lambda表达式及相关练习

    语法格式一无参数无返回值 语法格式二有一个参数并且无返回值 语法格式三若只有一个参数小括号可以省略不写 语法格式四有两个以上的参数有返回值并且Lambda体中有多条语句 语法格式五若Lambda体中只 ...

  3. windows下使用HyperV安装Centos7虚拟机

    以前都是用的VM(VMWare)安装虚拟机, 然鹅, 现在电脑装了Docker需要开启Windows的HyperV, 而我使用的VM版本(14)和HyperV 是不兼容的, 于是搜索引擎搜索了一下解决 ...

  4. AC自动机(转载)

    ac自动机学习博客 本来以为是很高级的算法 其实理解以后并不难 只是在字典树的基础上用fail数组标记一下回朔的位置 加速查找 就可以实现多模式串的匹配查找 模版如下: #include<cst ...

  5. hdu3635 Dragon Balls

    Problem Description Five hundred years later, the number of dragon balls will increase unexpectedly, ...

  6. zoj3471 Most Powerful

    Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These ato ...

  7. Pyqt5 安装

    window 安装PyQt5 pip install pyqt5 pip install pyqt5-tools  (安装常用的Qt工具) 添加环境变量 变量名: QT_QPA_PLATFORM_PL ...

  8. NLP论文阅读一:Paper阅读方法

    参考:https://pan.baidu.com/s/1MfcmXKopna3aLZHkD3iL3w 一.为什么要读论文? 基础技术:读论文中的related works可以帮助了解该领域的一些主要的 ...

  9. Redis Cluster 分布式集群(下)

    Redis Cluster 搭建(工具) 环境准备 节点 IP 端口 节点① 172.16.1.121 6379,6380 节点② 172.16.1.122 6379,6380 节点③ 172.16. ...

  10. 【非原创】LightOJ - 1284 Lights inside 3D Grid【概率期望】

    学习博客: 戳这里 戳这里 戳这里 戳这里 题意: 在一个三维的空间,每个点都有一盏灯,开始全是关的, 现在每次随机选两个点,把两个点之间的全部点,开关都按一遍:问k次过后开着的灯的期望数量: 题解: ...