Cómo crear una base de datos de series temporales desde cero
(nakabonne.dev)-
Está escrita en Go, pero es en gran medida independiente del lenguaje
-
Los datos de series temporales son una colección de múltiples valores con marca de tiempo. Cada elemento es un punto de datos
→ Hay muchísimos. Su significado depende de que haya gran volumen. En muchos casos se capturan millones de veces por segundo
→ Append-only, ordenados cronológicamente, prioridad a los datos recientes
→ Lectura masiva por unidades de tiempo específicas
→ High Cardinality (el tamaño del conjunto es extremadamente grande)
→ En la mayoría de los casos se leen y usan datos recientes
-
Se desarrolló en Go la librería del motor de base de datos TStorage, enfocada principalmente en cargas con muchas escrituras, como reflejo de las series temporales
-
Modelo de datos
→ Modelo de datos lineal
→ Particiona los puntos de datos por unidad de tiempo
→ Cada partición funciona como una DB separada e independiente que contiene todos los datos dentro de ese intervalo de tiempo
→ Se puede modificar para que solo la head y la siguiente partición se guarden en el heap como particiones en memoria
→ Para evitar pérdida de datos, se escribe en el WAL (Write Ahead Log) antes de escribir realmente
→ Los datos de las particiones anteriores se guardan en disco como un solo archivo. Las particiones en disco son de solo lectura
- Partición en memoria
→ La lista de puntos de datos se representa en el heap como un arreglo (similar a un slice de Go)
→ Debido a latencia y sincronización, el out-of-order ocurre con frecuencia. Si está dentro de la misma partición, se puede reordenar al guardar mediante buffering; si está en una partición distinta, se puede agregar después de una partición anterior que no sea la head
→ Guarda exactamente los mismos datos que realmente se registran en el WAL, para poder recuperarse incluso en caso de error
- Partición en disco
→ Guarda los metadatos y los datos reales comprimidos en un directorio por partición (una versión reducida de Prometheus V3 Storage)
→ Formato de datos Memory-Mapped (el kernel puede cachearlo con mmap)
→ Los metadatos forman un índice en formato JSON
- La codificación de datos, expresada como tuplas de timestamp y value, usa el método de codificación propuesto en el paper Gorilla de Facebook
→ timestamp y value se codifican con métodos distintos
→ timestamp usa un valor unsigned 64-bit integer con codificación Delta-of-delta
✓ Codificación Delta: método que registra solo la diferencia entre el valor anterior y el actual
✓ Codificación Delta-of-Delta: como normalmente ocurre en intervalos de tiempo determinados, registra solo el delta del delta
✓ Como se codifica con longitud variable, Delta-of-Delta usa el menor espacio
→ values usa valores signed 64-bit floating-point con codificación XOR
✓ El primer valor se guarda tal cual
✓ Si al hacer XOR con el siguiente valor el resultado es 0, significa que es igual al anterior, así que solo se guarda un bit 0
✓ Si no es 0, se calcula con base en los demás bits (Meaningful Bit)
✓ Se calculan los ceros al inicio y al final; si la cantidad de ceros es la misma, se guarda 0 y solo los bits significativos; si es distinta, se guarda la cantidad de leading zeros, la cantidad de Meaningful Bit y los bits mismos
Aún no hay comentarios.