Database vs file flat per dati a cui si accede raramente

7

Riceviamo dati in tempo reale da oltre 1000 sensori, ognuno dei quali invia un punto dati ogni 10 secondi in media, il che equivale a circa 1 milione di righe di dati ogni giorno. Il nostro sistema offre agli utenti la possibilità di selezionare qualsiasi sensore e un intervallo di date e di scaricare i punti dati come file Excel.

Abbiamo visto che i nostri utenti sono per lo più interessati a dati che hanno meno di 30 giorni. I dati di più di 30 giorni sono probabilmente già stati scaricati. Solo circa l'1% delle nostre richieste di recupero dei dati proviene da dati vecchi di oltre 30 giorni. Tuttavia, non possiamo dire che questi dati siano totalmente inutili, perché i nostri utenti a volte vogliono scaricare dati che hanno ancora più di un anno. Eliminare i vecchi dati non è una possibilità.

Attualmente stiamo utilizzando il database MySQL per archiviare i dati e tutti i dati vengono archiviati in una singola tabella. La tabella ora ha oltre 60 milioni di righe. Usiamo SSD e abbiamo gli indici giusti grazie ai quali il recupero dei dati avviene ancora molto più velocemente.

Un esempio di query del database che usiamo per selezionare ogni minuto è:

SELECT
    data_value AS value, param_id AS param_id,
    data_timestamp AS ts,
FROM tbl_data_log
WHERE param_id in (?)
    AND data_timestamp >= ? AND data_timestamp <= ?
GROUP BY DATE(data_timestamp), HOUR(data_timestamp),
    MINUTE(data_timestamp),
    param_id
ORDER BY data_timestamp ASC

Attualmente, questa query impiega meno di 5 secondi per recuperare dati di oltre 30 giorni per un sensore specifico.

Man mano che più dati vengono archiviati in questa tabella, diventeranno più grandi, forse fino a 2 miliardi di righe nel prossimo anno (aggiungiamo anche più sensori ogni giorno). Non so come la prestazione della query sarebbe in quella fase. Per me, archiviare tutti questi dati in un database MySQL non sembra essere giusto, perché l'accesso è molto raro e il fatto che i dati siano indicizzati a più di 4 mesi non sembra necessario.

Un approccio a cui ho pensato è di avere solo 30 giorni di dati in MySQL e spostare i vecchi dati in file flat con una struttura di cartelle come /old_data/%YEAR%/%MONTH%/%DATE%/%PARAM_ID%.dat . In questo modo la dimensione dei nostri dati non diventerà ingestibile ma allo stesso tempo i dati sono ancora indicizzati sotto forma di file flat su disco.

L'approccio attuale è buono in scala? Lo spostamento di vecchi dati in file flat aiuta o no? La memorizzazione di tutti i dati in una singola tabella è corretta? Abbiamo bisogno di cambiare il nostro motore di database stesso? Si prega di dare i tuoi pensieri su questa architettura. Grazie mille in anticipo!

    
posta Ananth 19.11.2017 - 06:11
fonte

5 risposte

8

I motori di database sono in linea di principio progettati per far fronte a enormi quantità di dati molto più rapidamente rispetto ai file di dati non elaborati, quando è necessario accedere ai dati in modo non sequenziale.

Dici di avere tutti gli indici giusti sulla tua tabella per ottenere un accesso ottimizzato, quindi data_timestamp è certamente indicizzato. Tuttavia, vedo nel tuo esempio di query che usi:

GROUP BY DATE(data_timestamp), HOUR(data_timestamp),
    MINUTE(data_timestamp),
    param_id

Questo costringe il tuo motore di database a convertire il timestamp di ogni riga corrispondente alla data della query date, che sospetto sia molto tempo consumando .

Poiché suppongo che data e ora vengano usate congiuntamente nella tua applicazione, ti suggerirei di prendere in considerazione un po 'di denormalizzazione qui per facilitare il lavoro del database precomputing della data ( DATE type) e il tempo arrotondato al minuto (o TIME type o eventualmente a SMALLINT tra 0000 e 2359). Questo è 5 byte di overhead per riga. Crea un indice su di essi per accelerare la clausola GROUP BY .

Se ciò non è sufficiente, assicurati che il server sia dimensionato correttamente per la sua sfida relativa ai big data e controlla se il tuo DBMS è sufficientemente ben posizionato nei benchmark con altri DBMS.

Un lavoro attorno a te potrebbe anche prendere in considerazione l'utilizzo di due tabelle: una tabella attiva per gli ultimi 30 giorni e una seconda tabella con tutti i dati storici precedenti a 30 giorni. Alcuni lavori batch spostano quindi i dati in scadenza da una tabella all'altra.

    
risposta data 19.11.2017 - 14:59
fonte
4

Quando inserisci dati in grandi tabelle indicizzate ad alta velocità di trasmissione dati, la semplice indicizzazione della manutenzione può diventare il fattore limitante. I valori di ogni singola riga devono essere inseriti nei loro indici.

Quindi, limitare la dimensione del tavolo è una buona idea. Ma non avendo una tabella e cancellando le vecchie voci dalla tabella perché ciò significa un altro aggiornamento dell'indice, questa volta rimuovendo le voci dall'indice, che impiega circa lo stesso tempo dell'inserimento.

Rimuovi i dati dal DB eliminando / troncando le tabelle complete invece di eliminare le righe.

Non so se mySQL abbia qualcosa di simile alle Tabelle Partizionate di Oracle (fisicamente su più tabelle, logicamente accessibili come una singola / simile a una vista che mostra UNION delle partizioni). Se mySQL non ce l'ha, non c'è magia nera necessaria per farlo con un sacco di normali tabelle del database, una vista e un po 'di logica.

Con questo schema, penso che puoi mantenere i vecchi dati nel database senza compromettere le prestazioni delle query per le tipiche query del mese corrente.

    
risposta data 19.11.2017 - 15:45
fonte
2

Ecco un'idea. Inizia un nuovo database (file) ogni mese. L'unico problema che vedo è che potresti ottenere una query che copre due diversi mesi. Puoi semplicemente dire ai tuoi utenti di eseguire due query diverse se hanno bisogno di dati di diversi mesi, o creare un codice proxy in grado di dividere una query e ricucire i dati prima di restituirli (puoi farlo in VBA in modo che i tuoi utenti possano eseguirli dal loro libro di esercizi).

Il timestamp dovrebbe essere nel nome del database in modo che il database da indirizzare possa essere costruito dai parametri di query. Potrebbe essere necessario un catalogo che associa un nome di database a un server in modo da poter scalare su server diversi. Potresti creare i futuri database in anticipo, inserire alcuni dati fittizi e testarli con quelli.

Potresti voler comprimere (vecchi) database e decomprimerli appena prima di montarli, ed eliminare i database decompressi ogni notte o prima che venga indirizzato un altro vecchio database. Ciò darebbe ai tuoi utenti un notevole impatto sulle prestazioni quando si affrontavano vecchi dati, ma sarebbe comunque possibile e potresti risparmiare molto spazio.

    
risposta data 19.11.2017 - 10:09
fonte
1

Ecco un'altra idea. Poiché la struttura dei dati è così semplice, è possibile scrivere il proprio programma, definire una struttura / record per quello che è ora il record del database e utilizzare un flusso di file per accedere ai dati. Potresti avere un file al giorno o al mese.

Per qualsiasi query, salta nel tuo stream, guarda quale timestamp colpisci, se sei troppo lontano salta a metà nella parte in cui sai che i tuoi dati sono in eccetera. Dovresti trovare il record di partenza in pochi tentativi. Poi fai lo stesso per il record finale e assembla il tuo set di risultati da tutti i record tra.

Salverebbe il sovraccarico dell'RDBMS. Questa potrebbe essere la soluzione più efficiente (potresti anche combinarla con la decompressione al volo) ma sarebbe meno flessibile. Se i dati del tuo "punto dati" cambiassero un po ', probabilmente avresti più lavoro di quello che avresti con la soluzione MySql.

    
risposta data 19.11.2017 - 10:34
fonte
1

Puoi guardare:

  • REDIS set ordinato ZRANGEBYSCORE
    • link con chiave come ID sensore
    • link per lo script lua in questo contesto
    • scopri come raggrupparlo nei dati temporali
  • scylladb con eventualmente kairosdb
  • Un database di serie temporali scalabile come InfluxDB (clustering non open source qui)

Penso che nel tuo caso utilizzerei solo uno scylladb in cluster correttamente.

    
risposta data 21.11.2017 - 23:37
fonte

Leggi altre domande sui tag