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. Java Web学习之路

    编程基础 1-1 常用数据结构 数组.链表.堆.栈.队列.Hash表.二叉树等1-2 算法思想 算法时间复杂度和空间复杂度的分析计算 1-2 算法思想:递推.递归.穷举.贪心.分治.动态规划.迭代.分 ...

  2. (15)Linux命令基本格式

    1.命令提示符 登录系统后,第一眼看到的内容是: [root@localhost ~]# 这就是 Linux 系统的命令提示符.那么,这个提示符的含义是什么呢? []:这是提示符的分隔符号,没有特殊含 ...

  3. JMeter多个请求按照比例并发的几种方式

    一.需求 在压测的过程中,为了能够压测整个链路,通常需要多个接口进行并发, 每个接口的请求比例不尽相同. 比如此时此刻,我在写博客,很多人在浏览博客,或者点赞.评论博客等等等,这些行为占比是不同的. ...

  4. C语言实现2048小游戏

    目录 2048 一.设计思路 1.游戏规则 2.思路 二.代码实现 1.存储结构 2.初始化游戏数据 3.向左合并 4.其他方向合并 5.产生新的方块 6.源代码 7.实例演示 三.问题 2048 一 ...

  5. 从微信小程序到鸿蒙js开发【05】——tabs组件&每日新闻

    目录: 1.tabs, tab-bar, tab-content 2.tabs的事件处理 3.tabs实现的每日新闻 1.tabs, tab-bar, tab-content 上章说到,鸿蒙的list ...

  6. Maven三种打包方式jar war pom

    1.pom工程 用在父级工程或聚合工程中.用来做jar包的版本控制.必须指明这个聚合工程的打包方式为pom 2.war工程 将会打包成war,发布在服务器上的工程.如网站或服务.在SpringBoot ...

  7. Codeforces Round #658 (Div. 2) D. Unmerge(dp)

    题目链接:https://codeforces.com/contest/1382/problem/D 题意 给出一个大小为 $2n$ 的排列,判断能否找到两个长为 $n$ 的子序列,使得二者归并排序后 ...

  8. Codeforces Round #657 (Div. 2) B. Dubious Cyrpto(数论)

    题目链接:https://codeforces.com/contest/1379/problem/B 题意 给出三个正整数 $l,r,m$,判断在区间 $[l,r]$ 内是否有 $a,b,c$ 满足存 ...

  9. Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) D. Navigation System(有向图,BFS,最短路)

    题意: n 点 m 边有向图,给出行走路径,求行走途中到路径终点最短路变化次数的最小值和最大值 . 思路 : 逆向广搜,正向模拟. #include <bits/stdc++.h> usi ...

  10. codeforces 86D D. Powerful array

    An array of positive integers a1, a2, ..., an is given. Let us consider its arbitrary subarray al, a ...