2015-08-17 33 views
5

Jestem pewien, że brakuje nam czegoś bardzo ważnego tutaj, więc mam nadzieję, że ktoś może wskazać mi właściwy kierunek. Z góry dziękuję :)StackExchange Redis niektóre klawisze zostały utracone podczas używania async do wstawiania/odczytu danych

Problem, który mamy obecnie: czasami operacja asynchroniczna (odczyt) nie zwraca nam wartości mieszania z db, która została napisana przez operację asynchroniczną. Na przykład, jedna operacja czasowa może zwrócić nam 600 kluczy, przy następnej liczbie kluczy może wynosić 598, następna: 596 i tak dalej. Występuje również ten sam problem z krótkimi zestawami (gdy mamy do 10 kluczy w zestawie i odczytujemy 10 obiektów hashowych w partii: czasami możemy uzyskać 8 obiektów, czasami 6, gdy otrzymamy tylko 2. Mamy problem z metodami asynchronicznymi w około 30-40% naszej działalności, migracja do synchronicznych operacji rozwiązany niektórych przypadkach. - być straciliśmy wydajność

Przykład naszych tworzonych/odczytu operacji wsadowych

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

używamy zapisu operacje w następujący sposób:

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

Czytamy dane jako partii, stosując kolejny przykładowy kod

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

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

Wiemy, że batch.Execute ma synchroniczny/asynchroniczny naprawdę nie operacja, w tym samym czasie musimy sprawdzić status każdej operacji później. Planujemy wykonać więcej operacji odczytu-zapisu na serwerze redis, ale korzystając z tego problemu, nie jesteśmy pewni, czy jesteśmy na dobrej drodze).

Wszelkie porady/próbki i punkty we właściwym kierunku są wysoko cenione!

Niektóre informacje dodatkowe: Używamy klienta redis StackExchange (najnowsza stabilna wersja: 1.0.481) w roli asp.mvc/worker (.NET w wersji 4.5) do nawiązywania połączenia i pracy z pamięcią podręczną Redis Azure (C1, Standard). W tej chwili mamy około 100 000 kluczy w bazie danych podczas małego przepływu testowego (głównie Hasch - na podstawie zaleceń podanych w redis.io (każdy klucz przechowuje do 10 pól dla różnych obiektów, bez dużych danych lub pól tekstowych przechowywanych w haśle) i zestawy (głównie odwzorowania, z których największy może zabrać rodzicowi do 10 000 kluczy)). Mamy około 20 małych pisarzy do pamięci podręcznej (każda instancja programu piszącego zapisuje własny podzbiór danych i nie pokrywa się z innym, liczba kluczy do zapisu na operację wynosi do 100 (hash)). Mamy również jednego pracownika "dużego człowieka", który może wykonać obliczenia na podstawie aktualnego stanu redis i zapisać dane z powrotem na serwerze redis (liczba operacji - do 1200 kluczy do odczytu/zapisu na pierwsze żądanie, a następnie pracować z 10 000+ kluczy (przechowuj i kalkuluj) W tym czasie wielki człowiek działa: nikt nie czyta i nie pisz do tego kluczowego obszaru, jednak małymi pisarzami ciągle piszą kilka kluczy stale W tym samym czasie mamy wielu małych czytelników (do 100 000), którzy mogą zażądać określonego fragmentu danych (na podstawie mapowań i złączeń 2 obiektów hashowych) Ilość elementów hash do zwrócenia czytelnikom wynosi około 100-500 rekordów. Z powodu pewnych ograniczeń w modelu domeny - mamy spróbuj przechowywać/czytać klucze jako operacje wsadowe (największa (najdłuższa) partia może mieć do 500-1000 odczytów/zapisów pól hashów do pamięci podręcznej. w tej chwili.

Odpowiedz

0

Może można użyć zamiast

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

coś takiego?

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

ConcurrentBag reprezentuje bezpieczny dla wątków, nieuporządkowany zbiór obiektów.