2016-03-16 12 views
7

Ho un requisito per elaborare più record da una coda. Ma a causa di alcuni problemi esterni gli oggetti possono verificarsi sporadicamente più volte. Ho bisogno di elaborare gli elementi solo una voltaRedis PFADD per verificare una query esistente nella serie

Quello che ho pianificato di utilizzare è PFADD in redis ogni record (come md5sum) e quindi vedere se ciò restituisce successo. Se questo non mostra incrementi, il record è un duplicato che processa il record.

Questo sembra abbastanza semplice, ma io sono sempre troppi falsi positivi durante l'utilizzo PFADD

Esiste un modo migliore per fare questo?

risposta

2

In generale nei sistemi distribuiti si deve scegliere tra gli elementi di elaborazione sia:

  • al massimo una volta
  • almeno una volta

lavorazione qualcosa di esattamente una sola volta sarebbe conveniente tuttavia questo è generalmente impossibile.

Detto questo, potrebbero esserci soluzioni accettabili per il tuo caso d'uso specifico e, mentre suggerisci di conservare gli articoli già elaborati, potrebbe essere una soluzione accettabile.

Attenzione però che PFADD utilizza HyperLogLog, che è veloce e scales but is approximate sul conteggio degli articoli, quindi in questo caso non penso che questo sia ciò che desideri. Tuttavia, se si ha una piccola probabilità di errori, la struttura di dati più appropriata in questo caso sarebbe uno Bloom filter (come descritto here for Redis), che può essere implementato in modo molto efficiente in termini di memoria.

Una soluzione semplice, efficiente e recommended sarebbe utilizzare una semplice chiave redis (ad esempio un hash) che memorizza un valore booleano ("0", "1" o "true", "false") per istanza con l'istruzione opzionale HSET o SET with the NX. Si potrebbe anche metterlo sotto un namespace se lo si desidera. Ha anche il vantaggio di poter espirare anche le chiavi.

Sarebbe evitare di utilizzare un set (non il comando SET, ma piuttosto il SINTER, SUNION comandi), che non necessariamente funziona bene con Redis cluster se si vuole scalare a più di un nodo. SISMEMBER va ancora bene (ma manca alcune funzionalità di hash come il tempo di vivere).

Se si utilizza un hash, vorrei anche suggerire di scegliere una funzione di hash che ha meno possibilità di collisions than md5 (una collisione significa che due oggetti diversi finiscono con lo stesso hash).

Un approccio alternativo all'hash sarebbe assegnare un uuid a ogni oggetto quando lo si mette in coda (o un squuid se si desidera avere informazioni sull'ora).

+1

Penso che HSET sia una buona soluzione, anche un normale SET con l'opzione NX è una buona opzione ed è possibile aggiungere una scadenza se gli articoli in coda non si ripetono dopo un periodo – PerroVerd

+0

@PerroVerd esattamente (pensavo di aver scritto a riguardo ma si è distratto). Le operazioni di base di Redis sono generalmente abbastanza buone (l'unica cosa è evitare la scansione dell'intero database e mantenere semplice la relazione tra le chiavi). – nha

+0

@nha usare un hash "booleano" invece di un Set non è solo imbarazzante ma anche più dispendioso dal momento che suggerisci di memorizzare anche le voci fasle/0 (stranamente, i Set di Redis sono implementati internamente con Hash). Gli insiemi sono ** la ** scelta naturale per i test di appartenenza e l'ultima modifica alla tua risposta la degrada solo - la parte relativa alle collisioni di hash è in realtà molto corretta ma è completamente persa in inesattezze. Infine, i set sono interamente sicuri per i cluster, sono operazioni cross-slot multi-chiave che non sono supportate a prescindere dalla struttura dei dati. –

4

Essendo la struttura dati probabilistica che è, l'HyperLogLog di Redis presenta uno 0,81% di errore standard. È possibile ridurre (ma mai eliminare) la probabilità di falsi positivi utilizzando più HLL, ciascuno dei quali contando il valore di una funzione di hash diversa nel record.

Si noti inoltre che se si utilizza un singolo HLL non è necessario eseguire il hash del record: solo PFADD così com'è.

In alternativa, utilizzare un set Redis per conservare tutti gli identificatori/hash/record e avere test di appartenenza accurati al 100% con SISMEMBER. Questo approccio richiede più risorse (RAM) durante la memorizzazione di ciascun elemento elaborato, ma a meno che la coda non sia davvero enorme e non dovrebbe costituire un problema per un'istanza Redis modesta. Per tenere sotto controllo il consumo di memoria, alternare gli insiemi in base alla data e impostare una scadenza sui tasti Set (un altro approccio consiste nell'utilizzare un singolo set ordinario e rimuovere manualmente i vecchi elementi mantenendo il loro timestamp nel punteggio).

+0

SISMEMBER memorizzerà tutti i "membri" in memoria, potrei avere 10 milioni di record md5 al giorno e ho bisogno di memorizzarlo per una settimana – Ram

+0

@Ram Redis è fondamentalmente un database in memoria, il pericolo con i set sarebbe quello non giocano bene con il cluster Redis (che potreste voler usare a un certo punto se avete molti dati). Nel complesso, consiglierei un semplice hash (set, hset). – nha

+0

@Ram - dovrai usare 'SADD' per aggiungere membri al Set,' SISMEMBER' è solo un test di appartenenza. E sì, tutti i valori saranno mantenuti nella RAM - 70 milioni di valori md5 dovrebbero essere circa 2 GB di dati grezzi. –

Problemi correlati