DotNetCore三大Redis客户端对比和使用心得

前言

稍微复杂一点的互联网项目,技术选型都会涉及Redis,.NetCore的生态越发完善,支持.NetCore的Redis客户端越来越多,

下面三款常见的Redis客户端,相信大家平时或多或少用到一些,结合三款客户端的使用经历,有些心得体会。

先比较宏观的背景:

使用心得

三款客户端Redis支持的连接字符串配置基本相同

  "connectionstrings": {"redis": "localhost:6379,password=abcdef,connectTimeout=5000,writeBuffer=40960"}
1. StackExchange.Redis

定位是高性能、通用的Redis .Net客户端;方便地应用Redis全功能;支持Redis Cluster

  • 高性能的核心在于:多路复用连接(允许有效使用来自多个调用线程的共享连接), 服务器端操作使用ConnectionMultiplexer类

ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:6379,server2:6379");
// 日常应用的核心类库是IDatabase
IDatabase db = redis.GetDatabase();// 支持Pub/Sub
ISubscriber sub = redis.GetSubscriber();
sub.Subscribe("messages", (channel, message) => {Console.WriteLine((string)message);
});
---
sub.Publish("messages", "hello");

也正是因为多路复用,StackExchange.Redis唯一不支持的Redis特性是 "blocking pops",这个特性是RedisMQ的关键理论。如果你需要blocking pops, StackExchange.Redis官方推荐使用pub/sub模型模拟实现。

  • 日常操作API请关注IDatabase接口,支持异步方法,这里我对【客户端操作Redis尽量不要使用异步方法】的说法不敢苟同,对于异步方法我认为还是遵守微软最佳实践:对于IO密集的操作,能使用异步尽量使用异步

// 对应redis自增api:DECR mykey
_redisDB0.StringDecrementAsync("ProfileUsageCap", (double)1)
// 对应redis api:HGET KEY field1
_redisDB0.HashGetAsync(profileUsage, eqidPair.ProfileId))           
// 对应redis哈希自增api:HINCRBY myhash field -1
_redisDB0.HashDecrementAsync(profileUsage, eqidPair.ProfileId, 1)
  • ConnectionMultiplexer 方式支持随时切换Redis DB,对于多个Redis DB的操作,我封装了一个常用的Redis DB 操作客户端。

public class RedisStore{private static Lazy<ConnectionMultiplexer> LazyConnection;private static string connectionRedis = "localhost:6379";public RedisStore(string connectiontring){connectionRedis = connectiontring ?? "localhost:6379";LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionRedis));}public static ConnectionMultiplexer Connection => LazyConnection.Value;public RedisDatabase RedisCache => new RedisDatabase(Connection);}public class RedisDatabase{private Dictionary<int, IDatabase> DataBases = new Dictionary<int, IDatabase>();public ConnectionMultiplexer RedisConnection { get; }public RedisDatabase(ConnectionMultiplexer Connection){DataBases = new Dictionary<int, IDatabase>{ };for(var i=0;i<16;i++){DataBases.Add(i, Connection.GetDatabase(i));}RedisConnection = Connection;}public IDatabase this[int index]{get{if (DataBases.ContainsKey(index))return DataBases[index];elsereturn DataBases[0];}}}
2. Microsoft.Extensions.Caching.StackExchangeRedis

从nuget doc可知,该组件库依赖于 StackExchange.Redis 客户端;是.NetCore针对分布式缓存提供的客户端,侧重点在Redis的缓存特性

该库是基于 IDistributedCache 接口实现的,该接口为实现分布式缓存的通用性,缓存内容将以byte[] 形式读写 ;另外能使用的函数签名也更倾向于【通用的 增、查操作】

// add Redis cache service
services.AddStackExchangeRedisCache(options =>
{options.Configuration = Configuration.GetConnectionString("redis");options.InstanceName = "SampleInstance";
});// Set Cache Item (by byte[])lifetime.ApplicationStarted.Register(() =>
{var currentTimeUTC = DateTime.UtcNow.ToString();byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);var options = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(20));cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});// Retrieve Cache Item
[HttpGet]
[Route("CacheRedis")]
public async Task<string> GetAsync()
{var ret = "";var bytes = await _cache.GetAsync("cachedTimeUTC");if (bytes != null){ret = Encoding.UTF8.GetString(bytes);_logger.LogInformation(ret);}return  await Task.FromResult(ret);
}

① 很明显,该Cache组件并不能做到自由切换 Redis DB, 目前可在redis连接字符串一次性配置项目要使用哪个Redis DB

② 会在指定DB(默认为0)生成key = SampleInstancecachedTimeUTC 的redis缓存项

③ 通用接口只支持bytes[] 形式传值,以上byte[] 实际是以Hash的形式存储

3. CSRedisCore

该组件是基于连接池模型,默认配置会预热50个redis连接。功能更灵活,针对实际Redis应用场景有更多玩法。

  • 普通模式

  • 官方集群模式 redis cluster

  • 分区模式(作者实现)

普通模式使用方法极其简单,这里要提示的是:该客户端也不支持随意切换Redis DB, 但是原作者给出一种缓解的方式:构造多客户端。

var redisDB = new CSRedisClient[16];                        // 多客户端
for (var a = 0; a < redisDB.Length; a++)redisDB[a] = new CSRedisClient(Configuration.GetConnectionString("redis") + ",defaultDatabase=" + a);
services.AddSingleton(redisDB);
// ----------------------------
_redisDB[0].IncrByAsync("ProfileUsageCap", -1)
_redisDB[0].HGetAsync(profileUsage, eqidPair.ProfileId.ToString())
_redisDB[0].HIncrByAsync(profileUsage, eqidPair.ProfileId.ToString(), -1);

内置的静态操作类RedisHelper, 与Redis-Cli 命令完全一致, 故能原生支持”blocking pops”。

// 实现后台服务,持续消费MQ消息
public class BackgroundJob : BackgroundService{private readonly CSRedisClient[] _redisDB;private readonly IConfiguration _conf;private readonly ILogger _logger;public BackgroundJob(CSRedisClient[] csRedisClients,IConfiguration conf,ILoggerFactory loggerFactory){_redisDB = csRedisClients;_conf = conf;_logger = loggerFactory.CreateLogger(nameof(BackgroundJob));}//  Background 需要实现的后台任务protected override async Task ExecuteAsync(CancellationToken stoppingToken){_redisDB[0] = new CSRedisClient(_conf.GetConnectionString("redis") + ",defualtDatabase=" + 0);RedisHelper.Initialization(_redisDB[0]);while (!stoppingToken.IsCancellationRequested){var key = $"eqidpair:{DateTime.Now.ToString("yyyyMMdd")}";// 阻塞式从右侧读取List首消息var eqidpair = RedisHelper.BRPop(5, key);// TODO Handler Messageelseawait Task.Delay(1000, stoppingToken);}}}-----RedisMQ 生产者---
//  将一个或多个msg插入List头部
RedisHelper.LPush(redisKey, eqidPairs.ToArray());

以上三大客户端,Microsoft.Extensions.Caching.StackExchangeRedis 与其他两者的定位还是有很大差距的,单纯使用Redis缓存特性, 有微软出品,必属精品情结的可使用此客户端;
StackExchange.Redis、CSRedisCore 对于Redis全功能特性支持的比较全

Redis的一点小经验

  • 对要使用的Redis API 的时间复杂度心里要有数,尽量不要使用长时间运行的命令如keys *,可通过redis.io SlowLog命令观测哪些命令耗时较长

  • Redis Key可按照“:”分隔定义成有业务意义的字符串,如NewUsers:202004:666(某些Redis UI可直观友好查看该键值)

  • 合适确定Key-Value的大小:Redis对于small value更友好, 如果值很大,考虑划分到多个key

  • 关于缓存穿透,面试的时候会问,自行搜索布隆过滤器。

  • redis虽然有持久化机制,但在实际中会将key-value持久化到关系型数据库,因为对于某些结构化查询,SQL更为有效。

推荐阅读

● 这么香的Chrome插件,你都安装了吗?

● 一文掌握Cookies前世今生

● ASP.NET Core跨平台技术内幕

● TPL Dataflow组件应对高并发,低延迟要求

● 实例解读Docker Swarm

● 基于docker-compose的Gitlab CI/CD实践&排坑指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android elevation 白色,Android Elevation

简介&#xff1a;在Android API21&#xff0c;新添加了一个属性&#xff1a;android:elevation&#xff0c;用以在xml定义View的深度(高度)&#xff0c;也即z方向的值。除了elevation之外&#xff0c;类似于已有的translationX、translationY&#xff0c;也相对应地新增了一个t…

(译)创建.NET Core多租户应用程序-租户解析

介绍本系列博客文章探讨了如何在ASP.NET Core Web应用程序中实现多租户。这里有很多代码段&#xff0c;因此您可以按照自己的示例应用程序进行操作。在此过程的最后&#xff0c;没有对应的NuGet程序包&#xff0c;但这是一个很好的学习和练习。它涉及到框架的一些“核心”部分。…

【要闻】Kubernetes无用论诞生、Elasticsearch 7.6.2 发布

导读&#xff1a;本期要闻包含OpenStack网络如何给组织带来好处、Portworx CEO分享的如何让Kubernetes跑得快还不出错的秘籍等精彩内容。大数据要闻Elasticsearch 7.6.2 发布&#xff0c;分布式搜索和数据分析引擎Elasticsearch 7.6.2 发布了&#xff0c;Elasticsearch 是一个分…

玩转控件:对Dev中GridControl控件的封装和扩展

清明节清明时节雨纷纷路上行人欲断魂借问酒家何处有牧童遥指杏花村又是一年清明节至&#xff0c;细雨绵绵犹如泪光&#xff0c;树叶随风摆动....转眼间&#xff0c;一年又过去了三分之一&#xff0c;疫情的严峻让不少企业就跟清明时节的树叶一样&#xff0c;摇摇欲坠。裁员的裁…

创业5年,我有5点关于人的思考

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份不知不觉创业五年了&#xff0c;也算一个屡战屡败、屡败屡战的创业老兵了。从第一次失败要靠吃抗抑郁的药&#xff0c;到现在理性的看待成败得失&#xff0c;不得不说&#xff0c;创业这条路对我还是有不小提…

C++实现具有[数组]相似特征的类DoubleSubscriptArray

#include <iostream> using namespace std;class DoubleSubscriptArray {public:DoubleSubscriptArray(int x, int y) {p new int *[x];//行 //申请行的空间for (int i 0; i < x; i) {p[i] new int [y];//每行的列申请空间}for (int i 0; i < x; i)for (int j …

Docker-HealthCheck指令探测ASP.NET Core容器健康状态

写在前面HealthCheck 不仅是对应用程序内运行情况、数据流通情况进行检查&#xff0c;还包括应用程序对外部服务或依赖资源的健康检查。健康检查通常是以暴露应用程序的HTTP端点的形式实施&#xff0c;可用于配置健康探测的的场景有 &#xff1a;容器或负载均衡器 探测应用状态…

ASP.NET Core分布式项目实战(课程介绍,MVP,瀑布与敏捷)--学习笔记

任务1&#xff1a;课程介绍课程目标&#xff1a;1、进一步理解 ASP.NET Core 授权认证框架、MVC 管道2、掌握 Oauth2&#xff0c;结合 Identity Sercer4 实现 OAuth2 和 OpenID Connect Server3、掌握 ASP.NET Core 与 Redis, MongoDB, RabitMQ, MySQL 配合使用4、理解 DDD&…

html坐标轴背景色,CSS 背景(css background)

CSS 背景-CSS background一、Css background背景语法 - TOPCSS背景基础知识CSS 背景这里指通过CSS对对象设置背景属性&#xff0c;如通过CSS设置背景各种样式。背景语法&#xff1a;background: background-color || background-image || background-repeat || background-…

LeetCode 965单值二叉树-简单

如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff1b;否则返回 false。 示例 1&#xff1a; 输入&#xff1a;[1,1,1,1,1,null,1] 输出&#xff1a;true 示例 2&#xff1a; 输入&…

使用EF.Core将同一模型映射到多个表

在 EntityFramework Core 中&#xff0c;我们可以使用属性或Fluent API来配置模型映射。有一天&#xff0c;我遇到了一个新的需求&#xff0c;有一个系统每天会生成大量数据&#xff0c;每天生成一个新的表存储数据。例如&#xff0c;数据库如下所示&#xff1a;所有表都具有相…

EntityFramework Core 3.x添加查询提示(NOLOCK)

前几天看到有博客园中有园友写了一篇关于添加NOLOCK查询提示的博文&#xff0c;这里呢&#xff0c;我将介绍另外一种添加查询提示的方法&#xff0c;此方式源于我看过源码后的实现&#xff0c;孰好孰歹&#xff0c;请自行判之&#xff0c;接下来我们一起来看看。在EntityFramew…

Xamarin.Forms客户端第一版

1. 功能简介1.1. 读取手机基本信息主要使用Xamarin.Essentials库获取设备基本信息&#xff0c;Xam.Plugin.DeviceInfo插件获取App Id&#xff0c;其实该插件也能获取设备基本信息。1.2. 读取手机联系人信息Android和iOS工程具体实现联系人读取服务&#xff0c;使用到Dependency…

给 EF Core 查询增加 With NoLock

给 EF Core 查询增加 With NoLockIntroEF Core 在 3.x 版本中增加了 Interceptor&#xff0c;使得我们可以在发生低级别数据库操作时作为 EF Core 正常运行的一部分自动调用它们。例如&#xff0c;打开连接、提交事务或执行命令时。所以我们可以自定义一个 Interceptor 来记录执…

LeetCode 138 复制带随机指针的链表-中等

给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的原节点的值。新节点的 n…

ASP.NET Core分布式项目实战(业务介绍,架构设计,oAuth2,IdentityServer4)--学习笔记...

任务4&#xff1a;第一章计划与目录敏捷产品开发流程原型预览与业务介绍整体架构设计API 接口设计 / swaggerIdentity Server 4 搭建登录账号 API 实现配置中心任务5&#xff1a;业务介绍项目背景&#xff1a;基于人脉关系的金融行业项目用户&#xff1a;1、账号&#xff1a;基…

LeetCode 82 删除排序链表中的重复元素||-中等

存在一个按升序排列的链表&#xff0c;给你这个链表的头节点 head &#xff0c;请你删除链表中所有存在数字重复情况的节点&#xff0c;只保留原始链表中 没有重复出现 的数字。 返回同样按升序排列的结果链表。 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,…

你复工了吗?啥感受?

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「136」篇原创敬上感觉还没做什么事情&#xff0c;2020年的第一季度就结束了。相信大多数人也都已经复工了。之前进行远程公办的&#xff0c;大多也都回到了原先在公…

LeetCode 1669合并两个链表-中等

给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中第 a 个节点到第 b 个节点删除&#xff0c;并将list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请你返回结果链表的头指针。 输入&#xff1a…

dotNET Core 3.X 使用 Web API

现在的 Web 开发大多都是前后端分离的方式&#xff0c;后端接口的正确使用显得尤为重要&#xff0c;本文讲下在 dotNET Core 3.X 下使用 Web API 。环境操作系统&#xff1a;MacIDE&#xff1a;RiderdotNET Core&#xff1a;3.1创建项目如果是 Windows 操作系统当然是首选 VS20…