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. (五)整合 Swagger2 ,构建接口管理界面

    整合 Swagger2 ,构建接口管理界面 1.Swagger2简介 1.1 Swagger2优点 1.2 Swagger2常用注解 2.SpringBoot整合Swagger2 2.1 Swagee ...

  2. 深入理解nodejs的HTTP处理流程

    目录 简介 使用nodejs创建HTTP服务 解构request 处理Request Body 处理异常 解构response 简介 我们已经知道如何使用nodejs搭建一个HTTP服务,今天我们会详 ...

  3. Git轻松入门3:远程仓库篇

    在第一讲中,我们有介绍过:Git是分布式版本控制系统.每个人的电脑上都有一份完整的版本库.当对项目作出了修改后,只要把修改推送给对方即可.但很有可能的情况是:两台电脑不在一个局域网内,无法互相访问:或 ...

  4. c++bind函数使用

    总述     最近写代码的时候看到代码使用了bind,一个参数绑定的标准库函数.程序是这么写的, speaker_play_routine_ = new boost::thread (boost::b ...

  5. C - C(换钱问题)

    换钱问题: 给出n种钱,m个站点,现在有第 s种钱,身上有v 这么多: 下面 m行 站点有a,b两种钱,rab a->b的汇率,cab a-->b的手续费, 相反rba cba :  问在 ...

  6. poj2778 DNA Sequence(AC自动机+矩阵快速幂)

    Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's ve ...

  7. Fiddler+雷电模拟器进行APP抓包

    1.下载最新版Fiddler,强烈建议在官网下载:https://www.telerik.com/download/fiddler 2. 正常傻瓜式安装,下一步,下一步,安装完毕后,先不用急于打开软件 ...

  8. Codeforces Round #643 (Div. 2) E. Restorer Distance (贪心,三分)

    题意:给你\(n\)个数,每次可以使某个数++,--,或使某个数--另一个++,分别消耗\(a,r,m\).求使所有数相同最少的消耗. 题解:因为答案不是单调的,所以不能二分,但不难发现,答案只有一个 ...

  9. .NET 5学习笔记(10)——Entity Framework Core之切换SQLServer和SQLite

    上一篇我们梳理了CodeFist的一般流程,本篇我们讨论如何在一套代码中,支持SQL Server和SQLite的切换.同时从本篇开始,我们从.NET Core 3.1 迁移到.NET 5.相信.NE ...

  10. Nginx location相关配置说明

    Nginx location相关配置说明       基于不同的IP.不同的端口以及不用得域名实现不同的虚拟主机,依赖于核心模块ngx_http_core_module实现. 新建PC web站点 [ ...