Come memorizzare 7,3 miliardi di righe di dati di mercato (ottimizzati per essere letti)?


86

Ho un set di dati di 1 minuto di dati di 1000 azioni dal 1998, che totali intorno alle (2012-1998)*(365*24*60)*1000 = 7.3 Billionrighe.

La maggior parte (99,9%) delle volte eseguirò solo richieste di lettura .

Qual è il modo migliore per archiviare questi dati in un database?

  • 1 grande tavolo con 7,3 miliardi di righe?
  • 1000 tabelle (una per ogni simbolo di borsa) con 7,3 milioni di righe ciascuna?
  • qualche raccomandazione del motore di database? (Ho intenzione di utilizzare MySQL di Amazon RDS)

Non sono abituato a gestire set di dati così grandi, quindi questa è un'eccellente opportunità per imparare. Apprezzerò molto il tuo aiuto e consiglio.

Modificare:

Questa è una riga di esempio:

'XX', 20041208, 938, 43.7444, 43.7541, 43.735, 43.7444, 35116.7, 1, 0, 0

La colonna 1 è il simbolo di borsa, la colonna 2 è la data, la colonna 3 è il minuto, il resto sono prezzi di apertura-alto-basso-chiusura, volume e 3 colonne intere.

La maggior parte delle query sarà del tipo "Dammi i prezzi di AAPL tra il 12 aprile 2012 12:15 e il 13 aprile 2012 12:52"

Informazioni sull'hardware: ho intenzione di utilizzare Amazon RDS, quindi sono flessibile su questo


5
Descrivi la query tipica prevista
William Pursell

10
"Penso che dovresti usare MongoDB perché è su scala web".
ta.speot.is

8
Probabilmente vuoi una grande tabella, partizionata dal simbolo di borsa.
ta.speot

1
Il set di dati è enorme! Potresti voler cercare in giro per datamining e analisi per vedere cosa trovi.
Mike Purcell

2
E un "RDBMS standard" con una sola tabella non è sufficiente per questo? (Tratto solo milioni ma "funziona per me". Potresti anche provarlo e vedere. Ricordati di indicizzare / cluster / partizionare come richiesto.)

Risposte:


29

Parlaci delle query e del tuo ambiente hardware.

Sarei molto molto tentato di passare a NoSQL , usando Hadoop o qualcosa di simile, purché tu possa sfruttare il parallelismo.

Aggiornare

Va bene, perché?

Prima di tutto, nota che ho chiesto informazioni sulle domande. Non puoi - e certamente non possiamo - rispondere a queste domande senza sapere qual è il carico di lavoro. (Per coincidenza avrò presto un articolo su questo, ma non posso collegarlo oggi.) Ma la portata del problema mi fa pensare di allontanarmi da un grande vecchio database perché

  • La mia esperienza con sistemi simili suggerisce che l'accesso sarà sequenziale (elaborazione di una sorta di analisi di serie temporali) o data mining molto molto flessibile (OLAP). I dati sequenziali possono essere gestiti meglio e più velocemente in modo sequenziale; OLAP significa calcolare moltissimi indici, il che richiederà molto tempo o molto spazio.

  • Se stai facendo quelle che sono effettivamente grandi corse contro molti dati in un mondo OLAP, tuttavia, un approccio orientato alle colonne potrebbe essere il migliore.

  • Se si desidera eseguire query casuali, in particolare effettuare confronti incrociati, un sistema Hadoop potrebbe essere efficace. Perché? Perché

    • è possibile sfruttare meglio il parallelismo su hardware merceologico relativamente piccolo.
    • puoi anche implementare meglio un'elevata affidabilità e ridondanza
    • molti di questi problemi si prestano naturalmente al paradigma MapReduce.

Ma il fatto è che, finché non sappiamo del tuo carico di lavoro, è impossibile dire qualcosa di definitivo.


7
Quale vantaggio offre "NoSQL" qui? Perché non un unico grande tavolo in un RDBMS tradizionale ? (Con indici corretti, ecc.) Tutti dicono "NoSQL", "NoSQL", "NoSQL", ma ... perché ?

5
Devo dire che il mio suggerimento sarebbe anche un approccio NoSQL usando Apache Accumulo (questa è la preferenza personale). Il set di dati piccolo (per Accumulo) e il tipo di query richieste sembrano perfettamente adatti ad esso utilizzando il suo stack iteratore distribuito.
Binary Nerd

Grazie per la risposta estesa. Posso fare +1 su quello.

2
A volte alcuni dei commenti qui mi confondono. "-1 per l'utilizzo di un database in cui non ha senso?" L'intera risposta è contro un database tradizionale.
Charlie Martin

52

Quindi i database sono per situazioni in cui hai uno schema grande e complicato che cambia costantemente. Hai solo una "tabella" con una mano piena di semplici campi numerici. Lo farei in questo modo:

Preparare una struttura C / C ++ per contenere il formato del record:

struct StockPrice
{
    char ticker_code[2];
    double stock_price;
    timespec when;
    etc
};

Quindi calcolare sizeof (StockPrice [N]) dove N è il numero di record. (Su un sistema a 64 bit) Dovrebbero essere solo poche centinaia di GB e stare su un HDD da $ 50.

Quindi tronca un file a quella dimensione e mmap (su Linux, o usa CreateFileMapping su Windows) in memoria:

//pseduo-code
file = open("my.data", WRITE_ONLY);
truncate(file, sizeof(StockPrice[N]));
void* p = mmap(file, WRITE_ONLY);

Trasmetti il ​​puntatore mmaped a StockPrice * e fai un passaggio dei tuoi dati compilando l'array. Chiudi mmap e ora avrai i tuoi dati in un grande array binario in un file che può essere nuovamente mmapato in seguito.

StockPrice* stocks = (StockPrice*) p;
for (size_t i = 0; i < N; i++)
{
    stocks[i] = ParseNextStock(stock_indata_file);
}
close(file);

Ora puoi spostarlo di nuovo in sola lettura da qualsiasi programma ei tuoi dati saranno prontamente disponibili:

file = open("my.data", READ_ONLY);
StockPrice* stocks = (StockPrice*) mmap(file, READ_ONLY);

// do stuff with stocks;

Quindi ora puoi trattarlo proprio come un array di strutture in memoria. È possibile creare vari tipi di strutture di dati di indice a seconda delle "query". Il kernel si occuperà dello scambio dei dati su / dal disco in modo trasparente, quindi sarà incredibilmente veloce.

Se ti aspetti di avere un certo pattern di accesso (ad esempio una data contigua) è meglio ordinare l'array in quell'ordine in modo che raggiunga il disco in sequenza.


12
Spendi qualche centinaio per metterlo su SSD invece che su disco rigido. Le letture casuali sono circa cento volte più veloci. O spendi 10K in ram. Altre cento volte più veloce
Stephan Eggermont

1
@Andrew Tomazos grazie amico, questa è "la" risposta
Pavneet_Singh

1
StockPrice sizeof sarebbe char [4] = 4 byte int = 4 byte short = 2 byte float = 4 byte float = 4 byte float = 4 byte float = 4 byte float = 4 byte int = 4 byte int = 4 byte int = 4 byte ------------ 42 byte circa 306,6 miliardi di byte = ~ 285,5435013771057 GB di memoria ... buona fortuna con quello
ZagNut

3
@ZagNut: Se la tua implicazione è che hai bisogno di 300 GB di memoria fisica, allora non è corretto: mmap non copia l'intera cosa in memoria, la inserisce / estrae secondo necessità (allo stesso modo del file di scambio) .
Andrew Tomazos

35

Ho un set di dati di 1 minuto di dati su 1000 azioni [...] la maggior parte (99,9%) delle volte eseguo solo richieste di lettura .

Memorizzare una volta e leggere molte volte i dati numerici basati sul tempo è un caso d'uso denominato "serie temporale". Altre serie temporali comuni sono i dati dei sensori nell'Internet degli oggetti, le statistiche di monitoraggio del server, gli eventi dell'applicazione ecc.

Questa domanda è stata posta nel 2012 e da allora diversi motori di database hanno sviluppato funzionalità specifiche per la gestione delle serie temporali. Ho ottenuto ottimi risultati con InfluxDB , che è open source, scritto in Go e con licenza MIT.

InfluxDB è stato specificamente ottimizzato per archiviare ed eseguire query sui dati delle serie temporali. Molto più di Cassandra , che viene spesso pubblicizzata come ottima per memorizzare le serie temporali:

Velocità di query InfluxDB vs Cassandra

L'ottimizzazione per le serie temporali comportava alcuni compromessi. Per esempio:

Gli aggiornamenti ai dati esistenti sono un evento raro e gli aggiornamenti controversi non avvengono mai. I dati delle serie temporali sono prevalentemente dati nuovi che non vengono mai aggiornati.

Pro: limitare l'accesso agli aggiornamenti consente di aumentare le prestazioni di query e scrittura

Contro: la funzionalità di aggiornamento è notevolmente limitata

Nei benchmark open source ,

InfluxDB ha superato MongoDB in tutti e tre i test con un throughput di scrittura 27 volte maggiore, utilizzando 84 volte meno spazio su disco e offrendo prestazioni relativamente uguali in termini di velocità delle query.

Confronto tra influxDB e MongoDB requisiti di archiviazione su disco e compressione

Anche le domande sono molto semplici. Se le tue righe hanno questo aspetto <symbol, timestamp, open, high, low, close, volume>, con InfluxDB puoi memorizzare proprio questo, quindi eseguire facilmente query. Dì, per gli ultimi 10 minuti di dati:

SELECT open, close FROM market_data WHERE symbol = 'AAPL' AND time > '2012-04-12 12:15' AND time < '2012-04-13 12:52'

Non ci sono ID, chiavi e join da fare. Puoi fare molte aggregazioni interessanti . Non è necessario partizionare verticalmente la tabella come con PostgreSQL o contorcere lo schema in array di secondi come con MongoDB . Inoltre, InfluxDB si comprime molto bene, mentre PostgreSQL non sarà in grado di eseguire alcuna compressione sul tipo di dati che hai .


1
Esistono altri database di serie temporali come kdb +, m3db o VictoriaMetrics , che possono gestire facilmente trilioni di righe su un singolo nodo sotto carico di lavoro di produzione. Vedi github.com/VictoriaMetrics/VictoriaMetrics/wiki/…
valyala

@valyala: VictoriaMetrics sembra fantastico! Ho avuto numerosi problemi con InfluxDB da quando l'ho pubblicato; sebbene VictoriaMetrics non supporti affatto gli aggiornamenti :-(
Dan Dascalescu

17

Ok, quindi questo è un po 'lontano dalle altre risposte, ma ... mi sembra che se hai i dati in un file system (uno stock per file, forse) con una dimensione di record fissa, puoi ottenere i dati veramente facilmente: data una query per un particolare stock e intervallo di tempo, puoi cercare nel posto giusto, recuperare tutti i dati di cui hai bisogno (saprai esattamente quanti byte), trasformare i dati nel formato di cui hai bisogno (che potrebbe essere molto veloce a seconda del formato di archiviazione) e sei via.

Non so nulla dell'archiviazione Amazon, ma se non hai nulla come l'accesso diretto ai file, potresti fondamentalmente avere BLOB: dovresti bilanciare BLOB di grandi dimensioni (meno record, ma probabilmente leggendo più dati di quanti ne hai bisogno ciascuno time) con piccoli blob (più record che danno più overhead e probabilmente più richieste per ottenerli, ma ogni volta vengono restituiti meno dati inutili).

Successivamente aggiungi il caching - suggerirei di dare a diversi server diversi stock da gestire, ad esempio - e puoi praticamente servire solo dalla memoria. Se puoi permetterti abbastanza memoria su abbastanza server, ignora la parte "carica su richiesta" e carica tutti i file all'avvio. Ciò semplificherebbe le cose, a costo di un avvio più lento (che ovviamente influisce sul failover, a meno che non ci si possa permettere di avere sempre due server per un particolare stock, il che sarebbe utile).

Nota che non è necessario memorizzare il simbolo di borsa, la data o il minuto per ogni record, perché sono impliciti nel file che stai caricando e nella posizione all'interno del file. Dovresti anche considerare di quale precisione hai bisogno per ciascun valore e come archiviarlo in modo efficiente: hai fornito 6SF nella tua domanda, che potresti memorizzare in 20 bit. Memorizza potenzialmente tre interi a 20 bit in 64 bit di memoria: leggilo come long(o qualunque sia il tuo valore intero a 64 bit) e usa mascheramento / spostamento per riportarlo a tre numeri interi. Avrai bisogno di sapere quale scala usare, ovviamente, che potresti probabilmente codificare nei 4 bit di riserva, se non riesci a renderla costante.

Non hai detto come sono le altre tre colonne di numeri interi, ma se riuscissi a farla franca anche con 64 bit per quelle tre, potresti memorizzare un intero record in 16 byte. Sono solo ~ 110 GB per l'intero database, il che non è molto ...

EDIT: L'altra cosa da considerare è che presumibilmente le azioni non cambiano durante il fine settimana, o addirittura dall'oggi al domani. Se il mercato azionario è aperto solo 8 ore al giorno, 5 giorni alla settimana, hai bisogno solo di 40 valori a settimana invece di 168. A quel punto potresti finire con solo circa 28 GB di dati nei tuoi file ... il che suona molto più piccolo di quanto probabilmente stavi pensando in origine. Avere così tanti dati in memoria è molto ragionevole.

EDIT: Penso di aver perso la spiegazione del motivo per cui questo approccio si adatta bene qui: hai un aspetto molto prevedibile per gran parte dei tuoi dati: il ticker di borsa, la data e l'ora. Esprimendo il ticker una volta (come nome del file) e lasciando la data / ora interamente implicita nella posizione dei dati, stai rimuovendo un sacco di lavoro. È un po 'come la differenza tra a String[]e a Map<Integer, String>: sapere che l'indice dell'array inizia sempre da 0 e sale con incrementi di 1 fino alla lunghezza dell'array consente un accesso rapido e un'archiviazione più efficiente.


Anche in questo caso dipende da come utilizza i dati. Se la sua domanda è quella di estrarre un dato particolare su tutta la linea (per quanto riguarda i simboli di borsa), ciò comporterebbe la lettura di ogni file e l'avere codifiche di data specifiche per estrarre i dati corretti da ciascuno. Oppure, se vuole il titolo con le migliori prestazioni a settimana, sarebbe un incubo con questo tipo di configurazione con la necessità di leggere tutti i record, ordinare e confrontare. Senza tali informazioni, possiamo solo supporre che questo sia per l'archiviazione fissa, forse come DW in blocco che alimenterà un DW di report a un certo punto (fonte ETL).
Wolf5370

2
@ Wolf5370: Sì, abbiamo sicuramente bisogno di sapere quali saranno le query, ma abbiamo almeno qualche indicazione dalla domanda: "La maggior parte delle query sarà del tipo" Dammi i prezzi di AAPL tra il 12 aprile 2012 12:15 e 13 aprile 2012 12:52 ". Sarebbe bello sapere quali sarebbero le altre domande, nonché le relative frequenze e requisiti di prestazione.
Jon Skeet

@JonSkeet dipende davvero dal carico di lavoro, ma ho una certa conoscenza del dominio di questo tipo di sistema, e raramente è solo "selezionare un titolo in un intervallo": è molto più spesso "selezionare azioni in questo portafoglio in questo intervallo, calcola & beta; quindi prova questo elenco di possibili azioni e guarda cos'è & beta; ". Ecco perché ti spinge verso qualcosa di simile a OLAP.
Charlie Martin

2
@CharlieMartin: Beh, stavo solo seguendo quello che dice la domanda. Tuttavia, se in pratica riesci a ottenere tutto in memoria (su alcuni server), è comunque piuttosto semplice: chiedi a ciascun server le azioni pertinenti nel portafoglio, quindi metti insieme i risultati. Penso che il mio punto di vista sull'utilizzo degli aspetti noti dei dati (una volta al minuto, ma non nei fine settimana o durante la notte) sia ancora utile in termini di riduzione significativa della difficoltà di ottenere tutto in memoria.
Jon Skeet

Questa discussione mi ricorda la citazione di Fred Brooks, "La rappresentazione è l'essenza della programmazione" e i relativi problemi in "Programming Pearls" di Bentley.
CS

14

A quanto mi risulta, HDF5 è stato progettato specificamente con l'archiviazione di serie temporali dei dati di stock come potenziale applicazione. Fellow stacker hanno dimostrato che HDF5 è utile per grandi quantità di dati: cromosomi , fisica .


2
+1 per una soluzione specifica. Adoro, tuttavia, SQL DQL (per la maggior parte) e la flessibilità che offre ... non sono sicuro di cosa sia richiesto con HDF5 per uscire da una "vista gerarchica".

4

Ecco un tentativo di creare un Market Data Server in cima al database di Microsoft SQL Server 2012 che dovrebbe essere utile per l'analisi OLAP, un progetto open source gratuito:

http://github.com/kriasoft/market-data


Sì. Non sono sicuro che quel particolare progetto sia applicabile, ma suggerirei sicuramente all'OP di prendere in considerazione la struttura della tabella dei fatti OLAP o Data Warehousing, entrambi gli approcci (a volte usati insieme) sono progettati per affrontare questo tipo di dati di un numero molto elevato di righe. Tuttavia, dipende davvero dal tipo di analisi che intendono eseguire.
AaronLS

4

Innanzitutto, non ci sono 365 giorni di negoziazione all'anno, con i giorni festivi 52 nei fine settimana (104) = diciamo 250 x le ore effettive del giorno il mercato è aperto come qualcuno ha detto, e usare il simbolo come chiave primaria non è una buona idea poiché i simboli cambiano, usa un k_equity_id (numerico) con un simbolo (char) poiché i simboli possono essere come questo A, o GAC-DB-B.TO, quindi nelle tabelle dei dati delle informazioni sui prezzi, hai, quindi la tua stima di 7.3 miliardo è ampiamente sopra calcolato poiché sono solo circa 1,7 milioni di righe per simbolo per 14 anni.

k_equity_id k_date k_minute

e per la tabella EOD (che verrà visualizzata 1000 volte rispetto agli altri dati)

k_equity_id k_date

In secondo luogo, non memorizzare i dati OHLC per minuto nella stessa tabella DB e tabella EOD (fine giornata), poiché chiunque desideri guardare un pnf, o grafico a linee, su un periodo di un anno, non ha interesse per il by le informazioni minime.


3

Lascia che ti consigli di dare un'occhiata ad apache solr , che penso sarebbe l'ideale per il tuo problema particolare. Fondamentalmente, indicizzerai prima i tuoi dati (ogni riga è un "documento"). Solr è ottimizzato per la ricerca e supporta nativamente le query di intervallo sulle date. La tua richiesta nominale,

"Give me the prices of AAPL between April 12 2012 12:15 and April 13 2012 12:52"

si tradurrebbe in qualcosa di simile:

?q=stock:AAPL AND date:[2012-04-12T12:15:00Z TO 2012-04-13T12:52:00Z]

Supponendo che "stock" sia il nome del titolo e "date" sia un "DateField" creato dalle colonne "date" e "minute" dei dati di input durante l'indicizzazione. Solr è incredibilmente flessibile e non posso davvero dire abbastanza cose positive al riguardo. Quindi, ad esempio, se hai bisogno di mantenere i campi nei dati originali, puoi probabilmente trovare un modo per creare dinamicamente il "DateField" come parte della query (o del filtro).


Puoi anche utilizzare Amazon EC2 per configurare la tua istanza solr
aliasmrchips

3
SOLR funziona alla grande per la ricerca, ma è comunque necessario memorizzare i dati da qualche parte, al fine di popolare gli indici.
Mike Purcell

Vero. Presumo che Victor P abbia i dati da qualche parte e dovrà essere indicizzato. Ciò richiederà risorse aggiuntive ... Tuttavia, anche tutti gli approcci proposti lo fanno.
aliasmrchips

@aliasmrchips: Penso che l' approccio InfluxDB sia migliore: memorizza in modo efficiente (throughput elevato, compressione 80 volte migliore rispetto a Mongo) e interroga facilmente.
Dan Dascalescu

3

Penso che qualsiasi RDBMS principale lo gestirà. A livello atomico, una tabella con il partizionamento corretto sembra ragionevole (partizione basata sull'utilizzo dei dati se risolta - è probabile che sia un simbolo o una data).

Puoi anche esaminare la creazione di tabelle aggregate per un accesso più rapido al di sopra del livello atomico. Ad esempio, se i tuoi dati sono al giorno, ma spesso ricevi dati indietro a livello settimanale o addirittura mensile, questo può essere precalcolato in una tabella aggregata. In alcuni database questo può essere fatto tramite una vista memorizzata nella cache (vari nomi per diverse soluzioni DB - ma fondamentalmente è una vista sui dati atomici, ma una volta eseguita la vista viene memorizzata nella cache / rafforzata in una tabella temporanea fissa - che viene interrogata per query di corrispondenza successive Questo può essere rilasciato a intervalli per liberare memoria / spazio su disco).

Immagino che potremmo aiutarti di più con qualche idea sull'utilizzo dei dati.


3

È necessario confrontare le soluzioni lente con un semplice modello di memoria ottimizzato. Non compresso si adatta a un ram server da 256 GB. Un'istantanea si adatta a 32 K e la indicizzi solo in posizione su datetime e stock. Quindi puoi fare istantanee specializzate, poiché l'apertura di una spesso equivale alla chiusura della precedente.

[modifica] Perché pensi che abbia senso usare un database (rdbms o nosql)? Questi dati non cambiano e si inseriscono nella memoria. Questo non è un caso d'uso in cui un dbms può aggiungere valore.


In realtà, ci sono diversi motivi, non ultimo il fatto che se hai 256 GB di memoria sarebbe bello se ci fosse spazio per lo spazio temporaneo, il sistema operativo e così via. Poi ci sono problemi come il checkpoint, la registrazione e la tolleranza agli errori: una volta che inizi a calcolare i risultati intermedi, torni a dover gestire lo storage. Sono d'accordo che un RDBMS non sia la scelta migliore, ma è assolutamente necessario qualcosa di più intelligente di "caricare il big array in memoria".
Charlie Martin

checkpoint, registrazione e tolleranza ai guasti sono estremamente semplici per i dati quasi statici. Sembra la soluzione ideale per una soluzione in stile prevayler
Stephan Eggermont

Ancora una volta, senza una migliore conoscenza dell'applicazione non è possibile dirlo con certezza, ma in generale, l'applicazione non è statica come pensi, perché vuoi mantenere i set di risultati e perché stai facendo calcoli costosi con, ancora , checkpoint e risultati parziali precalcolati.
Charlie Martin

2

Se hai l'hardware, ti consiglio MySQL Cluster . Ottieni l'interfaccia MySQL / RDBMS con cui sei così familiare e ottieni scritture veloci e parallele. Le letture saranno più lente del normale MySQL a causa della latenza di rete, ma hai il vantaggio di poter parallelizzare query e letture a causa del modo in cui funzionano MySQL Cluster e il motore di archiviazione NDB.

Assicurati di avere abbastanza macchine MySQL Cluster e abbastanza memoria / RAM per ognuna di esse: MySQL Cluster è un'architettura di database fortemente orientata alla memoria.

O Redis , se non ti dispiace un'interfaccia valore-chiave / NoSQL per le tue letture / scritture. Assicurati che Redis abbia abbastanza memoria: è super veloce per letture e scritture, puoi eseguire query di base con esso (non RDBMS però) ma è anche un database in memoria.

Come altri hanno già detto, saperne di più sulle query che eseguirai ti aiuterà.


2

Si vorranno i dati memorizzati in una tabella / database a colonne . I sistemi di database come Vertica e Greenplum sono database a colonne e credo che SQL Server ora consenta tabelle a colonne. Questi sono estremamente efficienti perSELECT inserimento da set di dati molto grandi. Sono anche efficienti per importare set di dati di grandi dimensioni.

Un database colonnare gratuito è MonetDB .


1

Se il tuo caso d'uso è leggere righe semplici senza aggregazione, puoi utilizzare Aerospike cluster. È nel database di memoria con il supporto del file system per la persistenza. È anche ottimizzato per SSD.

Se il tuo caso d'uso richiede dati aggregati, scegli il cluster Mongo DB con partizionamento orizzontale dell'intervallo di date. I dati della morsa dell'anno del club possono essere contenuti in frammenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.