Diseño de esquemas para datos de series temporales

En esta página, se describen los conceptos, los patrones y ejemplos del diseño de esquemas para almacenar datos de series temporales en Cloud Bigtable. Antes de leer esta página, deberías familiarizarte con la descripción general de Cloud Bigtable y con cómo diseñar tu esquema.

Cuando mides algún elemento y registras la hora junto con la medición, creas una serie temporal. Estas se encuentran en muchas situaciones, como las siguientes:

  • Cuando miras el trazado del uso de memoria en tu computadora debido a que está funcionando lenta, lo que ves es una serie temporal.

  • Cuando revisas la temperatura en un informe de las noticias, miras una serie temporal.

  • Si eres un comerciante de divisas y debes graficar los movimientos de los promedios de precios en 5, 10 y 30 días para USD o JPY, miras una serie temporal.

También son muy importantes en las siguientes situaciones:

  • Las series temporales nos ayudan a optimizar el uso de recursos, limitar el uso de energía, minimizar el impacto ambiental y reducir los costos.

  • Las series temporales nos ayudan a identificar tendencias en los datos, lo que nos permite demostrar de forma concreta qué ocurrió en el pasado y hacer estimaciones informadas sobre lo que sucederá en el futuro.

  • Las series temporales respaldan parte del aprendizaje automático y los análisis complejos en campos como los servicios financieros, las ventas minoristas, los seguros, la física y la química.

En esta guía, se ofrecen estrategias detalladas y una explicación para almacenar y consultar datos de series temporales en Cloud Bigtable.

Series temporales y Cloud Bigtable

Almacenar datos de series temporales en Cloud Bigtable es un ajuste natural. Cloud Bigtable almacena los datos como columnas no estructuradas en filas; cada fila tiene una clave de fila, y se ordenan de forma lexicográfica.

Existen dos formas comunes para recuperar datos de Cloud Bigtable:

  • Puedes indicar una clave de fila a fin de ver una sola fila.
  • Puedes indicar un rango de claves de fila a fin de ver varias filas.

Estos métodos son ideales para consultar datos de series temporales, ya que a menudo se consultan datos de un intervalo de tiempo determinado (por ejemplo, todos los datos del mercado del día o las estadísticas del servidor de CPU de los últimos 15 minutos). Por lo tanto, en cuanto a las funciones, Cloud Bigtable es una muy buena herramienta para consultar series temporales.

Sin embargo, siempre puede haber aspectos negativos. En Cloud Bigtable, el lado negativo es que el esquema de los datos (la estructura de columnas y claves de fila) debe diseñarse cuidadosamente. Un buen esquema genera un excelente rendimiento y escalabilidad, mientras que uno malo puede provocar un rendimiento deficiente del sistema. Sin embargo, ningún diseño ofrece los mejores resultados en todos los casos prácticos.

En el resto de este artículo, se presentan varios patrones para diseñar esquemas en Cloud Bigtable. Puedes usarlos a fin de diseñar un esquema ideal para tus casos prácticos. Después de ver una enumeración de los patrones para el diseño de esquemas y su explicación, puedes usar los ejemplos de los siguientes casos prácticos para obtener más información:

  • Datos del mercado financiero
  • Métricas del servidor (por ejemplo, CPU, memoria y uso de red)
  • Medidores inteligentes de energía (parte de la “Internet de las cosas” o IoT)

Patrones de diseño de esquemas para las series temporales

Los patrones de diseño de esquemas para almacenar series temporales en Cloud Bigtable se ajustan a las siguientes categorías:

  • Patrones generales
  • Patrones para el diseño de claves de fila
  • Patrones para el diseño de columnas de datos

Patrones generales

Usa nombres cortos pero significativos

Cuando transfieres datos desde Cloud Bigtable, también transfieres metadatos, incluidos los siguientes:

  • La clave de fila
  • La familia de columnas, un identificador que se usa para agrupar las columnas relacionadas
  • El calificador de columnas, un nombre único dentro de la familia

Por lo tanto, es importante elegir nombres significativos que sean lo más cortos posible, ya que el tamaño de cada nombre contribuye a la sobrecarga del almacenamiento y la RPC. Por ejemplo, en lugar de usar CELLPHONE_NUMBER como calificador de columna, podrías usar CELL que es más breve pero significativo.

Patrones para el diseño de claves de fila

Usa tablas largas y angostas

Una tabla larga y angosta tiene una menor cantidad de eventos por fila, incluso podría ser solo uno, mientras que una tabla corta y ancha tiene una gran cantidad de eventos por fila. Como explicaremos en un momento, las tablas largas y angostas son mejores para los datos de series temporales.

Por ejemplo, supongamos que mides la temperatura de tu huerta todas las mañanas. Si, a raíz de esto, decides que una fila por día es suficiente, tu tabla será larga y angosta. Ten en cuenta que las marcas de tiempo no son el primer elemento de la clave de fila. Como explicaremos a continuación, usar una marca de tiempo como el primer elemento de una clave de fila puede provocar muchos problemas.

Clave de fila Datos de la columna
VEGGIEGARDEN#20150301 DAILY:TEMP:60.4
VEGGIEGARDEN#20150302 DAILY:TEMP:61.2
VEGGIEGARDEN#20150303 DAILY:TEMP:61.0
VEGGIEGARDEN#20150304 DAILY:TEMP:65.1
VEGGIEGARDEN#20150305 DAILY:TEMP:62.2
VEGGIEGARDEN#20150331 DAILY:TEMP:60.4

Por otro lado, supongamos que deseas visualizar la temperatura por mes. En ese caso, una fila por mes sería una forma adecuada. En el siguiente ejemplo, se muestra la tabla corta y ancha que obtendrías:

Clave de fila Datos de la columna
VEGGIEGARDEN#20150301 TEMP:1:60.4 TEMP:2:61.2 TEMP:3:61.0 TEMP:4:65.1 TEMP:5:62.2 TEMP:31:60.4

Por lo general, se recomienda usar tablas largas y angostas para las series temporales. Esto se debe a dos motivos: almacenar un evento por fila facilita la ejecución de consultas en los datos. Si se almacenan muchos eventos por fila, es más probable que el tamaño total de la fila supere el máximo recomendado (consulta Las filas pueden ser grandes, pero no demasiado).

Con fines de optimización, puedes usar tablas cortas y anchas, pero debes limitar la cantidad de eventos en ellas. Por ejemplo, si usualmente debes recuperar los eventos de todo un mes, la tabla de temperatura de arriba sería una optimización razonable: el tamaño de la fila se restringe según la cantidad de días del mes.

Usa filas en lugar de versiones de columnas

En Cloud Bigtable, las columnas pueden tener versiones con marcas de tiempo. Por lo tanto, en teoría, es posible almacenar una serie temporal como un conjunto de versiones de una columna. Por ejemplo, si quisieras registrar el precio de cierre de las acciones de ZXZZT por día, podrías tener una sola columna con una versión con marca de tiempo para cada día:

Clave de fila Datos de la columna
ZXZZT STOCK:PRICE (V1 03/01/15):558.40 STOCK:PRICE (V2 03/02/15):571.34 STOCK:PRICE (V3 03/03/15):573.64 STOCK:PRICE (V4 03/04/15):573.37 STOCK:PRICE (V5 03/05/15):575.33

Sin embargo, esta no es la mejor forma de almacenar los datos.

De forma predeterminada, usa filas nuevas en lugar de versiones de columnas. Usar varias filas, con solo una versión de un evento en cada una, es la forma más simple de representar, comprender y consultar tus datos.

Se pueden usar versiones de una columna cuando el caso práctico es enmendar un valor cuyo historial sea importante. Por ejemplo, supongamos que hiciste unos cálculos basados en el precio de cierre de ZXZZT, y que los datos se ingresaron de manera incorrecta, como 559.40 en lugar de 558.40. En esta situación, podría ser importante conocer el historial del valor en caso de que el valor incorrecto haya provocado otros errores de cálculo.

Considera tus consultas en el momento de diseñar la clave de fila

Cuando Cloud Bigtable almacena filas, las ordena según sus claves de fila en orden lexicográfico. Solo hay un índice por tabla, que es la clave de fila. Las consultas que acceden a una sola fila, o a un rango contiguo de filas, se ejecutan con rapidez y efectividad. Todas las otras consultas generan análisis de la tabla completa, lo que puede tardar mucho más. Un análisis completo de la tabla es una revisión de cada fila de la tabla. En Cloud Bigtable, podrías llegar a almacenar muchos petabytes de datos en cada tabla, por lo que el rendimiento de un análisis completo solo va a empeorar a medida que el sistema crezca.

Por ejemplo, imagina una tabla en la que se almacenen las puntuaciones de los jugadores de un videojuego y que tiene el siguiente diseño.

Clave de fila Datos de la columna
LoL#20150301 GAME:PLAYER:Corrie GAME:WIN:false GAME:KDA:4.25
LoL#20150302 GAME:PLAYER:Jo GAME:WIN:true GAME:KDA:7.00
LoL#20150302 GAME:PLAYER:Sam GAME:WIN:true GAME:KDA:7.00
LoL#20150303 GAME:PLAYER:Corrie GAME:WIN:true GAME:KDA:9.50
Starcraft#20150303 GAME:PLAYER:Eriko GAME:WIN:true GAME:KDA:6.00

Supongamos que quieres consultar estos datos para responder la pregunta “¿Cuántas partidas de LoL ganó Corrie en marzo?”. Con el esquema de arriba, deberás analizar la mayor parte de la tabla para responderla. Por el contrario, si diseñas la tabla como se muestra a continuación, podrías responder esta pregunta con solo recuperar un rango específico de claves de fila:

Clave de fila Datos de la columna
LoL#Corrie#20150301 GAME:WIN:false GAME:KDA:4.25
LoL#Corrie#20150303 GAME:WIN:true GAME:KDA:9.50
LoL#Jo#20150302 GAME:WIN:true GAME:KDA:7.00
LoL#Sam#20150302 GAME:WIN:true GAME:KDA:7.00
Starcraft#Eriko#20150303 GAME:WIN:true GAME:KDA:6.00

Elegir una clave de fila que facilite las consultas comunes es fundamental para el rendimiento general del sistema. Enumera tus consultas, ponlas en orden de importancia y diseña claves de fila que funcionen con ellas.

¿Qué hacer en una situación donde no haya una clave de fila perfecta? Por ejemplo, supongamos que las consultas de todas las partidas de LoL de marzo y las partidas de LoL que Corrie jugó durante marzo tienen el mismo nivel de importancia. El esquema anterior nos permitiría consultar por las partidas de LoL de Corrie durante marzo, pero no nos serviría para ver todas las partidas de LoL durante marzo. Lo mejor que podrías hacer es consultar por todas las partidas de LoL y, luego, filtrar solo las de marzo. Existen dos formas de solucionar este problema:

Desnormalización

  • Usa dos tablas, cada una con una clave de fila adecuada para una de las consultas. Esta es una buena solución, ya que nos permite tener un sistema sólido y escalable.

Consulta y filtro

  • Mantén el esquema anterior y quédate con una consulta (todas las partidas de LoL durante marzo) con bajo rendimiento debido a que filtras muchas filas. Esta no es una buena solución, porque crea un sistema menos escalable que podría deteriorarse fácilmente a medida que el uso aumente.

Asegúrate de que tu clave de fila evite la generación de hotspots

El problema más común de las series temporales en Cloud Bigtable es la generación de hotspots. Este problema puede afectar a cualquier tipo de clave de fila que contenga un valor monótonamente creciente.

En resumen, cuando la clave de fila de una serie temporal incluye una marca de tiempo, todas tus escrituras se orientarán a un solo nodo, lo llenarán y pasarán al siguiente. Esto provocará la generación de hotspots. Por ejemplo, si almacenas el estado de la batería de un teléfono celular y tu clave de fila es la palabra “BATERÍA” y una marca de tiempo (como se muestra a continuación), la clave de fila siempre aumentará en secuencia. Dado que Cloud Bigtable almacena claves de filas adyacentes en el mismo nodo del servidor, todas las escrituras se enfocarán solo en un nodo hasta que se llene y pasarán al siguiente.

Clave de fila Datos de la columna
BATTERY#20150301124501001 METRIC:USER:Corrie METRIC:PERCENTAGE:98
BATTERY#20150301124501002 METRIC:USER:Jo METRIC:PERCENTAGE:54
BATTERY#20150301124501003 METRIC:USER:Corrie METRIC:PERCENTAGE:96
BATTERY#20150301124501004 METRIC:USER:Sam METRIC:PERCENTAGE:43
BATTERY#20150301124501005 METRIC:USER:Sam METRIC:PERCENTAGE:38

Existen algunas formas de solucionar este problema:

  • Promoción de campo. Mueve los campos de los datos de columnas a la clave de fila para que las escrituras no sean contiguas.

  • Alteración. Agrega un elemento adicional calculado a la clave de fila a fin de realizar escrituras no contiguas artificialmente.

Usar la herramienta Key Visualizer puede ayudar a identificar los hotspots y facilitar la solución de problemas con Cloud Bigtable.

Ascensión de campo

En este ejemplo, moverás USER desde una columna a un elemento de la clave de fila. Con este cambio, podría resolverse el problema de generación de hotspots, ya que los identificadores de usuario ofrecerán una distribución más uniforme de las claves de fila. Como resultado, las escrituras se dividirán entre varios nodos en tu clúster.

La ventaja de la promoción de campos es que, a menudo, hace que tus consultas sean más eficientes, lo que la convierte en una muy buena opción. La (leve) desventaja es que tus consultas están restringidas por los campos promovidos, lo que puede hacerte repetir el trabajo si no seleccionas el campo adecuado.

Clave de fila Datos de la columna
BATTERY#Corrie#20150301124501001 METRIC:PERCENTAGE:98
BATTERY#Corrie#20150301124501003 METRIC:PERCENTAGE:96
BATTERY#Jo#20150301124501002 METRIC:PERCENTAGE:54
BATTERY#Sam#20150301124501004 METRIC:PERCENTAGE:43
BATTERY#Sam#20150301124501005 METRIC:PERCENTAGE:38

Alteración

En este ejemplo, tomarás un hash de la marca de tiempo y lo dividirás en 3. Luego, tomas el resto del cálculo y lo sumas a la clave de fila. ¿Por qué 3? Esta es una estimación de la cantidad de nodos del clúster y serviría para dividir las actividades adecuadamente entre ellos.

La ventaja de la alteración es su simplicidad, ya que, en esencia, es una función de hash simple. Una desventaja es que cuando consultes por intervalos de tiempo, deberás hacer varios análisis, uno por cada valor alterado, y combinar los resultados en tu código. Otra desventaja es que es difícil elegir un valor alterado que distribuya la actividad entre los nodos y que funcione bien cuando escales el sistema hacia arriba o abajo. Debido a estas desventajas y a que es mejor usar claves de fila en lenguaje legible, te recomendamos evitar este método, a menos que no encuentres otra forma de evitar la generación de hotspots.

Clave de fila Datos de la columna
BATTERY#1#20150301124501003 METRIC:USER:Jo METRIC:PERCENTAGE:96
BATTERY#1#20150301124501004 METRIC:USER:Sam METRIC:PERCENTAGE:43
BATTERY#2#20150301124501002 METRIC:USER: Corrie METRIC:PERCENTAGE:54
BATTERY#3#20150301124501005 METRIC:USER:Sam METRIC:PERCENTAGE:38
BATTERY#3#20150301124501001 METRIC:USER:Corrie METRIC:PERCENTAGE:98

De forma predeterminada, se prefiere la promoción de campos. La promoción de campo evita la generación de hotspots en casi todos los casos y tiende a simplificar el diseño de una clave de fila que facilite las consultas.

Usa la alteración solo en los casos en que la promoción de campos no resuelva la generación de hotspots. En el caso infrecuente en que apliques una función de alteración, ten cuidado de no hacer demasiadas suposiciones sobre el tamaño subyacente del clúster. En el ejemplo anterior, se usa una función de este tipo que supone que existen 3 nodos en el clúster. Esta suposición es segura, porque se escalará a la cantidad limitada de nodos que pueden existir en un clúster de Cloud Bigtable. Si pudieras crear clústeres con cientos de nodos, preferirías usar otra función.

Revierte las marcas de tiempo solo cuando sea necesario

Si quieres revertir marcas de tiempo, puedes quitarlas del valor máximo del lenguaje de programación para números enteros largos (como java.lang.Long.MAX_VALUE de Java). Si las reviertes, puedes diseñar una clave de fila en la que los eventos más recientes aparezcan al comienzo de la tabla en lugar de al final de ella. Por consiguiente, puedes obtener los N eventos más recientes con solo recuperar las primeras N filas de la tabla.

Revierte las marcas de tiempo solo cuando tu consulta más común sea por los valores más recientes. Esto se debe a que revertir las marcas de tiempo hace que todas las demás consultas sean más complejas y complica el esquema general.

Patrones para el diseño de columnas de datos

Las filas pueden ser grandes, pero no demasiado

Las filas en Cloud Bigtable pueden contener, aproximadamente, 100 familias de columnas y millones de columnas, con un límite de 100 MB por cada valor que estas almacenen. Estos límites amplios ofrecen una gran flexibilidad. Sin embargo, no deberías suponer que la forma adecuada de almacenar tus datos es en filas grandes y que, por lo tanto, debes llenar todas las filas con la mayor cantidad de datos posible. Siempre ten en cuenta que recuperar valores grandes requiere más tiempo y memoria.

En general, mantén el tamaño de las filas por debajo de los 100 MB. Esto es más un lineamiento que una regla, ya que las filas pueden tener más de 100 MB. Sin embargo, si hay muchas filas con un tamaño superior a este, podrías experimentar problemas de rendimiento.

En general, mantén el tamaño de las columnas por debajo de los 10 MB. Nuevamente, esto es más un lineamiento que una regla. Puedes almacenar algunos valores superiores a los 10 MB, pero es probable que experimentes problemas de rendimiento.

En conclusión, si a menudo usas filas o valores individuales grandes, es posible que experimentes problemas de rendimiento en tu sistema.

Cloud Bigtable es un almacén de clave-valor, no un almacén relacional. No admite uniones ni transacciones, excepto las que se realizan dentro de la misma fila. Como resultado, es mejor acceder a los datos en filas individuales o en un conjunto de filas contiguas.

Un resultado de este patrón es bastante evidente. En la gran mayoría de los casos, las consultas de series temporales acceden a un conjunto de datos determinado por cierto período. Por lo tanto, asegúrate de que todos los datos del período se almacenen en filas contiguas, a menos que esto provoque la generación de hotspots.

Otro resultado es que cuando lees los datos de una fila o de un rango de filas, estos deberían considerarse útiles por sí solos; no debería ser necesario que los combines con otros. Por ejemplo, supongamos que almacenas la actividad de usuarios en un sitio web de compras y que, a menudo, necesitas recuperar las últimas cinco acciones que un usuario realizó a fin de mostrarlas en una barra lateral. En este caso, deberías considerar desnormalizar los datos, además de incluir algunos detalles del producto y el usuario en la tabla de acciones recientes. Por el contrario, con una base de datos relacional, almacenarías el ID de usuario y el ID del producto en una tabla y, luego, la unirías con otras tablas de productos y usuarios en tu consulta de SQL.

Dicho esto, no es necesario que incluyas todos los datos de una entidad en cada fila. Por ejemplo, si muestras información sobre las acciones recientes de un usuario, no es necesario que almacenes su número de teléfono o la dirección de un fabricante del producto, ya que no mostrarás esa información en la barra lateral.

Busca oportunidades de desnormalizar los datos a fin de satisfacer las consultas, pero solo incluye los datos necesarios.

Almacena en una sola familia de columnas los datos a los que accederás en una consulta

Los calificadores de columnas de la misma familia de columnas tienen una relación lógica y física. En general, todos los calificadores de una familia de columnas se almacenan juntos, se accede a ellos juntos y se mantienen juntos en la memoria caché. Como resultado, una consulta que accede a una sola familia de columnas podría ejecutarse con mayor eficiencia que las que pasan de una familia a otra.

Asegúrate de que se recuperen datos de la menor cantidad de familias de columnas posible para las consultas más comunes, de modo que sean más eficientes.

No explotes la atomicidad de filas individuales

Cloud Bigtable no admite transacciones, con solo una excepción: las operaciones en una sola fila son transaccionales. Las transacciones también son costosas, lo que implica que un sistema basado en transacciones no tendrá tan buen rendimiento como otros.

Cuando trabajes con series temporales, no aproveches el comportamiento transaccional de las filas. Los cambios en los datos de una fila existente deberían almacenarse como una fila nueva independiente, en lugar de modificarse en la misma. Este modelo es más sencillo y te permite mantener un historial de actividad sin depender de versiones de columnas.

Ejemplos de diseños de esquemas

Ahora aplicarás los patrones del diseño de esquemas a fin de crear ejemplos para los siguientes tipos de datos:

  • Datos del mercado financiero
  • Métricas del servidor
  • Medidores inteligentes de energía (Internet de las cosas)

Recuerda que estos son solo ejemplos. A fin de encontrar el mejor esquema para tus datos de series temporales, tendrás que considerar qué datos almacenas y cómo piensas consultarlos; luego, aplica los patrones de diseño de la sección anterior.

Datos del mercado financiero

En este ejemplo, se usa un mensaje hipotético que representa la información de un mercado de valores imaginario:

Campo Datos de ejemplo
Ticker symbol (Símbolo bursátil) ZXZZT
Bid (Precio de venta) 600.55
Ask (Precio de compra) 600.60
Bide size (Tamaño de venta) 500
Ask size (Tamaño de compra) 1500
Last sale (Última venta) 600.58
Last size (Último tamaño) 300
Quote time (Hora de cotización) 12:53:32.156
Trade time (Hora de la transacción) 12:53:32.045
Exchange (Bolsa de valores) NASDAQ
Volume (Volumen) 89000

Algunas observaciones sobre este tipo de mensajes antes de continuar:

  • El mensaje agrega datos de cotización y transacción que se separan de forma lógica.

  • Existen miles de símbolos bursátiles.

  • Varios cientos de estos símbolos abarcarán el 90% de los mensajes recibidos, ya que pocas acciones se comercian activamente.

  • Con frecuencia, los mensajes llegan desde cientos a decenas de miles por segundo, con un promedio de varios miles por segundo.

  • Las consultas típicas se usarán para los datos de cotizaciones o para los datos de transacciones por separado, no para ambos a la vez.

  • En ambos casos, una consulta típica indicará lo siguiente:

    • Una bolsa de valores (como NASDAQ)
    • Un símbolo bursátil (como ZXZZT)
    • Una hora de inicio y finalización

Ahora puedes diseñar la tabla para este caso práctico:

Mantén los datos relacionados en la misma tabla y separa los no relacionados

  • Almacena los datos de cotizaciones en una tabla llamada QUOTE.
  • Almacena los datos de transacciones en una tabla llamada TRADE.
  • Las consultas pueden incluir intervalos de tiempo arbitrarios, por lo que almacenarás los datos de un solo mensaje en cada fila.

Las filas pueden ser grandes, pero no demasiado

  • Cada fila almacena datos de un solo mensaje. Esto evita preocupaciones por el tamaño.

No abuses de la atomicidad de las filas individuales

  • Cada mensaje se restringe a sí mismo, por lo que no existen preocupaciones.

Usa nombres cortos pero significativos

  • Para hacerlo más simple, en este ejemplo, se usan los campos del mensaje como nombres, pero en mayúsculas y sin espacios.

Con estas decisiones, obtienes el siguiente diseño de columna:

Ejemplo de la tabla QUOTE:

Datos de la columna
MD:SYMBOL:ZXZZT MD:BID:
600.55
MD:ASK:
600.60
MD:BIDSIZE:
500
MD:ASKSIZE:
1500
MD:QUOTETIME:
1426535612156
MD:EXCHANGE:
NASDAQ

Ejemplo de la tabla TRADE:

Datos de la columna
MD:SYMBOL:
ZXZZT
MD:LASTSALE:
600.58
MD:LASTSIZE:
300
MD:TRADETIME:
1426535612045
MD:EXCHANGE:
NASDAQ
MD:VOLUME:
89000

A continuación, diseña la clave de fila:

Usa tablas largas y angostas

  • Cada fila almacenará datos de un mensaje, lo que generará una gran cantidad de filas relativamente angostas.

Usa filas en lugar de versiones de columnas

  • Usa versiones de columnas solo en el caso excepcional de que un valor haya sido incorrecto.

Considera tus búsquedas en el momento de diseñar la clave de fila

  • Las claves de fila QUOTE y TRADE pueden seguir el mismo formato.
  • Como esta es una serie temporal, puedes suponer que QUOTETIME formará parte de la clave de fila de forma predeterminada.
  • Para consultar por un intercambio y un símbolo bursátil con horas específicas de inicio y finalización, deberás usar los valores EXCHANGE, SYMBOL y QUOTETIME.
  • Por lo tanto, ascenderás EXCHANGE (como un código de 6 caracteres; los que tengan menos se llenarán automáticamente con espacios), SYMBOL (como un código de 5 caracteres; los que tengan menos se llenarán automáticamente con espacios) y QUOTETIME (como un número de 13 dígitos). Cuando se llenan EXCHANGE y SYMBOL con espacios, te aseguras de que cada parte de la clave de fila se encuentre de forma predecible.
  • Si se juntan estos valores, la clave de fila tendrá el formato EXCHANGE + SYMBOL + QUOTETIME (por ejemplo, NASDAQ#ZXZZT#1426535612156).

Asegúrate de que tu clave de fila evite la generación de hotspots

  • Si tienes EXCHANGE y SYMBOL en las posiciones principales de la clave de fila, la actividad se distribuirá de forma natural.
  • Dado que el 90% de los mensajes se concentran en pocos cientos de símbolos, existe riesgo de generar hotspots, pero debes realizar una prueba de esfuerzo del sistema antes de implementar cambios adicionales. Si esto provoca un rendimiento deficiente, podrías aplicar la alteración para dividir la actividad de manera más efectiva.

Revierte las marcas de tiempo solo cuando sea necesario

  • En este caso, no revertirás las marcas de tiempo, ya que las consultas no siempre requieren acceso a los datos más recientes.

Cuando termines este ejercicio, tendrás las siguientes tablas:

Ejemplo de la tabla QUOTE:

Clave de fila Datos de la columna
NASDAQ#ZXZZT#1426535612156 MD:SYMBOL:
ZXZZT
MD:BID:
600.55
MD:ASK:
600.60
MD:BIDSIZE:
500
MD:ASKSIZE:1
500
MD:QUOTETIME:
1426535612156
MD:EXCHANGE:
NASDAQ

Ejemplo de la tabla TRADE:

Clave de fila Datos de la columna
NASDAQ#ZXZZT#1426535612045 MD:SYMBOL:
ZXZZT
MD:LASTSALE:
600.58
MD:LASTSIZE:
300
MD:TRADETIME:
1426535612045
MD:EXCHANGE:
NASDAQ
MD:VOLUME:
89000

Estas tablas crecerán a un ritmo de cientos de millones de filas por día, lo que no representa ningún problema para Cloud Bigtable.

Métricas del servidor

En el siguiente ejemplo, se usa un sistema de supervisión de servidores imaginario que recopila una gran variedad de métricas (como el uso del disco, de CPU y de memoria por núcleo) de un amplio inventario de máquinas. En este ejemplo, verás diversas iteraciones del esquema.

Puedes hacer las siguientes suposiciones sobre los datos:

  • Se recopilan 100 métricas por máquina.
  • Recopila métricas de 100,000 máquinas.
  • Las métricas se recopilan cada 5 segundos.
  • Las consultas típicas serán una de las siguientes opciones:

    • Métricas de una máquina específica con horas de inicio y finalización determinadas
    • Las últimas métricas de todo el inventario de máquinas

Con ese caso práctico en mente, puedes comenzar a diseñar la tabla de la siguiente manera:

Iteración 1

Mantén los datos relacionados en la misma tabla y separa los no relacionados

  • Almacenarás los datos de métricas en una tabla llamada METRIC.
  • Existen varias categorías de métricas y las agruparás con las familias de columnas que correspondan.
  • Las consultas pueden incluir intervalos de tiempo arbitrarios, de esta forma, puedes hacer que cada fila almacene un solo conjunto de métricas de una máquina en una hora específica.

Las filas pueden ser grandes, pero no demasiado

  • En cada fila, se almacena un conjunto de métricas, lo que evita preocupaciones por el tamaño.

No abuses de la atomicidad de las filas individuales

  • No te bases en la atomicidad de las filas en el diseño de nuestro esquema.

Usa nombres cortos pero significativos

  • Para hacerlo más simple, usa los nombres de campos de las métricas como calificadores de columnas, pero en mayúsculas y sin espacios.

Con estas decisiones, obtienes el siguiente diseño de columna:

Datos de la columna
METRIC:
HOSTNAME:
server1.bbb.com
METRIC:
CPU/CPU1_USR:
0.02
METRIC:
CPU/CPU1_NICE:
0.00
METRIC:
IO/BLK_READ:
253453634
METRIC:
MIO/BLK_WRTN:
657365234

A continuación, diseña la clave de fila de acuerdo con los siguientes patrones:

Usa tablas largas y angostas

  • Cada fila de la tabla almacenará un conjunto de métricas de una máquina, lo que generará una gran cantidad de filas.

Usa filas en lugar de versiones de columnas

  • No usarás versiones de columnas.

Considera tus búsquedas en el momento de diseñar la clave de fila

  • Dado que esta es una serie temporal, incluye la marca de tiempo TS en la clave de fila.
  • Para recuperar las métricas de una máquina en una hora de inicio y finalización específicas, deberás recuperar un rango de filas con HOSTNAME y TS.
  • Es difícil recuperar las métricas más recientes de todo el inventario de máquinas. No puedes simplemente revertir la marca de tiempo y analizar N filas, ya que no hay garantía de que se seleccionen todas las máquinas del inventario.

Ahora tienes un problema para diseñar la clave de fila. La solución sería la desnormalización. Deberás crear otra tabla que almacene las versiones más recientes de las métricas, llamada CURRENT_METRIC, que se actualizará junto con METRIC. Cuando actualices las métricas existentes de una máquina, solo deberás reemplazar la fila correspondiente.

Luego, deberás realizar la iteración en tu diseño original de la siguiente manera:

Iteración 2

Mantén los datos relacionados en la misma tabla y separa los no relacionados

  • Almacenarás los datos de métricas en una tabla llamada METRIC.
  • Almacenarás la versión más reciente de las métricas en una tabla llamada CURRENT_METRIC.
  • El resto de la información se mantiene igual que en la iteración 1.

Las filas pueden ser grandes, pero no demasiado

  • Se mantiene igual que en la iteración 1.

No abuses de la atomicidad de las filas individuales

  • Deberás basarte en la atomicidad de las filas para actualizar los datos de cada máquina en CURRENT_METRIC. Esta es una mutación simple de las filas con pocas posibilidades de contención, por lo que no provocará ningún problema.

Usa nombres cortos pero significativos

  • Se mantiene igual que en la iteración 1.

Luego, debes diseñar la clave de fila según los siguientes patrones:

Usa tablas largas y angostas

  • En ambas tablas, cada fila almacenará un conjunto de métricas de una máquina, lo que generará una gran cantidad de filas.

Usa filas en lugar de versiones de columnas

  • Se mantiene igual que en la iteración 1.

Considera tus búsquedas en el momento de diseñar la clave de fila

  • Dado que esta es una serie temporal, incluye la marca de tiempo TS en la clave de fila. Para recuperar las métricas de una máquina en una hora de inicio y finalización específicas, deberás recuperar un rango de filas de METRIC con HOSTNAME y TS.
  • Por lo tanto, deberás ascender HOSTNAME a la clave de fila y usar esta última en el formato HOSTNAME + TS.
  • Si quieres encontrar las métricas más recientes para máquinas específicas, analiza CURRENT_METRIC filtrando el prefijo de la clave de fila, o HOSTNAME, de esas máquinas.
  • Para encontrar las métricas más recientes de todo el inventario de máquinas, analiza CURRENT_METRIC sin especificar una clave de fila.
  • Por lo tanto, no es necesario que asciendas campos adicionales a la clave de fila; esta solo debe mantener el formato HOSTNAME + TS simple. Esto permitirá que el esquema sea simple y fácil de entender, y que las tablas se fragmenten de manera eficaz.
  • En la tabla CURRENT_METRIC, ya no necesitarás la marca de tiempo, por lo que la clave de fila será HOSTNAME.

    Ejemplo de clave de fila de METRIC: server1.aaa.bbb.com#1426535612045

    Ejemplo de clave de fila de CURRENT_METRIC: server1.aaa.bb.com

Asegúrate de que tu clave de fila evite la generación de hotspots

  • En METRIC y CURRENT_METRIC, no existen preocupaciones por la generación de hotspots, ya que tener el nombre del host al comienzo de la clave de fila distribuirá la actividad entre las regiones.

Revierte las marcas de tiempo solo cuando sea necesario

  • Almacena los datos de las métricas más recientes en otra tabla para no tener que revertir las marcas de tiempo.

Cuando termines el ejercicio, tendrás las siguientes tablas:

Tabla METRIC:

Clave de fila Datos de la columna
server1.bbb.com#1426535612045 METRIC:
CPU/CPU1_USR:
0.02
METRIC:
CPU/CPU1_NICE:
0.00
METRIC:
IO/BLK_READ:
253453634
METRIC:
MIO/BLK_WRTN:
657365234

Esta tabla crecerá a un ritmo de, aproximadamente, 2,000 millones de filas por día, lo que no representa ningún problema para Cloud Bigtable.

Tabla CURRENT_METRIC:

Clave de fila Datos de la columna
server1.bbb.com METRIC:
CPU/CPU1_USR:
0.02
METRIC:
CPU/CPU1_NICE:
0.00
METRIC:
IO/BLK_READ:
253453634
METRIC:
MIO/BLK_WRTN:
657365234

Medidores inteligentes de energía (Internet de las cosas)

En este ejemplo, se usa una situación hipotética de la IoT en la que los medidores inteligentes de energía envían lecturas del sensor periódicamente a un sistema centralizado. Una vez más, en este ejemplo, verás diversas iteraciones del esquema.

Puedes hacer las siguientes suposiciones sobre los datos:

  • Hay 10,000,000 de medidores operativos.
  • Cada medidor envía una lectura del sensor cada 15 minutos.
  • El ID del medidor es un ID numérico único.
  • Las consultas típicas serán una de las siguientes opciones:

    • Todos los datos de un medidor durante un día
    • Todos los datos de un día

Si es necesario, puedes diseñar la siguiente tabla:

Mantén los datos relacionados en la misma tabla y separa los no relacionados

  • Almacenarás los datos de los sensores en una tabla llamada SENSOR.
  • Las consultas aumentan a diario, por lo que deberás hacer que cada fila almacene los datos de un medidor durante un día.

Las filas pueden ser grandes, pero no demasiado

  • Cada fila contendrá los datos que un medidor recopile durante un día, por lo que tendrá un total de 96 columnas (24 horas al día * 60 minutos por hora / 1 lectura cada 15 minutos), por lo que no habrá preocupaciones por el tamaño.

No abuses de la atomicidad de las filas individuales

  • Explotarás la atomicidad de las filas, ya que cuando se reciban los datos, se agregarán a las filas que correspondan. Esta es una mutación simple de las filas con pocas posibilidades de contención, por lo que no provocará ningún problema.

Usa nombres cortos pero significativos

  • ID para almacenar el ID del medidor (un número entero único).
  • Una serie de columnas con nombres desde 0000 hasta 2345 para contener los 96 valores registrados cada 15 minutos durante el día. Se adopta este esquema porque permite cambiar a frecuencias distintas de 15 minutos en caso de ser necesario.

Con estas decisiones, obtienes el siguiente diseño de columna:

Iteración 1

Datos de la columna
METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
METER:2330:
27.89
METER:2345:
28.90

Luego, diseña la clave de fila:

Usa tablas largas y angostas

  • Como ya explicamos, cada fila almacenará los datos de un día.

Usa filas en lugar de versiones de columnas

  • Usa versiones de columnas solo en el caso excepcional de que un valor haya sido incorrecto.

Considera tus búsquedas en el momento de diseñar la clave de fila

  • Dado que esta es una serie temporal, incluye DATE en la clave de fila. Como el nivel de precisión que necesitas solo se basa en los días, los últimos cinco dígitos de la marca de tiempo serán cero y se omitirán.
  • Para consultar un medidor específico en un día en particular, deberás recuperar una sola fila con METER y DATE.
  • Para consultar todos los medidores en un día, deberás recuperar un rango de filas con DATE.
  • Por lo tanto, asciende DATE (como un numeral de 8 dígitos) y METER (como un numeral de 10 dígitos, con un ID de medidor de 10 dígitos a fin de acomodar 1,000 millones de posibles medidores en orden lexicográfico).
  • Si se juntan las consultas, la clave de fila deberá tener el formato DATE + METER. Por ejemplo: |20170726|0000987654|.

En este momento, es posible que detectes un problema. Al comienzo de cada día, todos los medidores se orientarán al mismo nodo, debido a que la fecha se encuentra en la posición principal de la clave de fila. Con 10 millones de medidores, esto podría ser un problema que afecte el rendimiento todos los días. La solución es encontrar una mejor manera de consultar los datos de los medidores de un día específico. Si ejecutas una sola consulta cada noche y almacenas los resultados en una tabla nueva llamada SENSOR_YYYYMMDD, no será necesario que optimices la clave de fila para las consultas basadas en fechas.

Realicemos una iteración para resolver este problema:

Iteración 2

Mantén los datos relacionados en la misma tabla y separa los no relacionados

  • Almacena los datos del sensor en una tabla llamada SENSOR.
  • Las consultas se recuperan en aumentos diarios, por lo que cada fila almacenará los datos de un medidor durante un día.
  • Ejecuta una consulta por lote durante la noche que cree otra tabla llamada SENSOR_YYYYMMDD (la fecha) que almacenará los datos de todos los medidores en esa fecha.

Las filas pueden ser grandes, pero no demasiado

  • Se mantiene igual que en la iteración 1.

No abuses de la atomicidad de las filas individuales

  • Se mantiene igual que en la iteración 1.

Usa nombres cortos pero significativos

  • Se mantiene igual que en la iteración 1.

Con todos estos elementos, una fila de ejemplo se vería como la siguiente en la tabla SENSOR y en las tablas SENSOR_YYYYMMDD:

Datos de la columna
METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
METER:2330:
27.89
METER:2345:
28.90

A continuación, diseña la clave de fila:

Usa tablas largas y angostas

  • Se mantiene igual que en la iteración 1.

Usa filas en lugar de versiones de columnas

  • Se mantiene igual que en la iteración 1.

Considera tus búsquedas en el momento de diseñar la clave de fila

  • Dado que esta es una serie temporal, incluye DATE en la clave de fila.
  • Para consultar un medidor específico en un día en particular, deberás recuperar una sola fila con METER y DATE.
  • Por lo tanto, asciende DATE (como un numeral de 8 dígitos) y METER (como un numeral de 10 dígitos, con un ID de medidor de 10 dígitos a fin de acomodar 1,000 millones de posibles medidores en orden lexicográfico).
  • La clave de fila deberá tener el formato METER + DATE (por ejemplo, “0000987654#20170726”), que servirá para nuestra consulta y que permitirá una buena distribución de la actividad entre los nodos.
  • También ejecutarás una consulta por lote por día, la que analizará toda la tabla y almacenará los datos del día anterior en una tabla nueva llamada SENSOR_YYYYMMDD, en la que YYYYMMDD es la fecha del día anterior.

Asegúrate de que tu clave de fila evite la generación de hotspots

  • La generación de hotspots no es una preocupación en la tabla SENSOR. Las escrituras se distribuirán de manera uniforme, ya que la clave de fila tiene METER en la posición principal.
  • La generación de hotspots no es una preocupación en las tablas SENSOR_YYYYMMDD. Cada tabla se crea solo una vez, como una consulta por lote, en la que el rendimiento es una preocupación menor. Sin embargo, para crear estas tablas, se requiere un análisis completo de SENSOR, por lo que te recomendamos crear las tablas SENSOR_YYYYMMDD cuando haya pocas consultas en la tabla SENSOR.

Revierte las marcas de tiempo solo cuando sea necesario

  • En este caso, no es necesario revertir las marcas de tiempo.

Cuando termines este ejercicio, tendrás lo siguiente en la tabla SENSOR y las tablas SENSOR_YYYYMMDD:

Clave de fila Datos de la columna
0000987654#20170726 METER:ID:987654 METER:0000:
12.34
METER:0015:
13.45
METER:2330:
27.89
METER:2345:
8.90

Esta tabla crecerá a un ritmo de poco menos de 10 millones de filas por día, lo que no representa ningún problema para Cloud Bigtable.

Próximos pasos