标签:
核心文件是: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 的这两个部分。
标签:
原文地址:http://www.cnblogs.com/Daniel-Liang/p/5787791.html