Jeg kan ærlig talt ikke afgøre, om dette er et SO-spørgsmål eller et MSO-spørgsmål, men:
At gå til et andet system er aldrig hurtigere end at forespørge på lokal hukommelse (så længe den er tastet); enkelt svar:vi bruger begge dele! Så vi bruger:
- lokal hukommelse
- ellers tjek redis, og opdater lokal hukommelse
- ellers hent fra kilden, og opdater redis og lokal hukommelse
Dette forårsager så, som du siger, et problem med cache-invalidering - selvom det faktisk ikke er kritisk de fleste steder. Men til dette - gør redis-begivenheder (pub/sub) en nem måde at udsende nøgler, der ændrer sig til alle noder, så de kan droppe deres lokale kopi - hvilket betyder:næste gang det er nødvendigt, henter vi den nye kopi fra redis . Derfor udsender vi nøglenavne, der ændrer sig i forhold til et enkelt begivenhedskanalnavn.
Værktøjer:Redis på ubuntu-serveren; BookSleeve som en redis-indpakning; protobuf-net og GZipStream (aktiveret / deaktiveret automatisk afhængigt af størrelse) til pakkedata.
Så:redis pub/sub-begivenhederne bruges til at ugyldiggøre cachen for en given nøgle fra én node (den, der ved, at tilstanden er ændret) straks (stort set) til alle noder.
Med hensyn til forskellige processer (fra kommentarer, "bruger du nogen form for delt hukommelsesmodel til flere forskellige processer, der leverer de samme data?"):nej, det gør vi ikke. Hver web-tier-boks er kun vært for én proces (af et givet niveau), med multi-lejemål inden for det, så inden for den samme proces har vi måske 70 websteder. Af ældre årsager (dvs. "det virker og skal ikke repareres") bruger vi primært http-cachen med webstedsidentiteten som en del af nøglen.
For de få massivt dataintensive dele af systemet har vi mekanismer til at blive ved med at holde på disken, så in-memory-modellen kan overføres mellem successive app-domæner, efterhånden som nettet naturligt genbruger (eller genudrulles), men det er ikke relateret til redis.
Her er et relateret eksempel, der viser kun den brede smag af, hvordan dette kan fungere - spin op et antal forekomster af følgende, og skriv derefter nogle nøglenavne i:
static class Program
{
static void Main()
{
const string channelInvalidate = "cache/invalidate";
using(var pub = new RedisConnection("127.0.0.1"))
using(var sub = new RedisSubscriberConnection("127.0.0.1"))
{
pub.Open();
sub.Open();
sub.Subscribe(channelInvalidate, (channel, data) =>
{
string key = Encoding.UTF8.GetString(data);
Console.WriteLine("Invalidated {0}", key);
});
Console.WriteLine(
"Enter a key to invalidate, or an empty line to exit");
string line;
do
{
line = Console.ReadLine();
if(!string.IsNullOrEmpty(line))
{
pub.Publish(channelInvalidate, line);
}
} while (!string.IsNullOrEmpty(line));
}
}
}
Hvad du bør se er, at når du skriver et nøglenavn, vises det med det samme i alle de kørende forekomster, som så ville dumpe deres lokale kopi af den pågældende nøgle. I virkeligheden skal de to forbindelser naturligvis placeres et sted og holdes åbne, så ikke være i using
udsagn. Vi bruger næsten en enkelt til dette.