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. Spark 将DataFrame所有的列类型改为double

    Spark 将DataFrame所有的列类型改为double 1.单列转化方法 2.循环转变 3.通过:_* 1.单列转化方法 import org.apache.spark.sql.types._ ...

  2. HttpURLConnection下载文件流

    package com.loan.modules; import sun.net.www.protocol.file.Handler; import java.io.*; import java.ne ...

  3. Kubernetes --(k8s) service

    service Kubernete Service 是一个定义了一组Pod的策略的抽象,我们也有时候叫做宏观服务.这些被服务标记的Pod都是(一般)通过label Selector决定的 对于Kube ...

  4. 从官方文档中探索MySQL分页的几种方式及分页优化

    概览 相比于Oracle,SQL Server 等数据库,MySQL分页的方式简单得多了,官方自带了分页语法 limit 语句: select * from test_t LIMIT {[offset ...

  5. jvm学习第二天

    0.垃圾回收概述 1.什么是垃圾,怎么判断? 1.1引用计数法 含义 顾名思义,此种算法会在每一个对象上记录这个对象被引用的次数,只要有任何一个对象引用了此对象,这个对象的计数器就+1,取消对这个对象 ...

  6. ASP.NET Core默认容器实现Controller的属性注入

    仅针对Controller的属性注入: 使用默认容器,不依赖第三方库: 故事背景   闲来无事给项目做优化,发现大多数Controller里面都会用到Logger和AutoMapper,每个Contr ...

  7. shell编程基础一

    1.定义变量 a=1 shell定义变量要注意等号前后不能有空格,不然会报错,请严格按照格式编写. 2.打印输出 echo 1 使用echo打印,后面留一个空格. 3.shell中通过 ${变量名} ...

  8. Codeforces Round #594 (Div. 2) D1 - The World Is Just a Programming Task

    思路:枚举换的位置i,j 然后我们要先判断改序列能否完全匹配 如果可以 那我们就需要把差值最大的位置换过来 然后直接判断就行

  9. 【洛谷 p3366】模板-最小生成树(图论)

    题目:给出一个无向图,求出最小生成树,如果该图不连通,则输出orz. 解法:Kruskal求MST. 1 #include<cstdio> 2 #include<cstdlib> ...

  10. CodeForces 630Q Pyramids(数学公式)

    IT City administration has no rest because of the fame of the Pyramids in Egypt. There is a project ...