Diseña tu esquema

Esta página contiene información sobre el diseño de esquema de Cloud Bigtable. Antes de leer esta página, debes familiarizarte con la descripción general de Bigtable. En esta página, se abordan los siguientes temas:

  • Conceptos generales: Conceptos básicos que se deben tener en cuenta cuando se diseña el esquema.
  • Prácticas recomendadas: Lineamientos de diseño que se aplican a la mayoría de los casos prácticos, desglosados por componente de la tabla.
  • Casos prácticos especiales: Recomendaciones para algunos casos prácticos y patrones de datos específicos.

Conceptos generales

Diseñar un esquema de Bigtable es diferente a diseñar un esquema para una base de datos relacional. En Bigtable, un esquema es un plano o modelo de una tabla, incluida la estructura de los componentes siguientes de la tabla:

  • clave(s) de fila
  • Familias de columnas, incluidas sus políticas de recolección de elementos no utilizados
  • Columnas

Los siguientes conceptos generales se aplican al diseño de esquemas de Bigtable:

  • Bigtable es un almacén de clave-valor, no un almacén relacional. No admite uniones, y las transacciones solo se admiten dentro de una fila.
  • Cada tabla tiene solo un índice: la clave de fila. No existen índices secundarios. Cada clave de fila debe ser única.
  • Las filas se ordenan lexicográficamente por clave de fila, desde la mayor string de bytes a la menor. Las claves de filas siguen el orden de bytes big-endian (a veces llamado orden de bytes de red), que es el equivalente binario del orden alfabético.
  • Las familias de columnas no se almacenan en un orden específico.
  • Las columnas se agrupan por familia de columnas y se clasifican en orden lexicográfico dentro de la familia de columnas. Por ejemplo, en una familia de columnas llamada SysMonitor con calificadores de columna de ProcessName, User, %CPU, ID, Memory, DiskRead y Priority, Bigtable almacena las columnas en este orden:
SysMonitor
%CPU DiskRead ID Memoria Prioridad ProcessName Usuario
  • La intersección de una fila y una columna puede contener varias celdas con marcas de tiempo. Cada celda contiene una versión única con marca de tiempo de los datos para esa fila y columna.
  • Todas las operaciones son atómicas a nivel de fila. Esto significa que una operación afecta una fila completa o ninguna de la fila.
  • Lo ideal es que las lecturas y escrituras se distribuyan de manera uniforme en el espacio de filas de la tabla.

  • Las tablas de Bigtable son dispersas. Una columna no ocupa ningún espacio en una fila que no use la columna.

Prácticas recomendadas

Un buen esquema genera un excelente rendimiento y escalabilidad, mientras que uno mal diseñado puede provocar un rendimiento deficiente del sistema. Cada caso práctico es diferente y requiere su propio diseño, pero las siguientes prácticas recomendadas se aplican a la mayoría de los casos prácticos. Se mencionan las excepciones.

A partir del nivel de la tabla y el de la clave de fila, las siguientes secciones describen las prácticas recomendadas para el diseño de esquemas:

Todos los elementos de la tabla, en especial las claves de fila, deben diseñarse teniendo en cuenta las solicitudes de lectura planificadas. Verifica las cuotas y límites para conocer los límites de tamaño recomendados y estrictos para todos los elementos de la tabla.

Tablas

Almacena conjuntos de datos con esquemas similares en la misma tabla, en lugar de hacerlo en tablas separadas.

En otros sistemas de bases de datos, puedes elegir almacenar datos en varias tablas según el asunto y la cantidad de columnas. En Bigtable, sin embargo, suele ser mejor almacenar todos tus datos en una tabla grande. Puedes asignar un prefijo de clave de fila único para cada conjunto de datos, de modo que Bigtable almacene los datos relacionados en un rango contiguo de filas que luego puedas consultar por prefijo de clave de fila.

Bigtable tiene un límite de 1,000 tablas por instancia. Sin embargo, en la mayoría de los casos, deberías tener muchas menos tablas. La creación de muchas tablas pequeñas es un antipatrón de Bigtable por algunas razones:

  • El envío de solicitudes a muchas tablas diferentes puede aumentar la sobrecarga de la conexión de backend, lo que aumenta la latencia final.
  • Tener varias tablas de diferentes tamaños puede interrumpir el balanceo de cargas tras bambalinas que hace que Bigtable funcione.

Es lógico que desees una tabla separada para un caso práctico completamente diferente que requiera un esquema distinto, pero no debes usar tablas separadas para datos similares. Por ejemplo, no debes crear una tabla nueva por un año nuevo o un cliente nuevo.

Familias de columnas

Coloca las columnas relacionadas en la misma familia de columnas. Cuando una fila contiene varios valores relacionados entre sí, se recomienda agrupar las columnas que contienen esos valores en la misma familia de columnas. Agrupa los datos lo más cerca posible, para evitar tener que diseñar filtros complejos y obtener solo la información que necesitas, pero no más, en tus solicitudes de lectura más frecuentes.

Crea hasta 100 familias de columnas por tabla. La creación de más de 100 familias de columnas puede degradar el rendimiento.

Elige nombres cortos pero significativos para tus familias de columnas. Los nombres se incluyen en los datos que se transfieren para cada solicitud.

Coloca columnas que tengan diferentes necesidades de retención de datos en diferentes familias de columnas. Esto es importante si deseas limitar los costos de almacenamiento. Las políticas de recolección de elementos no utilizados se establecen a nivel de la familia de columnas, no a nivel de la columna. Por ejemplo, si solo necesitas mantener la versión más reciente de un dato en particular, no la almacenes en una familia de columnas que esté configurada para almacenar 1,000 versiones de algo más. De lo contrario, pagarás el almacenamiento de 999 celdas de datos que no necesitas.

Columnas

Trata los calificadores de columnas como datos. Dado que tienes que almacenar un calificador de columna para cada columna, puedes ahorrar espacio nombrando la columna con un valor. Como ejemplo, considera una tabla que almacena datos sobre amistades, en la que cada fila representa a una persona y todas sus amistades. Cada calificador de columna puede ser el ID de un amigo, y el valor de esa columna puede ser el círculo social en el que se encuentra el amigo. En este ejemplo, las filas podrían verse así:

Jose Fred:club de lectura Gabriel:trabajo Hiroshi:tenis
Sofía Hiroshi:trabajo Seo Yoon:escuela Jakob:club de ajedrez

Compara este procedimiento con un esquema para los mismos datos que no usa calificadores de columnas como datos:

Jose#1 Amigo:Fred Círculo: club de lectura
Jose#2 Amigo:Gabriel Círculo:trabajo
Jose#3 Amigo:Hiroshi Círculo:tenis
Sofia#1 Friend:Hiroshi Circle:work
Sofia#2 Amigo:Seo Yoon Círculo:escuela
Sofia# Amigo:Jakob Círculo:club de lectura

El segundo diseño de esquema hace que la tabla crezca mucho más rápido.

Si no usas calificadores de columna para almacenar datos y deseas reducir la cantidad de datos que se transfieren para cada solicitud, asigna calificadores de columnas cortos, pero nombres significativos. El tamaño máximo es de 16 KB.

Crea tantas columnas como necesites en la tabla. Las tablas de Bigtable son dispersas, y no hay penalización de espacio para una columna que no se usa en una fila. Puedes tener millones de columnas en una tabla, siempre que ninguna fila exceda el límite máximo de 256 MB por fila.

Evita usar demasiadas columnas en una sola fila. Aunque una tabla puede tener millones de columnas, una fila no. Algunos factores contribuyen a esta práctica recomendada:

  • Bigtable demora en procesar cada celda de una fila.
  • Cada celda agrega algo de sobrecarga a la cantidad de datos que se almacenan en tu tabla y que se envían por la red. Por ejemplo, si almacenas 1 KB (1,024 bytes) de datos, sería mucho más eficiente almacenarlos en una sola celda que dividirlos en 1,024 celdas y que cada una contenga 1 byte.

Si tu conjunto de datos requiere de forma lógica más columnas por fila de las que Bigtable puede procesar de manera eficiente, considera almacenar los datos como un protobuf en una sola columna.

Filas

No almacenes más de 100 MB de datos en una sola fila. Las filas que exceden este límite pueden reducir el rendimiento de la lectura.

Mantén toda la información de una entidad en una sola fila. Para la mayoría de los casos prácticos, evita almacenar datos que necesites leer de forma atómica o todas a la vez, en más de una fila a fin de evitar inconsistencias. Por ejemplo, si actualizas dos filas de una tabla, es posible que una fila se actualice correctamente y la otra actualización falle. Asegúrate de que tu esquema no requiera más de una fila al mismo tiempo para que los datos relacionados sean precisos. Esto garantiza que, si parte de una solicitud de escritura falla o se requiere volver a enviar, esa parte de los datos no estará incompleta de forma temporal.

Excepción:Si mantener una entidad en una sola fila genera filas de cientos de MB, debes dividir los datos en varias filas.

Almacena entidades relacionadas en filas adyacentes para que las lecturas sean más eficientes.

celdas

No almacenes más de 10 MB de datos en una sola celda. Recuerda que una celda son los datos almacenados para una fila y columna determinadas con una marca de tiempo única, y que se pueden almacenar varias celdas en la intersección de esa fila y columna. La cantidad de celdas retenidas en una columna se rige por la política de recolección de elementos no utilizados que estableces para la familia de columnas de la columna.

clave(s) de fila

Diseña tu clave de fila con las consultas que usarás para recuperar los datos. Las claves de fila bien diseñadas obtienen el mejor rendimiento de Bigtable. Las consultas de Bigtable más eficientes recuperan datos mediante una de las siguientes opciones:

  • Clave de fila
  • Prefijo de la clave de fila
  • Rango de filas definidas mediante el inicio y la finalización de las claves de fila

Otros tipos de consultas activan un análisis completo de la tabla, lo que es mucho menos eficiente. Si eliges la clave de fila correcta, te ahorrarás un proceso de migración de datos agotador en el futuro

Mantén las claves de fila cortas. Una clave de fila debe tener 4 KB o menos. Las claves de fila largas ocupan más memoria y almacenamiento, y aumentan el tiempo necesario para obtener respuestas del servidor de Bigtable.

Almacena varios valores delimitados en cada clave de fila. A menudo, es útil que incluyas varios identificadores en tu clave de fila, debido a que la única forma de realizar consultas eficaces en Bigtable es a través de clave de fila. Es especialmente importante comprender en profundidad cómo usarás tus datos cuando tu clave de fila incluye varios valores.

Los segmentos de clave de fila suelen estar separados por un delimitador, como dos puntos, barra o símbolo de hash. El primer segmento o conjunto de segmentos contiguos es el prefijo de la clave de fila, y el último segmento o conjunto de segmentos contiguos es el sufijo de clave de fila.

Clave de fila de muestra

Los prefijos de clave de fila bien planificados te permiten aprovechar el orden de clasificación de Bigtable para almacenar datos relacionados en filas contiguas. El almacenamiento de datos relacionados en filas contiguas te permite acceder a datos relacionados como un rango de filas, en lugar de ejecutar análisis ineficientes de las tablas.

Si tus datos incluyen números enteros que deseas ordenar o almacenar numéricamente, rellena los números enteros con ceros a la izquierda. Bigtable almacena los datos lexicográficamente. Por ejemplo, lexicográficamente, 3 > 20, pero 20 > 03. El relleno de los 3 con un cero inicial garantiza que los números se ordenen de forma numérica. Esta táctica es importante para las marcas de tiempo en las que se desean realizar consultas basadas en rangos.

Es importante crear una clave de fila que también permita recuperar un rango de filas bien definido. De lo contrario, tu consulta requiere un análisis de la tabla, que es mucho más lento que recuperar filas específicas.

Por ejemplo, si tu aplicación realiza un seguimiento de los datos del dispositivo móvil, puedes tener una clave de fila que incluya el tipo de dispositivo, su ID y el día en que se registran los datos. Las claves de fila para estos datos podrían verse así:

        phone#4c410523#20200501
        phone#4c410523#20200502
        tablet#a0b81f74#20200501
        tablet#a0b81f74#20200502

Este diseño de clave de fila te permite recuperar datos con una sola solicitud para lo siguiente:

  • Un tipo de dispositivo
  • Una combinación del tipo de dispositivo y el ID del dispositivo

Este diseño de clave de fila no sería óptimo si deseas recuperar todos los datos de un día determinado. Debido a que el día se almacena en el tercer segmento o en el sufijo de la clave de fila, no puedes solicitar un rango de filas según el sufijo o un segmento intermedio de la clave de fila. En su lugar, debes enviar una solicitud de lectura con un filtro que analice toda la tabla en busca del valor del día.

Usa valores de string legibles en tus claves de fila siempre que sea posible. Esta práctica facilita el uso de la herramienta Key Visualizer para solucionar problemas con Bigtable.

En muchos casos, debes diseñar claves de fila que comiencen con un valor común y terminen con un valor detallado. Por ejemplo, si tu clave de fila incluye un continente, un país y una ciudad, puedes crear claves de fila que se vean de la siguiente manera para que, primero, se ordenen automáticamente por valores con cardinalidad más baja:

        asia#india#bangalore
        asia#india#mumbai
        asia#japan#okinawa
        asia#japan#sapporo
        southamerica#bolivia#cochabamba
        southamerica#bolivia#lapaz
        southamerica#chile#santiago
        southamerica#chile#temuco

Claves de fila que debes evitar

Algunos tipos de claves de fila pueden dificultar la consulta de tus datos y algunas dan como resultado un rendimiento bajo. En esta sección, se describen algunos tipos de claves de fila que debes evitar usar en Bigtable.

Claves de fila que comienzan con una marca de tiempo. Esto hará que las escrituras secuenciales se envíen a un solo nodo, lo que crea un hotspot. Si colocas una marca de tiempo en una clave de fila, debes anteponer un valor de cardinalidad alta, como un ID de usuario, para evitar la generación de hotspots.

Claves de fila que hacen que los datos relacionados no se agrupen. Evita que las claves de fila hagan que los datos relacionados se almacenen en rangos de fila no contiguos, que son ineficientes para leer juntos.

ID numéricos secuenciales. Imagina que tu sistema asigna un ID numérico a cada uno de los usuarios de tu aplicación. Es posible que te parezca una buena idea usar el ID numérico del usuario como clave de fila en tu tabla. Sin embargo, debido a que es más probable que los usuarios nuevos sean usuarios activos, es posible que este enfoque envíe la mayor parte de tu tráfico a una pequeña cantidad de nodos.

Un enfoque más seguro es usar una versión invertida del ID numérico del usuario, que distribuye el tráfico de manera más uniforme en todos los nodos de tu tabla de Bigtable.

Identificadores que se actualizan con frecuencia Evita usar una sola clave de fila para identificar un valor que debe actualizarse con mucha frecuencia. Por ejemplo, si almacenas los datos de uso de memoria de varios dispositivos una vez por segundo, no uses una sola clave de fila para cada dispositivo que esté compuesto por el ID de dispositivo. y la métrica que se almacena, como 4c410523#memusage, y actualiza la fila varias veces. Este tipo de operación sobrecarga la tablet que almacena la fila de uso frecuente. También puede causar que una fila exceda su límite de tamaño, porque los valores anteriores de una columna ocupan espacio hasta que las celdas se quitan durante la recolección de elementos no utilizados.

En su lugar, almacena cada lectura nueva en una fila nueva. En el ejemplo de uso de memoria, cada clave de fila puede contener el ID de dispositivo, el tipo de métrica y una marca de tiempo, por lo que las claves de fila son similares a 4c410523#memusage#1423523569918. Esta estrategia es eficiente porque en Bigtable, crear una fila nueva no lleva más tiempo que crear una celda nueva. Además, esta estrategia te permite leer rápidamente los datos de un período de fechas específico, mediante el cálculo de las claves de inicio y fin adecuadas.

Para los valores que cambian con mucha frecuencia, como un contador que se actualiza cientos de veces por minuto, la mejor opción es simplemente mantener los datos en la memoria, en la capa de la aplicación, y escribir nuevas filas en Bigtable periódicamente.

Valores de hash La generación de un hash de clave de fila quita tu capacidad de aprovechar el orden de clasificación natural de Bigtable, lo que hace imposible almacenar las filas de manera óptima para realizar consultas. Por el mismo motivo, el hashing dificulta el uso de la herramienta Key Visualizer para solucionar problemas con Bigtable. Usa valores legibles en lugar de valores con hash.

Valores expresados como bytes sin procesar, en lugar de strings legibles. Los bytes sin procesar son adecuados para los valores de columna, pero para la legibilidad y la solución de problemas, usa valores de string en las claves de fila.

Casos de uso especiales

Es posible que tengas un conjunto de datos único que requiera una consideración especial cuando diseñes un esquema para almacenarlo en Bigtable. En esta sección, se describen algunos, pero no todos, los diferentes tipos de datos de Bigtable y algunas tácticas sugeridas para almacenarlos de la manera más óptima.

Datos basados en el tiempo

Incluye una marca de tiempo como parte de la clave de fila si necesitas recuperar datos en función del momento en que se registraron.

Por ejemplo, es posible que tu aplicación necesite registrar datos relacionados con el rendimiento, como el uso de la CPU y la memoria, una vez por segundo para una gran cantidad de máquinas. Tu clave de fila para estos datos puede combinar un identificador para la máquina con una marca de tiempo para los datos (por ejemplo, machine_4223421#1425330757685). Ten en cuenta que las claves de fila están ordenadas de manera lexicográfica.

No uses una marca de tiempo sola o al comienzo de una clave de fila, ya que esto provocará que las escrituras secuenciales se envíen a un solo nodo y creen un hotspot.

Si por lo general recuperas primero los registros más recientes, puedes usar una marca de tiempo invertida en la clave de fila cuando le quites la marca de tiempo del valor máximo de tu lenguaje de programación para números enteros largos (en Java, java.lang.Long.MAX_VALUE). Con una marca de tiempo invertida, los registros se ordenarán del más reciente al menos reciente.

Si deseas obtener información específica sobre cómo trabajar con datos de series temporales, consulta Diseño de esquemas para datos de series temporales.

Multiusuario

Los prefijos de clave de fila proporcionan una solución escalable para los casos prácticos de “instancias múltiples”, lo que ocurre cuando almacenas datos similares, con el uso del mismo modelo de datos, en nombre de varios clientes. El uso de una tabla para todas las instancias es la forma más eficaz de almacenar y acceder a los datos de varias instancias.

Por ejemplo, supongamos que almacenas y realizas un seguimiento de los historiales de compra en nombre de muchas empresas. Puedes usar tu ID único para cada empresa como prefijo de clave de fila. Todos los datos de un usuario se almacenan en filas contiguas en la misma tabla, y puedes buscarlos o filtrarlos mediante el prefijo de la clave de fila. Luego, cuando una empresa ya no es tu cliente y necesitas borrar los datos del historial de compras que almacenabas para la empresa, puedes descartar el rango de filas que usan el prefijo de clave de fila del cliente.

Por ejemplo, si almacenas los datos de los teléfonos celulares para los clientes altostrat y examplepetstore, puedes crear claves de filas como las que se muestran a continuación: Luego, si altostrat ya no es tu cliente, descarta todas las filas con el prefijo de clave de fila altostrat.

        altostrat#phone#4c410523#20190501
        altostrat#phone#4c410523#20190502
        altostrat#tablet#a0b41f74#20190501
        examplepetstore#phone#4c410523#20190502
        examplepetstore#tablet#a6b81f79#20190501
        examplepetstore#tablet#a0b81f79#20190502

En cambio, si almacenas datos en nombre de cada empresa en su propia tabla, puedes experimentar problemas de escalabilidad y rendimiento. También es muy probable que, sin darte cuenta, alcances el límite de 1,000 tablas por instancia de Bigtable. Después de que una instancia alcanza este límite, Bigtable evita que crees más tablas en la instancia.

Privacidad

A menos que tu caso de uso lo requiera, evita usar información de identificación personal (PII) o datos de usuario en claves de fila o ID de familia de columnas. Las claves de fila y las familias de columnas son datos y metadatos, y las aplicaciones que los usan como metadatos, como la encriptación o el registro, pueden exponerlos accidentalmente a los usuarios que no deberían tener acceso a datos privados.

Nombres de dominio

Amplia gama de nombres de dominio

Si almacenas datos sobre entidades que pueden representarse como nombres de dominio, considera usar un nombre de dominio inverso (por ejemplo, com.company.product) como la clave de fila. El uso de un nombre de dominio inverso es ideal si los datos de cada fila tienden a superponerse con las filas adyacentes. En este caso, en Bigtable se pueden comprimir tus datos de manera más eficiente.

En cambio, los nombres de dominio estándar que no se revierten pueden hacer que las filas se ordenen de tal manera que los datos relacionados no se agrupen en un solo lugar, lo que puede generar una compresión menos eficiente y lecturas menos eficientes.

Este enfoque funciona mejor cuando tus datos se distribuyen a través de muchos nombres de dominio inversos diferentes.

Para ilustrar este punto, considera los siguientes nombres de dominio, que se ordenan de forma automática en orden lexicográfico por Bigtable:

      drive.google.com
      en.wikipedia.org
      maps.google.com

Esto no es recomendable para el caso práctico en el que deseas consultar todas las filas del google.com. Por el contrario, considera las mismas filas en las que se revirtieron los nombres de dominio:

      com.google.drive
      com.google.maps
      org.wikipedia.en

En el segundo ejemplo, las filas relacionadas se ordenan de manera automática de una manera que facilita su recuperación como un rango de filas.

Pocos nombres de dominio

Si esperas almacenar una gran cantidad de datos para uno o una pequeña cantidad de nombres de dominio, considera otros valores para tu clave de fila. De lo contrario, puedes enviar escrituras a un solo nodo del clúster, lo que genera hotspots, o puede que las filas crezcan demasiado.

Consultas cambiantes o inciertas

Si no ejecutas las mismas consultas en tus datos o no estás seguro de cuáles serán, una opción es almacenar todos los datos de una fila en una sola columna en lugar de varias. Con este enfoque, usas un formato que facilita la extracción de los valores individuales más adelante, como el formato binario del búfer de protocolo o el json.

La clave de fila aún está diseñada con cuidado para garantizar que puedas recuperar los datos que necesitas, pero cada fila suele tener solo una columna que contiene todos los datos de la fila en un solo protobuf.

Almacenar datos como un mensaje protobuf en una sola columna en lugar de distribuirlos en varias columnas tiene ventajas y desventajas. Entre las ventajas, se incluyen las siguientes:

  • Los datos ocupan menos espacio, por lo que te cuesta menos almacenarlos.
  • Mantienes una cierta flexibilidad, ya que no te comprometes a las familias de columnas ni a los calificadores de columnas.
  • No es necesario que tu aplicación de lectura sepa cuál es el esquema de tu tabla.

Algunas desventajas son las siguientes:

  • Tienes que deserializar los mensajes protobuf después de leerlos desde Bigtable.
  • Se pierde la opción de consultar los datos en mensajes protobuf mediante filtros.
  • No puedes usar BigQuery para ejecutar consultas federadas en campos dentro de mensajes protobuf después de leerlos desde Bigtable.

¿Qué sigue?