前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis系列(二)-Hredis客户端设计及开源

Redis系列(二)-Hredis客户端设计及开源

作者头像
蘑菇先生
发布2018-05-21 17:18:16
8440
发布2018-05-21 17:18:16
举报

接上篇c#实现redis客户端(一),重新整理些了下。

项目说明

背景:因为有地方要用,而又没找到对sentinel良好支持的Net客户端,所以就简单重写了个。

目标:尽可能的简单,轻量级,不进行过度的封装,使用方便。

代码说明:

        1. 与Redis服务端的Socket通信、协议格式封装。在RedisBaseClient里 

        2. 只对Set、Get封装,暴露出Send接口。在RedisCommand里面添加自己想要的支持。

代码语言:javascript
复制
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命令通信、密码配置。
代码语言:javascript
复制
 [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事件信息。
代码语言:javascript
复制
        [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");
            }
        }
代码语言:javascript
复制
[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("*");
        }
三.  client连接池、Parallel并发模拟。
代码语言:javascript
复制
  [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();
        }
代码语言:javascript
复制
        [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();
        }
三.  超时重连、多线程并发超时重连。
代码语言:javascript
复制
        [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();
        }
代码语言:javascript
复制
  [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类型添加、过期时间添加。
代码语言:javascript
复制
[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");
            }
        }
代码语言:javascript
复制
  [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);

            }
        }

总结

开源地址:https://github.com/mushroomsir/HRedis  有需要的同学,可以参考下。

Hredis后续会跟实际需求来写,如果有更好的实现思路,欢迎一起交流。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-04-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目说明
  • Hredis设计图
  • 单元测试场景  
    • 一. Info命令通信、密码配置。
      •  二. 普通订阅,及模式匹配订阅。这里订阅的是Sentinel事件信息。
        • 三.  client连接池、Parallel并发模拟。
          • 三.  超时重连、多线程并发超时重连。
            • 四. String类型添加、过期时间添加。
            • 总结
            相关产品与服务
            云数据库 Redis
            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档