Abbiamo eseguito un benchmark di Neo4j, FalkorDB e Memgraph su un grafo sintetico derivato da 120.000 recensioni di prodotti Amazon (381.000 nodi, 804.000 archi). Abbiamo eseguito 12 modelli di query con 1.000 misurazioni ciascuno, testato l'ingestione con 6 dimensioni di batch, sostenuto un carico simultaneo per 60 secondi con un massimo di 32 thread e misurato l'impatto sulla memoria, sull'avvio a freddo, sul carico di lavoro misto e sull'indice.
FalkorDB ha offerto una velocità di elaborazione superiore a Neo4j e Memgraph con 8 thread.
Risultati del benchmark del database a grafo
Throughput simultaneo
QPS (query al secondo) misura quante query di lettura il database risponde al secondo sotto un carico multi-thread sostenuto. Ogni test dura 60 secondi. Un valore più alto è migliore.
Latenza della query (p50)
p50 è la latenza mediana: metà di tutte le query vengono completate più velocemente di questo valore. Un valore inferiore è migliore.
- Ricerca puntuale: recupera un singolo nodo tramite ID. Le tabelle hash Redis di FalkorDB eseguono ricerche in memoria con complessità O(1), circa 3 volte più veloci.
- Attraversamento: Percorso da un nodo ai suoi vicini (1 salto) o ai vicini dei vicini (2 salti). FalkorDB esegue il percorso a 2 salti in 2,9 volte più velocemente.
- Aggregazione: Conta le recensioni per marca, calcola la media delle valutazioni in stelle.
- Filtra + scansiona: Filtra le recensioni in base alla valutazione in stelle sull'intero set di dati.
Flusso di ingestione
La velocità di elaborazione delle recensioni misura quante recensioni al secondo il database è in grado di scrivere. Ogni punto sul grafico rappresenta una diversa dimensione del batch: quante recensioni vengono raggruppate in una singola query. Un valore più alto indica prestazioni migliori.
Con una dimensione del batch pari a 1, Memgraph è in testa (1.427/s). All'aumentare della dimensione del batch, FalkorDB scala rapidamente e supera Memgraph intorno al batch 500. Neo4j si stabilizza a circa 10.600/s indipendentemente dalla dimensione del batch. Al batch 5.000, FalkorDB raggiunge 22.784/s, 77 volte la sua prestazione con batch 1.
Puoi leggere ulteriori informazioni sulla nostra metodologia di benchmarking per database a grafo .
Principali risultati
FalkorDB raggiunge 6.693 QPS con 8 thread e Neo4j 6.7x.
Le strutture dati in memoria e il ciclo di eventi di Redis consentono di combinare query a bassa latenza con un elevato parallelismo. Dopo 8 thread, il throughput si stabilizza perché il core single-thread di Redis rappresenta il limite massimo. Neo4j raggiunge il picco a 16 thread (1.010 QPS) per poi diminuire a 32 (927 QPS), il che indica una contesa tra i thread.
FalkorDB si avvia a freddo in 1,1 ms, 82 volte più veloce di Neo4j
Neo4j impiega 90 ms per accettare la sua prima query dopo un riavvio. La prima query di riscaldamento viene eseguita in 274 ms, poi occorrono circa 3 query per stabilizzarsi a 34 ms. FalkorDB è pronto in 1,1 ms, con la prima query a 0,4 ms. In un'architettura a microservizi o serverless, dove i pod scalano verticalmente, questa differenza è significativa.
Indici: differenza di 1.700x su Neo4j, ~1x su FalkorDB
Senza indici, la query deep_feature_products di Neo4j ha impiegato 293 ms. Con gli indici, 0,17 ms. Si tratta di una differenza di 1.712 volte. Memgraph ha mostrato una sensibilità simile (da 160 a 898 volte a seconda della query). I risultati di FalkorDB sono rimasti pressoché invariati con o senza indici perché le tabelle hash di Redis funzionano già come indici impliciti.
Memoria: 415 MB contro 2.668 MB per lo stesso grafico
- Memgraph: 415 MB
- FalkorDB: 496 MB
- Neo4j: 2.668 MB (memoria heap JMX utilizzata)
La JVM di Neo4j prealloca 4 GB all'avvio, quindi la sua memoria a livello di processo (VmRSS) è sempre di circa 5,2 GB, indipendentemente dall'effettivo utilizzo dei dati. La metrica rilevante è quella relativa all'heap JMX. Il picco di 2,7 GB è il valore da utilizzare per la pianificazione della capacità.
Neo4j ha vinto l'aggregazione più pesante
FalkorDB ha registrato la latenza più bassa in 11 delle 12 query. L'eccezione è stata agg_feature_sentiment (raggruppamento per sentiment con filtro), dove l'ottimizzatore di query di Neo4j ha prodotto un piano di esecuzione migliore: 131 ms contro i 152 ms di FalkorDB.
Carico di lavoro misto (80% lettura, 20% scrittura)
8 thread, 60 secondi, zero errori su tutti e tre i database:
- FalkorDB: 50.223 operazioni (837 query al secondo)
- Neo4j: 44.256 operazioni (738 query al secondo)
- Memgrafo: 28.040 operazioni (467 QPS)
Le operazioni di scrittura non hanno compromesso in modo significativo le prestazioni di lettura su nessuno di essi.
Architetture in questo benchmark
Ogni database è dotato di una propria interfaccia utente di gestione. Questi screenshot mostrano lo stesso set di dati (16.127 nodi, 24.318 archi) caricato in tutti e tre, eseguendo la stessa query di attraversamento COMPARED_WITH.
FalkorDB
FalkorDB è un modulo per grafi basato sul database chiave-valore in memoria di Redis. Le query sono in OpenCypher, ma alla base ci sono le tabelle hash di Redis. Ecco perché le ricerche puntuali si attestano tra 0,044 e 0,048 ms.
Gli altri due database in questo benchmark hanno registrato prestazioni 2-3 volte superiori sulle stesse query. Il compromesso è che il core a singolo thread di Redis implica che la velocità di elaborazione simultanea smette di scalare oltre gli 8 thread.
Neo4j
Neo4j viene eseguito sulla JVM. La compilazione JIT significa che le query ripetute diventano più veloci nel tempo (riscaldamento: 274 ms -> 34 ms). Le pause del garbage collector influiscono sulla latenza di coda, ma vengono intercettate dalla rimozione degli outlier IQR. L'ottimizzatore di query gestisce bene i piani di aggregazione complessi, ed è da qui che deriva il vantaggio di agg_feature_sentiment. Il costo è rappresentato dalla preallocazione di 4 GB di heap e dall'overhead del garbage collector.
Memgraph
Memgraph è scritto in C++. Nessun overhead della JVM. 415 MB per l'intero dataset, il più basso dei tre. Il più veloce negli inserimenti singoli (1.427/s) grazie al minimo overhead per query. Tuttavia, è inferiore in termini di throughput simultaneo (picco di 684 QPS). Compatibile con Bolt, quindi funziona con il driver Neo4j.
metodologia di benchmark per database a grafo
Ambiente
- RunPod 8 vCPU (AMD EPYC x86_64), 32 GB di RAM, Ubuntu 24.04 LTS
- Installazione nativa, senza Docker. Tutti e tre i database sulla stessa macchina, connessioni in locale.
- Python 3.12.3. Sessioni persistenti per test a singolo thread, sessioni per chiamata da un pool di connessioni per test multi-thread.
Dati
- 120.000 recensioni sintetiche generate da distribuzioni Zipf (marchi, caratteristiche) e Poisson (entità, relazioni), seed fisso=42.
- 6 tipi di nodi: Recensione, Prodotto, Recensore, Marchio, Funzionalità, Categoria
- 8 tipi di archi: ABOUT, WRITTEN_BY, IN_CATEGORY, MADE_BY, HAS_POSITIVE, HAS_NEGATIVE, MENTTIONS, COMPARED_WITH
Domande
12 modelli Cypher in 5 categorie: ricerca punti (3), attraversamento a 1 salto (2), attraversamento a 2 salti (2), aggregazione (3), filtro (1), scansione completa (1). Ogni query parametrizzata viene eseguita con 10 diversi valori di parametro, 100 volte ciascuno, per 1.000 misurazioni per query per database.
I parametri vengono campionati dall'intero spazio degli ID utilizzando la selezione ponderata secondo Zipf, in modo da testare sia gli elementi più comuni che quelli più rari.
Tre esempi:
Ricerca punto : recupera un singolo nodo tramite ID indicizzato
Attraversamento a 2 salti : Percorso da un marchio, attraverso i suoi prodotti, fino alle relative recensioni.
Aggregazione : scansione completa del grafo con unione e calcolo multi-hop
Misurazione
- Tempistiche:
time.perf_counter_ns(), 500 query di riscaldamento, 100 esecuzioni per query minimo - Statistiche: 10.000 campioni bootstrap, intervallo di confidenza al 95%, rimozione degli outlier IQR (fattore 3,0x). Vengono riportati sia i dati grezzi che quelli filtrati.
- Memoria: Neo4j tramite heap JMX utilizzato (VmRSS è irrilevante perché la JVM prealloca), FalkorDB tramite Redis
used_memory_rss, Memgraph tramite/proc/{pid}/statusVmRSS.
Equità
- Stessa dimensione del pool di connessioni, stesso numero di cicli di riscaldamento, stesse query Cypher, stessi dati e stessa macchina per tutti e tre i database.
- Test di concorrenza: carico sostenuto di 60 secondi su 1, 2, 4, 8, 16 e 32 thread con un pool_size fisso pari a 32. Composizione delle query: 40% attraversamento a 1 hop, 30% attraversamento a 2 hop, 20% aggregazione, 10% attraversamento a 3 hop.
Database testati
Limitazioni
Macchina singola, nodo singolo per database. Nessun benchmark distribuito o in cluster. Il clustering Neo4j Enterprise e la replica Memgraph sono esclusi dall'ambito di applicazione.
Dati sintetici con distribuzioni derivate da recensioni reali di Amazon. Potrebbero non corrispondere a specifici modelli di carico di lavoro di produzione.
Non misurati: persistenza/ripristino su disco, ricerca full-text, algoritmi sui grafi (PageRank, rilevamento delle comunità) e carichi di lavoro con elevato numero di scritture (>50% di scritture).
Driver diversi: Neo4j e Memgraph utilizzavano il driver Python di Neo4j, mentre FalkorDB utilizzava il proprio. La differenza di overhead era inferiore a 0,5 ms nei test a singolo thread.
Conclusione
FalkorDB ha vinto 11 query su 12, ha raggiunto 6.693 QPS e si è avviato a freddo in 1,1 ms. Per i carichi di lavoro su grafi con un elevato numero di letture, è l'opzione più veloce in questo benchmark. Memgraph è l'opzione più efficiente in termini di memoria (415 MB contro 2,7 GB). Neo4j offre l'ecosistema più ampio: RBAC, clustering, monitoraggio e un ottimizzatore di query che gestisce piani di aggregazione complessi meglio di entrambe le alternative.
L'architettura determina il limite massimo. Cluster distribuiti, grafi con oltre un milione di nodi e carichi di lavoro con un'elevata intensità di scrittura sono le prove che potrebbero rimescolare queste classifiche.
Sii il primo a commentare
Il tuo indirizzo email non verrà pubblicato. Tutti i campi sono obbligatori.