Come conservare i contatori su Redis riducendo al minimo la potenziale perdita di dati

0

L'applicazione su cui sto lavorando ha bisogno di creare un contatore che rappresenti il numero di volte in cui ogni pezzo di contenuto è stato visualizzato.

Ci sono due obiettivi qui:

  1. Aggiorna il contatore in tempo reale
  2. Riduci il carico su MySQL

Attualmente ciò che facciamo è creare una chiave di cache in Redis per ogni parte di contenuto che contiene il numero di visualizzazioni. Quando si verifica un evento di visualizzazione, incrementiamo il conteggio delle visualizzazioni. Se non c'è ancora un valore sulla chiave quando avviene una lettura o una scrittura, calcoliamo il conteggio delle visualizzazioni di tutti i tempi utilizzando un'origine dati separata (Influxdb).

Il problema è che il nostro approccio esistente non sarà più fattibile a causa del modo in cui stiamo ristrutturando i dati di InfluxDB. Non è più adeguatamente performante calcolare il conteggio di tutte le visualizzazioni temporali per una carta usando i dati di Influx, per ragioni per cui non entrerò qui (non esitate a chiedere).

Essenzialmente, non abbiamo più un modo per calcolare le visualizzazioni di tutte le ore "da zero". Dovremo fare affidamento sui valori dei contatori esistenti e solo incrementarli (mai completamente ricalcolarli).

Ho la seguente idea per fare questo:

  1. Calcola le visualizzazioni di tutti i tempi su ogni contenuto e archivia in MySQL (questo può essere fatto una sola volta per seminare i dati)
  2. Quando una lettura / scrittura avviene per la prima volta, cercalo in MySQL e memorizzalo in Redis
  3. Ogni volta che si verifica una scrittura, incrementa il conteggio su Redis
  4. In un lavoro in background, una volta all'ora o giù di lì, aggiorna il numero di visualizzazioni nel database MySQL usando i dati in Redis.

Questo produrrà al massimo un'ora di perdita di dati, se Redis rilascia tutte le chiavi un minuto 59 proprio prima che avvenga il lavoro in background.

Questo approccio ha senso? Se c'è un modo migliore per farlo?

modifica

Ora che ci penso un po 'di più, il concetto di un lavoro in background che aggiorna tutte le carte è un po' problematico. Se nella cache sono presenti milioni di chiavi, in che modo l'applicazione dovrebbe sapere quale attività ha avuto e come dovrebbero essere copiati i conteggi Redis su MySQL?

Quindi, penso che ci possa essere un tasto speciale su Redis che memorizza una coda di tutti gli ID delle carte che hanno avuto aggiornamenti. Quindi il lavoro in background può vedere gli ID di scheda unqiue in questo elenco e richiedere solo i dati per l'aggiornamento.

    
posta max pleaner 18.12.2018 - 21:51
fonte

1 risposta

0

Una tecnica che può essere utile è usare tecniche probabilistiche invece di programmi fissi. Ogni volta che un processo aggiorna la cache, possono lanciare i dadi per determinare se tale chiave (o un intervallo di chiavi) debba essere sincronizzata. Se la probabilità di sincronizzazione dipende dalla velocità di scrittura su ciascuna chiave (come p = 1 / n per n modifiche recenti) può aiutarti a mantenere un tasso di sincronizzazione coerente su tutte le chiavi. Al contrario, una pianificazione fissa potrebbe portare a picchi di carico nei database o potrebbe non corrispondere alla velocità di modifica (ad esempio la sincronizzazione dei tasti che non sono stati modificati). La parte difficile di questa soluzione è tenere traccia della velocità delle modifiche.

Potresti anche voler rimuovere le chiavi non utilizzate dalla cache. Puoi forse iscriverti agli eventi di sfratto in modo da poterli persistere prima che vengano rimossi.

Potrebbe anche valere la pena di considerare se provare a sincronizzare due database sia una soluzione ragionevole (in particolare, se i requisiti di prestazione richiedono tutta questa complessità). Alternative:

  • Potresti voler utilizzare un archivio di valori-chiave persistente solo per questi contatori, non nel tuo database principale. Redis stesso può farlo, con alcune restrizioni. Tuttavia, separare i dati renderà alcune domande più complicate, ad es. ordinamento per valore contatore.
  • Probabilmente la soluzione più semplice sarebbe quella di ridimensionare il database principale in modo che possa gestire direttamente il carico, possibilmente utilizzando una cache per ammorbidire il carico di lettura.
  • Per ridurre il carico di scrittura di eventi ad alto tasso, potrebbe essere sufficiente tenere e aggregare questi eventi in una breve coda. La coda viene regolarmente impegnata come aggiornamento batch (ad esempio ogni 1 s). Se più modifiche allo stesso contatore arrivano in una finestra di campionamento, possono essere combinate. Questo è simile alla tua idea di cache, ma dal momento che la coda contiene solo elementi che sono stati modificati, non è necessario eseguire la scansione di un enorme spazio per le chiavi durante la sincronizzazione. Uno svantaggio è che questa coda diventa un singolo punto di errore.

Naturalmente, gli aspetti di queste soluzioni possono essere combinati se necessario. Prenderò in considerazione una cache scritta nella tua domanda, ma indirizzerà tutte le scritture persistenti attraverso una coda che può unire le scritture. Per esempio. alcuni eventi aggiornerebbero sia la coda che la cache, ma non ci sarebbero servizi che scansionano la cache per le chiavi che devono essere aggiornate.

    
risposta data 21.12.2018 - 16:54
fonte

Leggi altre domande sui tag