码迷,mamicode.com
首页 > 其他好文 > 详细

Scut:Redis 资源管理器

时间:2016-08-19 18:51:56      阅读:393      评论:0      收藏:0      [点我收藏+]

标签:

核心文件是:RedisConnectionPool.cs

对象池类的通用泛型封装:ObjectPoolWithExpire<T>

 

1. 主要变量

        private static ICacheSerializer _serializer;     //redis 存储内容的序列化器
        private static RedisPoolSetting _setting;        //redus 他、应遵循的配置
        private static ConcurrentDictionary<string, ObjectPoolWithExpire<RedisClient>> _poolCache;   //字典结构:每个 key 对应一个 pool 的集合   
        private static RedisInfo _currRedisInfo;

 

2. 初始化

        public static void Initialize(RedisPoolSetting setting, ICacheSerializer serializer)
        {
            _setting = setting;         //RedisPoolSetting 按默认配置加载的配置
            _serializer = serializer;   //采取的序列化器
            //init pool
            string key = GenratePoolKey(setting.Host, setting.DbIndex);     //127.0.0.1:6379#0 是首个管理 redisclient-pool 的 key
            var pool = GenrateObjectPool(setting);                          //建立对象池,主要是为泛型类注入 factory 方法,以及池深度、对象生命周期参数
        private static ObjectPoolWithExpire<RedisClient> GenrateObjectPool(RedisPoolSetting setting)
        {
            return new ObjectPoolWithExpire<RedisClient>(() => CreateRedisClient(setting), true, setting.PoolTimeOut, setting.MaxWritePoolSize / 10);   
        }
            for (int i = 0; i < pool.MinPoolSize; i++)      
            {
                pool.Put();
            }
            _poolCache[key] = pool;
            InitRedisInfo();  
        }

 

3. RedisClient 获取、读、写操作

句柄获取:

        public static RedisClient GetClient()
        {
             return GetOrAddPool(_setting);
        public static RedisClient GetOrAddPool(RedisPoolSetting setting)
        {
            var key = GenratePoolKey(setting.Host, setting.DbIndex);
            var lazy = new Lazy<ObjectPoolWithExpire<RedisClient>>(() => GenrateObjectPool(setting));  //根据配置找到pool的key,使用key检索到pool
            ObjectPoolWithExpire<RedisClient> pool = _poolCache.GetOrAdd(key, k => lazy.Value);          //在目标pool 获取一个 redisclient
            return pool.Get();
        }

        }

 

读取:

  先来看下应用层是如何加载数据的:

        public static object[] GetAllEntity(string personalId, params  Type[] entityTypes)
        {
            //todo: trace GetAllEntity
            var watch = RunTimeWatch.StartNew("Get redis data of persionalId:" + personalId);
            if (entityTypes.Length == 0) return null;

            byte[] keytBytes = ToByteKey(personalId);  //将私有ID转化成二进制流
            var redisKeys = new List<string>();
            foreach (var type in entityTypes)           //遍历所有要获取数据的类型
            {
                redisKeys.Add(GetRedisEntityKeyName(type));
            }
            try
            {
                byte[][] valueBytes = null;
                ProcessReadOnly(client =>
                {
                    var values = new List<byte[]>();
                    using (var p = client.CreatePipeline())
                    {
                        foreach (var key in redisKeys)  //使用redis管道,一次性执行多条读取命令
                        {
                            string k = key;
                            p.QueueCommand(cli => ((RedisNativeClient)cli).HGet(k, keytBytes), values.Add);  //将类型与私有ID组合成rediskey,将值获取到value中
                        }
                        p.Flush();
                    }
                    valueBytes = values.ToArray();  
                    //valueBytes = client.Eval(script, redisKeys.Count, redisKeys.ToArray());
                });
                watch.Check("redis get");
                if (valueBytes != null)
                {
                    var result = new object[entityTypes.Length];
                    for (int i = 0; i < entityTypes.Length; i++)  //遍历每个类型,将二进制流反序列化成对象
                    {
                        var type = entityTypes[i];
                        var val = i < valueBytes.Length ? valueBytes[i] : null;
                        result[i] = val == null || val.Length == 0
                            ? null
                            : _serializer.Deserialize(val, type);
                    }
                    return result;  //得到对象数组后返回,从应用层来看,该API可用于一次性获取一个personalkey的多种多类型数据
                }
            }
            catch (Exception ex)
            {
                TraceLog.WriteError("Get redis data of persionalId:{0} error:{1}", personalId, ex);
            }
            finally
            {
                watch.Flush(true, 200);
            }
            return null;
        }

 

写入:

  这里只看一个最常用的事务写入,对一个hashid下的多个key事务性地写入数据。 

     //该API的命名是更新,更新则包含写入与删除两个操作
     private static void TransUpdateEntity(IRedisTransaction trans, string hashId, byte[][] keys, byte[][] values, byte[][] removeKeys) { if (keys.Length > 0) { trans.QueueCommand(c => { var cli = (RedisClient)c; cli.HMSet(hashId, keys, values);   }); } if (removeKeys.Length > 0) { trans.QueueCommand(c => { var cli = (RedisClient)c; cli.HDel(hashId, removeKeys); }); } }

 

  在看 RedisConnectionPool.cs 的过程中,发现了大量 SchemaSet 与 Cache 的使用,下个阶段重点分析 Scut 的这两个部分。

 

Scut:Redis 资源管理器

标签:

原文地址:http://www.cnblogs.com/Daniel-Liang/p/5787791.html

(1)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!