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. 通过脚本本地下载Jar包

    通过脚本本地下载Jar包 1.脚本 2.pom.xml 1.脚本 download.bat # !/bin/bash mvn -f pom.xml dependency:copy-dependenci ...

  2. jenkins 简介和简单操作

    持续集成:Continuous Intergration (CI) 持续交付:Continuous Delivery(CD) 持续部署:Continuous Deployment(CD) jenkin ...

  3. K8s client 使用

    使用的k8s client包: <dependency> <groupId>io.fabric8</groupId> <artifactId>kuber ...

  4. Cisco的互联网络操作系统IOS和安全设备管理器SDM__CDP

    1.CDP定时器和保持信息时间:通过show cdp 命令查看 show cdp neighbors命令提供下列信息:device ID(设备ID).local interface(本地接口).hol ...

  5. Flink-v1.12官方网站翻译-P028-Custom Serialization for Managed State

    管理状态的自定义序列化 本页面的目标是为需要使用自定义状态序列化的用户提供指导,涵盖了如何提供自定义状态序列化器,以及实现允许状态模式演化的序列化器的指南和最佳实践. 如果你只是简单地使用Flink自 ...

  6. MySQL 中的自增主键

    MySQL 的主键可以是自增的,那么如果在断电重启后新增的值还会延续断电前的自增值吗?自增值默认为1,那么可不可以改变呢?下面就说一下 MySQL 的自增值. 特点 保存策略 1.如果存储引擎是 My ...

  7. 【noi 2.6_2000】&【poj 2127】 最长公共子上升序列 (DP+打印路径)

    由于noi OJ上没有Special Judge,所以我是没有在这上面AC的.但是在POJ上A了. 题意如标题. 解法:f[i][j]表示a串前i个和b串前j个且包含b[j]的最长公共上升子序列长度 ...

  8. HDU 3336——Count the string

    It is well known that AekdyCoin is good at string problems as well as number theory problems. When g ...

  9. Codeforces Round #177 (Div. 2) B. Polo the Penguin and Matrix (贪心,数学)

    题意:给你一个\(n\)x\(m\)的矩阵,可以对矩阵的所有元素进行\(\pm d\),问能否使得所有元素相等. 题解:我们可以直接记录一个\(n*m\)的数组存入所有数,所以\((a_1+xd)=( ...

  10. PowerShell随笔1---背景

    既然是随笔,那就想到什么说什么,既会分享主题知识,也会分享一些其他技巧和个人学习方法,供交流. 我一般学习一个东西,我都会问几个问题: 这东西是什么? 这东西有什么用,为什么会出现,出现是为了解决什么 ...