Scut:Redis 资源管理器

核心文件是: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 / );
}
            for (int i = ; 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 == ) 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 = ; i < entityTypes.Length; i++)  //遍历每个类型,将二进制流反序列化成对象
{
var type = entityTypes[i];
var val = i < valueBytes.Length ? valueBytes[i] : null;
result[i] = val == null || val.Length ==
? 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, );
}
return null;
}

写入:

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

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

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

上一篇:jquery 农历日历 可自适应


下一篇:C#分布式缓存一:Couchbase的安装与简单使用