StackExchange Redis一些键已经丢失,而使用异步插入/读取数据



我相信我们在这里错过了一些非常重要的东西,所以希望有人能给我指出正确的方向。提前谢谢你:)

我们目前遇到的问题:有时异步操作(读)不会返回由异步操作写入的数据库的哈希值。例如,一次操作可以返回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表示一个线程安全的、无序的对象集合。

最新更新