我相信我们在这里错过了一些非常重要的东西,所以希望有人能给我指出正确的方向。提前谢谢你:)
我们目前遇到的问题:有时异步操作(读)不会返回由异步操作写入的数据库的哈希值。例如,一次操作可以返回600个键,下一次操作可以返回598个键,下一次可以返回596个键,以此类推。对于短集合,我们也会遇到同样的问题(当我们在集合中有多达10个键并在批处理中读取10个哈希对象时:有时我们可以获得8个对象,有时可以获得6个对象,一旦我们只获得2个对象)。我们在大约30-40%的操作中存在异步方法的问题,迁移到同步操作解决了一些情况——即使我们失去了性能。
创建/读批处理操作示例
protected void CreateBatch(Func<IBatch, List<Task>> action)
{
IBatch batch = Database.CreateBatch();
List<Task> tasks = action(batch);
batch.Execute();
Task.WaitAll(tasks.ToArray());
}
protected IEnumerable<T> GetBatch<T, TRedis>(
IEnumerable<RedisKey> keys,
Func<IBatch, RedisKey, Task<TRedis>> invokeBatchOperation,
Func<TRedis, T> buildResultItem)
{
IBatch batch = Database.CreateBatch();
List<RedisKey> keyList = keys.ToList();
List<Task> tasks = new List<Task>(keyList.Count);
List<T> result = new List<T>(keyList.Count);
foreach (RedisKey key in keyList)
{
Task task = invokeBatchOperation(batch, key).ContinueWith(
t =>
{
T item = buildResultItem(t.Result);
result.Add(item);
});
tasks.Add(task);
}
batch.Execute();
Task.WaitAll(tasks.ToArray());
return result;
}
我们用下一种方式写操作:
private void CreateIncrementBatch(IEnumerable<DynamicDTO> dynamicDtos)
{
CreateBatch(
batch =>
{
List<Task> tasks = new List<Task>();
foreach (DynamicDTO dynamicDto in dynamicDtos)
{
string dynamicKey = KeysBuilders.Live.Dynamic.BuildDetailsKeyByIdAndVersion(
dynamicDto.Id,
dynamicDto.Version);
HashEntry[] dynamicFields = _dtoMapper.MapDynamicToHashEntries(dynamicDto);
Task task = batch.HashSetAsync(dynamicKey, dynamicFields, CommandFlags.HighPriority);
tasks.Add(task);
}
return tasks;
});
}
我们使用下一个代码示例
批量读取数据IEnumerable<RedisKey> userKeys =
GetIdsByUserId(userId).Select(x => (RedisKey) KeysBuilders.Live.Dynamic.BuildDetailsKeyByUserId(x));
return GetBatch(userKeys, (batch, key) => batch.HashGetAllAsync(key), _dtoMapper.MapToDynamic);
我们知道那批货。执行不是同步/不是真正的异步操作,同时我们需要稍后检查每个操作的状态。我们确实计划对redis服务器进行更多的读写操作,但是使用这个问题,我们不确定我们是否在正确的道路上。
任何建议/样品和指出正确的方向是非常感谢!
一些附加信息:我们在asp中使用StackExchange redis客户端(最新稳定版本:1.0.481)。Mvc/worker角色. NET版本4.5)连接和使用Azure redis缓存(C1,标准)。目前,在小型测试流程中,我们在数据库中有大约10万个键(主要是基于redis提供的建议的哈希值)。IO(每个键为不同的对象存储最多10个字段,没有大数据或文本字段存储在散列中)和set(主要是映射,最大的一个可以将多达10,000个键存储到父节点))。我们有大约20个小的写入器到缓存(每个写入器实例写它自己的数据子集,并且不与另一个重叠,每个操作要写的键的数量最多为100(哈希))。此外,我们还有一个"大人物"工作人员,他可以根据当前redis状态进行一些计算,并将数据存储回redis服务器(操作量-每次请求读/写多达1200个键,然后处理10,000多个键(存储和计算)。这时,大人物在工作:没有人对这个精确的键空间进行读写,然而,小的写入器继续不断地写入一些键。同时,我们有许多小的读取器(最多10万个),它们可以请求特定的数据块(基于映射和两个哈希实体的连接)。返回给读取器的哈希实体的数量大约是100-500条记录。由于域模型中的一些限制,我们尝试将键作为批处理操作来存储/读取(最大(最长)的批处理可以将多达500-1000个哈希字段读/写到缓存中)。我们现在不使用交易。
也许你可以用
List<T> result = new List<T>(keyList.Count);
像这样?
ConcurrentBag<T>result = new ConcurrentBag<T>();
ConcurrentBag表示一个线程安全的、无序的对象集合。