[Python] Python, redis e bottleneck

Pietro Battiston me a pietrobattiston.it
Mar 17 Dic 2013 16:37:07 CET


Il giorno mar, 17/12/2013 alle 00.38 +0100, Enrico Bianchi ha scritto:
> On 12/16/2013 01:22 PM, Pietro Battiston wrote:
> > Nel mio scenario, se dovessi (costretto con le spalle al muro)
> > sostituire Redis lo sostituirei con un dizionario Python, che potrebbe
> > aumentare un po' l'efficienza, a costo però di costringermi a legare i
> > dati ad un processo specifico.
> Per me stai continuando a sbagliare strumento. Redis e` un database 
> NoSQL di tipo key value con qualche struttura di gestione semplice del 
> dato, mentre tu parli di dizionari e JSON. Con queste premesse, e` molto 
> piu` conviente orientarsi su di un database di dipo document store, che 
> permettono tra l'altro la navigabilita` del documento. Sistemi adatti 
> sono quindi MongoDB, Cassandra (un po' meno), CouchDB, OrientDB e, non 
> ultimo PostgreSQL (il datatype JSON e` completamente navigabile). A 
> questo punto ti consiglio di valutare e di provare uno dei sistemi che 
> ti ho appena citato, indubbiamente saranno molto piu` adatti di Redis 
> per quello che ti prefiggi
> 


È assolutamente verosimile che mi sfugga qualcosa. Ma io non ho
_oggetti_ json. Ho scoperto cos'è un json un paio di settimane fa su
Wikipedia, semplicemente perché è l'unico mezzo - secondo me imperfetto
- che ho trovato per fare il dump di database Redis per ricaricarlo in
seguito.

Non sono stato a dare i dettagli dei dati che uso perché sono di diverse
tipologie. Ma in generale sono dati estremamente semplici - in alcuni
casi ad ogni chiave è associata una breve stringa, in altri una lista di
brevi stringhe, in altri un piccolo dizionario i cui valori sono brevi
stringhe (insomma, tutti tipi perfettamente supportati da Redis). Ad
esempio un set di dati che utilizzo è la descrizione di una rete. Quindi
la struttura base è un semplice dizionario

{ "elemento1" : ["elemento53", "elemento114", "elemento54"],
  "elemento2" : ["elemento1", "elemento32"],
... }

Io ho bisogno di rispondere in modo più veloce possibile alla domanda "a
chi è collegato elementox?". Quindi in particolare ho bisogno che questo
dizionario sia costantemente in RAM (e siccome accedo a molti elementi,
ma poche volte ad ognuno, non mi basta sapere che il caching li tiene in
RAM dopo il primo accesso).

Qui si chiude il problema 1. Qual'è la soluzione migliore? A me sembrava
di capire "Redis". Ho visto¹ che con un filesystem tempfs si può
utilizzare mongoDB in RAM, e presumo che la tecnica sia adattabile a
tutti gli altri DB (no)SQL che hai menzionato. Ma non mi è chiaro quale
sarebbe il guadagno

Veniamo al problema 2: dopo che ho fatto tutte le analisi che devo fare
sul dizionario tipo quello descritto sopra, devo spostare la mia
attenzione ad un altro dizionario. Diciamo che la dimensione di ognuno
di questi dizionari è dell'ordine di grandezza di 1-2 GB, e di RAM
disponibile, inclusa quella che uso per il sistema, ne ho 5 GB. Quindi:
faccio il flush del database Redis, carico la descrizione del nuovo
dizionario.

Funzionare funziona, ma l'operazione di caricamento mi prende 4 minuti
(e mi ha spinto, per fare economia di RAM, a scrivere il parser json
incrementale a cui ho accennato in un'altra mail¹). Quindi mi domandavo
semplicemente se ci fosse un modo migliore.

Una soluzione ai problemi 1 e 2 dovrebbe essere qualcosa di efficiente
quanto Redis ma a cui io possa dire "ora voglio lavorare su questo set
di dati - caricalo in memoria", "ora questo set di dati non mi serve
più". Ma la priorità assoluta è la velocità con i dati che ho in
memoria. Se poi posso abbassare i tempi che devo aspettare per
caricarli, tanto meglio.

Se poi riuscissi a capire, a prescindere da tutto ciò, perché
l'operazione di riempire un database Redis da un dump json non utilizzi
al 100% né CPU né disco né RAM, la mia curiosità sarebbe soddisfatta. È
un problema hardware di bandwidth tra RAM e CPU? È la gestione dei
socket da parte del sistema (Linux, per la cronaca) che impiega la CPU
per il resto del tempo?
Per la cronaca: avevo detto che se utilizzo Redis tramite socket unix
invece che tramite TCP-IP, l'utilizzo della CPU da parte di Python passa
dal 70% circa all'80% circa... sì, ma mi sono anche accorto che alla
fine per fare la stessa operazione ci mette di più!

ciao

Pietro

¹
http://edgystuff.tumblr.com/post/49304254688/how-to-use-mongodb-as-a-pure-in-memory-db-redis-style
² http://pietrobattiston.it/jsaone




Maggiori informazioni sulla lista Python