2016-11-24 5 views
0

Unsere ist eine Reise-Website. Bei bestimmten Suchkriterien (Location, checkIn, CheckOut, Adults, Child) zeige ich das Ergebnis auf der Benutzeroberfläche gleichzeitig an und speichere das Ergebnis im redis-Server zum Zwischenspeichern, da sich die Werte nicht so oft ändern.Handle Nebenläufigkeit

dh Schlüssel wäre Suchkriterien und Wert wäre List.Now wenn nächste Anfrage kommt es zuerst sucht die redis und wenn für den angeforderten Schlüssel, Wert ist, wird das Ergebnis von Redis anderen weise eine neue Suche angezeigt würde angewendet und die Ergebnisse werden im Cache gespeichert.

Frage: Wenn es keine Ergebnisse in Redis gibt und Millionen Benutzer die Suche nach den gleichen Suchkriterien gleichzeitig anwenden.Wie kann diese Situation behandelt werden? Weil alle Suchen gleichzeitig kommen und der Cache zu diesem Zeitpunkt kein Ergebnis hat. Wir müssen die Leistung im Auge behalten.

Hilfe wäre willkommen.

Antwort

0

Es scheint, als wollten Sie vermeiden, unnötigerweise zur Datenquelle zu wechseln. Wenn viele Threads zur gleichen Zeit dasselbe Objekt anfordern, möchten Sie es einem Benutzer ermöglichen, die Datenquelle abzufragen und die Daten zwischenzuspeichern und die anderen zu halten, bis die Daten gefüllt sind.

Möglicherweise möchten Sie eine haben decorator, um sicherzustellen, dass nur ein Abfragetyp zur gleichen Zeit ausgeführt wird. Sie können die Abfrage mit einem Objekt darstellen, das sich in einer Thread-sicheren Auflistung befindet, und sie während der Ausführung der Abfrage sperren.

So eine Schnittstelle zum Ausdruck, wie Sie Ihre Datenquelle abfragen gegeben:

interface IQueryExecuter<TQuery, TResult> 
{ 
    TResult Execute(TQuery query); 
} 

Sie einen Thread sicher Dekoratorobjekt verwenden können, die Abfragen Ergebnisse und im Falle speichert das Abfrageergebnis nicht im Cache gespeichert wird, wird nur ein Thread führt die Abfrage an die Datenquelle durch:

Nicht getesteter Code!

class QueryThrottler<TQuery, TResult> : IQueryExecuter<TQuery, TResult> 
{ 
    // do not lock on external objects 
    class QueryObject 
    { 
     public TQuery Query { get; set; } 
    } 

    readonly IQueryExecuter<TQuery, TResult> _inner; 
    readonly ConcurrentDictionary<TQuery, QueryObject> _queries; 

    public QueryThrottler(IQueryExecuter<TQuery, TResult> inner) 
    { 
     _queries = new ConcurrentDictionary<TQuery, QueryObject>(); 
     _inner = inner; 
    } 

    public TResult Execute(TQuery query) 
    { 
     // if it is on cache return the result 
     TResult result; 
     if (!IsCached(query, out result)) 
     { 
      // otherwise lock other threads 
      // on the same query 
      var queryObject = _queries.GetOrAdd(query, k => new QueryObject() { Query = k }); 
      lock (queryObject) 
      { 
       // double check it is not cached already 
       if (!IsCached(query, out result)) 
       { 
        result = _inner.Execute(queryObject.Query); 
        PopulateCache(query, result); 
       } 
      } 
     } 
     return result; 
    } 

    private void PopulateCache(TQuery query, TResult result) 
    { 
     // Save the result in Redis using TQuery as key 
    } 

    private bool IsCached(TQuery query, out TResult result) 
    { 
     // go to redis and check if the query is cached using TQuery as key 
     // if exists, set the result out parameter and return true 
     // otherwise, return false 
     result = default(TResult); 
     return false; 
    } 
} 

Dieser Code stützt sich auf TQuery richtige Implementierungen von GetHashCode und Equals haben.

Das verzierte Objekt (inner im Konstruktor) ist das Objekt, das die eigentliche Abfrage an die Datenquelle ausführen würde.

Wenn Sie viele Server haben, und wollen sicherstellen, dass nur ein Thread machen von allen Servern die eigentliche Abfrage mit der Datenquelle zu tun, anstatt lock, können Sie eine verteilte Sperre wie LockTake/LockRelease von StackExchange.Redis verwenden.