Redis系列(二)-Hredis客户端设计及开源
接上篇c#实现redis客户端(一),重新整理些了下。
阅读目录:
- 项目说明
- Hredis设计图
- 单元测试场景
- 总结
项目说明
背景:因为有地方要用,而又没找到对sentinel良好支持的Net客户端,所以就简单重写了个。
目标:尽可能的简单,轻量级,不进行过度的封装,使用方便。
代码说明:
1. 与Redis服务端的Socket通信、协议格式封装。在RedisBaseClient里
2. 只对Set、Get封装,暴露出Send接口。在RedisCommand里面添加自己想要的支持。
var info = rcClient.Send(RedisCommand.INFO);
3. RedisBaseClient是通信层。 如果扩展其他用途继承即可,比如RedisPubSub:RedisBaseClient,RedisSentinel:RedisBaseClient
4. 供上层良好调用的话,可以做成partial类扩展redisclient。比如RedisClient.String
5. 订阅的监听使用while的,可在触发事件里面做阻塞。
6. PoolRedisClient池的实现使用ConcurrentStack,仅达到了复用socket连接的目的。
7. 支持socket重连,做法是关闭旧连接,重新建立新socket。
8. 多个命令使用管道实现。见set实现
后续思路:
一:PoolRedisClient池里面连接的释放问题?
1. 使用using
2. 不用使用using,会自动检测并回收 。
不做成自动检测的话,就会出现连接无法释放的问题,总会有人忘记释放的,所以要优化成1+2结合的方式。
二:client池和socket池分离,socket单独做一个池? 还在考虑中。
Hredis设计图
命令执行流程图、解决方案图、类图。
单元测试场景
一. Info命令通信、密码配置。
[TestMethod, TestCategory("Server")]public void Redis_PassWord(){using (var rcClient = new RedisClient(new RedisConfiguration(){Host = ip,Port = 6381,PassWord = "123465"})){var info = rcClient.Send(RedisCommand.INFO);Debug.Write(info.ToString());}}
二. 普通订阅,及模式匹配订阅。这里订阅的是Sentinel事件信息。
[TestMethod, TestCategory("PushSub")]public void Subscribe_Sentinel_Test(){using (RedisPubSub rsc = new RedisPubSub("127.0.0.1", 20001)){rsc.SubscriptionReceived += rsc_SubscriptionReceived;//rsc.Subscribe("+sdown");}}
[TestMethod, TestCategory("PushSub")]public void PSubscribe_Sentinel_Test(){using (RedisPubSub rsc = new RedisPubSub("127.0.0.1", 20001)){rsc.SubscriptionReceived += rsc_SubscriptionReceived;// rsc.PSubscribe("*"); }}private void rsc_SubscriptionReceived(object sender, object args){if (args is object[]){var list = args as object[];foreach (var o in list){Debug.Write("\r\n" + o.ToString());}}else{Debug.Write("\r\n" + args.ToString());}var sr = sender as RedisPubSub;sr.UnSubscribe("*");}
View Code
三. client连接池、Parallel并发模拟。
[TestMethod, TestCategory("poolRedisclient")]public void GetClient_Test(){PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration(){Host = ip,Port = port,MaxClients = 100});using (var client = prc.GetClient()){client.Set("GetClient_Test", "GetClient_Test");var info2 = client.Get("GetClient_Test");Assert.AreEqual(info2.ToString(), "GetClient_Test");}prc.Dispose();}
View Code
[TestMethod, TestCategory("poolRedisclient")]public void Parallel_PoolClient_Test(){PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration(){Host = ip,Port = port,MaxClients = 100});Parallel.For(0, 1000, new ParallelOptions() {MaxDegreeOfParallelism = 100}, (index, item) =>{using (var client = prc.GetClient()){Thread.Sleep(100);client.Set("Parallel_PoolClient_Test" + index, "Parallel_PoolClient_Test");var info2 = client.Get("Parallel_PoolClient_Test" + index);Assert.AreEqual(info2.ToString(), "Parallel_PoolClient_Test");}});prc.Dispose();}
View Code
三. 超时重连、多线程并发超时重连。
[TestMethod, TestCategory("poolRedisclient")]public void PoolClient_TimeOut_Test(){PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration(){Host = ip,Port = port,MaxClients = 100});object info2;using (var client = prc.GetClient()){var result = client.Set("PoolClient_TimeOut_Test", "PoolClient_TimeOut_Test");Thread.Sleep(15000);info2 = client.Get("PoolClient_TimeOut_Test");}Assert.AreEqual(info2.ToString(), "PoolClient_TimeOut_Test");prc.Dispose();}
View Code
[TestMethod, TestCategory("poolRedisclient")]public void Thread_PoolClient_Test(){PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration(){Host = ip,Port = port});Parallel.For(0, 1000, new ParallelOptions() {MaxDegreeOfParallelism = 100}, (index, item) =>{var t = new Thread(() =>{Thread.Sleep(1000);object info2;using (var client = prc.GetClient()){client.Set("Parallel_PoolClient_Test" + index, "Parallel_PoolClient_Test");Thread.Sleep(15000);info2 = client.Get("Parallel_PoolClient_Test" + index);}Assert.AreEqual(info2.ToString(), "Parallel_PoolClient_Test");});t.Start();});Thread.Sleep(20000);prc.Dispose();}
四. String类型添加、过期时间添加。
[TestMethod, TestCategory("String")]public void Set_Get_key(){using (var rcClient = new RedisClient(ip, port)){rcClient.Set("Set_Get_key", "Set_Get_key");var info2 = rcClient.Get("Set_Get_key");Assert.AreEqual(info2.ToString(), "Set_Get_key"); } }
[TestMethod, TestCategory("String")]public void Set_key_Expire(){using (var rcClient = new RedisClient(ip, port)){rcClient.Set("Set_key_Expire", "Set_key_Expire", 10);var info1 = rcClient.Get("Set_key_Expire");Assert.AreEqual(info1.ToString(), "Set_key_Expire");Thread.Sleep(11000);var info2 = rcClient.Get("Set_key_Expire");Assert.AreEqual(info2, null);}}
View Code
总结
开源地址:https://github.com/mushroomsir/HRedis 有需要的同学,可以参考下。
Hredis后续会跟实际需求来写,如果有更好的实现思路,欢迎一起交流。
Redis系列(二)-Hredis客户端设计及开源相关推荐
- redis 系列二 -- 常用命令
2019独角兽企业重金招聘Python工程师标准>>> 1.基础命令 info ping quit save dbsize select flushdb ...
- Redis系列二:reids介绍
一.什么是redis.redis有哪些特性.redis有哪些应用场景.redis的版本 1. 什么是redis redis是一种基于键值对(key-value)数据库,其中value可以为string ...
- Redis系列二、redis的五种数据结构和相关指令之String
redis是一种基于键值对(key-value)的内存数据库,redis数据结构可以分为string.hash.list.set.sorted set.本节中将介绍Redis支持的主要数据结构中的st ...
- redis搭建主从哨兵模式+分片集群部署(redis系列二)
前言:在前一章了解redis的基本介绍后,这一章主要介绍redis的实战部署,文章有点长请一步步耐心看完,我相信肯定会有收获的,这里用的资源包是2022年最新的redis版本可能会跟旧版本不同,在此章 ...
- Redis系列(十四)、Redis6新特性之RESP3与客户端缓存(Client side caching)
Redis6引入新的RESP3协议,并以此为基础加入了客户端缓存的新特性,在此特性下,大大提高了应用程序的响应速度,并降低了数据库的压力,本篇就带大家来看一下Redis6的新特性:客户端缓存. 目录 ...
- 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明)
系列文章 1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列一) 2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明) 3. 开源一款强大的文件服务组件 ...
- 深入剖析Redis系列(七) - Redis数据结构之列表
前言 列表(list)类型是用来存储多个 有序 的 字符串.在 Redis 中,可以对列表的 两端 进行 插入(push)和 弹出(pop)操作,还可以获取 指定范围 的 元素列表.获取 指定索引下标 ...
- 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解
前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...
- Redis系列(五):Redis的过期键删除策略
Redis系列(五):Redis的过期键删除策略 - 申城异乡人 - 博客园 本篇博客是Redis系列的第5篇,主要讲解下Redis的过期键删除策略. 本系列的前4篇可以点击以下链接查看: Redis ...
- 深入剖析Redis系列(五) - Redis数据结构之字符串
前言 字符串类型 是 Redis 最基础的数据结构.字符串类型 的值实际可以是 字符串(简单 和 复杂 的字符串,例如 JSON.XML).数字(整数.浮点数),甚至是 二进制(图片.音频.视频),但 ...
最新文章
- GDB attach到进程
- 5G NGC — NWDAF 网络智能分析功能
- solr4.1 DataImport MYSQL批量导入
- MooseFS使用问题分析总结
- 【任务脚本】0530更新淘宝618活动领喵币脚本,OrangeJs基于autojs全自动程序稳定运行,向大神致敬...
- Segment-段(SAP)
- 快速谱峭度matlab,一种基于快速谱峭度分析的泵潜在空化故障检测方法与流程
- Win10下安装LabelImg以及使用(绝对是全网最简单的教程)
- vscode ---- 插件
- 程序员修神之路--分布式高并发下Actor模型如此优秀
- SDNLAB技术分享(二):从Toaster示例初探ODL MD-SAL架构
- python模块使用手册_Python中文手册-Python模块
- suse 12 sp5安装bug
- 汇编语言简明教程习题答案
- div 设置a4大小_转载 网页打印时设置A4大小
- 轻量级Kubernetes之k3s:15:firewalld对应方法
- 头条小程序可以使用uniapp的地图选择(uni.chooseLocation)
- 多个勤于奋,到底那个是真的?勤于奋被他人抄袭
- 柯伊玟导演作品《黑暗迷踪》顺利杀青
- 【Chrome】图片批量下载扩展zzllrr Imager小乐图客V1.4 (支持正则表达式、自定义JS代码、自定义引擎、多网站取图规则)...