Paginações 1.0: Coleções de séries temporais em cinco minutos
Avalie esse Artigo
Como alguém que curte medir constantemente a si mesmo e a tudo ao seu redor, estava ansioso para ver o MongoDB adicionar coleções de séries temporais dedicadas no MongoDB 5.0. Anteriormente, o MongoDB era ótimo para lidar com dados de série temporal, mas apenas se você estivesse preparado para escrever um código de inserção e atualização bastante complicado e usar um esquema complexo. Em 5.0, todo o trabalho duro é feito para você, incluindo muita otimização nos bastidores.
Trabalhar com dados de séries temporais traz alguns desafios técnicos interessantes para bancos de dados. Deixe-me explicar.
Dados de série temporal são onde temos vários pontos de dados relacionados que têm um tempo, uma fonte e um ou mais valores. Por exemplo, posso estar registrando minha velocidade na minha bicicleta e o gradiente da estrada, para ter a hora, a fonte (eu na bicicleta) e dois valores de dados (velocidade e gradiente). A fonte mudaria se fosse uma bicicleta diferente ou outra pessoa andando nela.
Os dados de série temporal não são simplesmente quaisquer dados que tenham um componente de data, mas especificamente dados em que queremos ver como os valores mudam durante um período de tempo e, portanto, precisamos comparar dados para uma determinada janela de tempo ou Windows. Na minha bicicleta, estou desacelerando com o tempo em um passeios? Ou minha velocidade varia com o gradiente da via?
Isso significa que, quando armazenamos dados de séries temporais, geralmente queremos recuperar ou trabalhar com todos os pontos de dados por um período de tempo ou com todos os pontos de dados por um período de tempo para uma ou mais fontes específicas.
Esses pontos de dados tendem a ser pequenos. Um tempo geralmente tem oito bytes, um identificador normalmente tem apenas (no máximo) uma dúzia de bytes e um ponto de dados geralmente é um ou mais números de ponto flutuante de oito bytes. Portanto, cada "registro" que precisamos armazenar e acessar talvez tenha 50 ou 100 bytes de comprimento.
É nesse ponto que lidar com dados de séries temporais se torna interessante - pelo menos, eu acho que é interessante. A maioria dos bancos de dados, incluindo o MongoDB, armazena dados em discos, e esses são lidos e escritos pelo hardware subjacente em blocos de normalmente 4, 8 ou 32 KB de cada vez. Devido a esses blocos de disco, as camadas acima dos discos físicos - memória virtual, sistemas de arquivos, sistemas operacionais e bancos de dados - também trabalham em blocos de dados. O MongoDB, como todos os bancos de dados, usa blocos de registros ao ler, escrever e armazenar em cache. Infelizmente, isso pode tornar a leitura e a gravação desses minúsculos registros de séries temporais muito menos eficientes.
Esta live mostra o que acontece quando esses registros são simplesmente inseridos em um banco de dados de uso geral, como o MongoDB ou um RDBMS.
À medida que cada registro é recebido, ele é armazenado sequencialmente em um bloco no disco. Para nos permitir acessá-los, usamos dois índices: um com o identificador de registro exclusivo, que é necessário para replicação, e outro com a origem e o carimbo de data/hora para nos permitir encontrar tudo para um dispositivo específico durante um período de tempo.
Isso é bom para escrever dados. Temos uma gravação sequencial rápida e podemos organizar as descargas de disco de blocos para obter uma velocidade de gravação muito alta.
A questão surge quando lemos. Para encontrar os dados sobre um dispositivo durante um período de tempo, precisamos buscar muitos desses pequenos registros. Devido à forma como foram armazenados, os registros que queremos estão espalhados por vários blocos de banco de dados e blocos de disco. Para cada bloco que temos que ler, pagamos uma multa de ter que ler e processar o bloco inteiro, usando o espaço de cache do banco de dados equivalente ao tamanho do bloco. Isso é muitos recursos de computação desperdiçados.
MongoDB 5.0 possui coleções de séries temporais especializadas e otimizadas para esse tipo de dados, que podemos usar simplesmente adicionando dois parâmetros ao criar uma collection.
1 db.createCollection("readings", 2 "time-series" :{ "timeField" : "timestamp", 3 "metaField" : "deviceId"}})
Não precisamos alterar o código que usamos para ler ou escrever. O MongoDB trata de tudo para nós nostrás dos palcos. Esta segunda animação mostra como.
Com uma coleção de séries temporais, o MongoDB organiza as gravações para que os dados da mesma fonte sejam armazenados no mesmo bloco, juntamente com outros pontos de dados de um ponto semelhante no tempo. Os blocos são limitados em tamanho (porque os blocos de disco também) e, assim que tivermos dados suficientes em um bloco, criaremos automaticamente outro. O ponto importante é que cada bloco cobrirá uma fonte e um intervalo de tempo, e temos um índice para cada bloco para nos ajudar a encontrar esse intervalo.
Isso significa que podemos ter índices muito menores, pois temos apenas um identificador exclusivo por bloco. Também temos apenas um índice por bloco, normalmente para a origem e o intervalo de tempo. Isso resulta em uma redução geral de centenas de vezes no tamanho do índice.
Não apenas isso, mas ao armazenar dados como esse, o MongoDB pode aplicar melhor compressão. Com o tempo, os dados de uma fonte não mudarão aleatoriamente, portanto, podemos comprimir as alterações em valores co-localizados. Isso resulta em uma melhoria no tamanho dos dados de pelo menos três a cinco vezes.
E quando passamos a lê-los, podemos lê-los várias vezes mais rápido, pois não precisamos mais ler dados, o que não é relevante para nossa query apenas para obter os dados que queremos.
E isso, em poucas palavras, são as coleções de séries temporais do MongoDB. Eu posso simplesmente especificar a hora e os campos de origem ao criar uma coleção e o MongoDB reorganizará meus dados de ciclo para torná-los três a cinco vezes menores, além de mais rápidos, de ler e analisar.