2015-08-17 26 views
5

Sono sicuro che ci manca qualcosa di molto importante qui, quindi spero che qualcuno possa indicarmi la giusta direzione. Grazie in anticipo :)StackExchange Redis alcuni tasti sono stati persi durante l'utilizzo async per inserire/leggere i dati

Problema che attualmente riscontriamo: a volte operazione asincrona (leggi) non restituire valore hash da db che è stato scritto dall'operazione asincrona. Ad esempio, un'operazione di una volta può restituire 600 chiavi, la quantità di chiavi successiva può essere 598, la successiva: 596 e così via. Inoltre riscontriamo lo stesso problema con i set brevi (quando abbiamo 10 chiavi nel set e leggiamo 10 oggetti hash nel batch: a volte possiamo ottenere 8 oggetti, a volte 6, una volta ottenuto solo 2. Abbiamo problemi con i metodi asincroni in circa il 30-40% delle nostre operazioni, migrazione alle operazioni sincrone risolto alcuni dei casi -. essere abbiamo perso prestazioni

Esempio dei nostri creare/operazioni batch lettura

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; 
    } 

usiamo write operazioni in corso:

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; 
       }); 
    } 

Leggiamo i dati come in batch utilizzando il codice di esempio seguente

IEnumerable<RedisKey> userKeys = 
         GetIdsByUserId(userId).Select(x => (RedisKey) KeysBuilders.Live.Dynamic.BuildDetailsKeyByUserId(x)); 

        return GetBatch(userKeys, (batch, key) => batch.HashGetAllAsync(key), _dtoMapper.MapToDynamic); 

Sappiamo che batch.Execute è alcuna operazione sincrona/asincrona non veramente, allo stesso tempo, abbiamo bisogno di controllare lo stato di ogni operazione in seguito. Abbiamo in programma di fare molte più operazioni di lettura-scrittura sul server redis, ma usando questo problema, non siamo sicuri di essere sulla strada giusta.

Tutti i consigli/campioni e punti nella giusta direzione sono molto apprezzati!

Alcune informazioni Additonal: Stiamo usando StackExchange Redis cliente (ultima versione stabile: 1.0.481) in asp.mvc/ruolo dei lavoratori (.NET versione 4.5) per connettersi e lavorare con Azure Redis cache (C1, Standard). Al momento abbiamo circa 100.000 chiavi nel Database durante un piccolo flusso di test (principalmente Hash - basate su raccomandazioni fornite in redis.io (ciascuna chiave memorizza fino a 10 campi per oggetti diversi, nessun dato grande o campi di testo memorizzati nell'hash) e set (principalmente i mapping, il più grande può richiedere fino a 10.000 chiavi per il genitore)). Abbiamo circa 20 piccoli scrittori nella cache (ogni istanza del writer scrive il proprio sottoinsieme di dati e non si sovrappone a un altro, la quantità di chiavi da scrivere per operazione è fino a 100 (hash)). Inoltre, abbiamo un lavoratore "grande uomo" che può eseguire alcuni calcoli basati sullo stato redis corrente e archiviare i dati nel server redis (quantità di operazioni: fino a 1200 chiavi da leggere/scrivere per prima richiesta, quindi lavorare con 10 000+ chiavi (memorizza e calcola) Al momento il grande uomo lavora: nessuno legge-scrive in questo spazio tasti esatto, tuttavia i piccoli scrittori continuano a scrivere alcune chiavi costantemente. Allo stesso tempo abbiamo molti piccoli lettori (fino a 100.000) che possono richiedere il loro specifico pezzo di dati (basato su mapping e join di 2 entità hash. La quantità di entità hash da restituire ai lettori è di circa 100-500 record. A causa di alcune restrizioni nel modello di dominio - noi prova a memorizzare/leggere le chiavi come operazioni batch (il batch più grande (il più lungo) può contenere fino a 500-1000 letture/scritture di campi hash nella cache. Non usiamo transazioni a t il momento.

risposta

0

Forse si può usare al posto di

List<T> result = new List<T>(keyList.Count); 

qualcosa di simile?

ConcurrentBag<T>result = new ConcurrentBag<T>(); 

ConcurrentBag rappresenta una raccolta di oggetti non protetta da thread.