sql >> Base de Datos >  >> NoSQL >> HBase

División y fusión de regiones de Apache HBase

Esta entrada de blog se publicó en Hortonworks.com antes de la fusión con Cloudera. Es posible que algunos enlaces, recursos o referencias ya no sean precisos.

Para esta publicación, nos sumergimos técnicamente en profundidad en una de las áreas centrales de HBase. Específicamente, veremos cómo Apache HBase distribuye la carga a través de regiones y administra la división de regiones. HBase almacena filas de datos en tablas. Las tablas se dividen en fragmentos de filas llamadas "regiones". Esas regiones se distribuyen en el clúster, se alojan y se ponen a disposición de los procesos del cliente mediante el proceso RegionServer. Una región es un rango continuo dentro del espacio de claves, lo que significa que todas las filas de la tabla que se clasifican entre la clave de inicio y la clave de finalización de la región se almacenan en la misma región. Las regiones no se superponen, es decir, una sola clave de fila pertenece exactamente a una región en cualquier momento. Una región solo es atendida por un único servidor de región en cualquier momento, que es la forma en que HBase garantiza una coherencia sólida dentro de un solo número de fila. Junto con -ROOT- y .META. regiones, las regiones de una tabla forman efectivamente un árbol B de 3 niveles con el fin de ubicar una fila dentro de una tabla.

Una Región a su vez, consta de muchas “Tiendas”, que corresponden a familias de columnas. Una tienda contiene una tienda de memoria y cero o más archivos de tienda. Los datos de cada familia de columnas se almacenan y se accede a ellos por separado.

Una tabla normalmente consta de muchas regiones, que a su vez están alojadas en muchos servidores de regiones. Por lo tanto, las regiones son el mecanismo físico que se utiliza para distribuir la carga de escritura y consulta entre los servidores de la región. Cuando se crea una tabla por primera vez, HBase, de forma predeterminada, asignará solo una región para la tabla. Esto significa que, inicialmente, todas las solicitudes irán a un solo servidor de región, independientemente de la cantidad de servidores de región. Esta es la razón principal por la que las fases iniciales de carga de datos en una tabla vacía no pueden utilizar toda la capacidad del clúster.

Pre-partido

La razón por la que HBase crea solo una región para la tabla es que no puede saber cómo crear los puntos de división dentro del espacio de clave de fila. La toma de tales decisiones se basa en gran medida en la distribución de las claves en sus datos. En lugar de adivinar y dejar que usted se haga cargo de las consecuencias, HBase le brinda herramientas para administrar esto desde el cliente. Con un proceso llamado división previa, puede crear una tabla con muchas regiones proporcionando los puntos de división en el momento de la creación de la tabla. Dado que la división previa garantizará que la carga inicial se distribuya de manera más uniforme en todo el clúster, siempre debe considerar su uso si conoce la distribución de claves de antemano. Sin embargo, la división previa también tiene el riesgo de crear regiones que realmente no distribuyen la carga de manera uniforme debido al sesgo de datos o en presencia de filas muy calientes o grandes. Si el conjunto inicial de puntos de división de regiones se elige mal, puede terminar con una distribución de carga heterogénea, lo que a su vez limitará el rendimiento de sus clústeres.

No hay una respuesta breve para la cantidad óptima de regiones para una carga determinada, pero puede comenzar con un múltiplo menor de la cantidad de servidores de la región como cantidad de divisiones y luego dejar que la división automatizada se encargue del resto.

Un problema con la división previa es calcular los puntos de división para la tabla. Puede utilizar la utilidad RegionSplitter. RegionSplitter crea los puntos de división mediante el uso de un SplitAlgorithm conectable. HexStringSplit y UniformSplit son dos algoritmos predefinidos. El primero se puede usar si las claves de fila tienen un prefijo para cadenas hexadecimales (como si estuviera usando hashes como prefijos). Este último divide el espacio de claves de manera uniforme, suponiendo que son matrices de bytes aleatorios. También puede implementar su SplitAlgorithm personalizado y usarlo desde la utilidad RegionSplitter.

$ hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f f1

donde -c 10, especifica el número solicitado de regiones como 10, y -f especifica las familias de columnas que desea en la tabla, separadas por ":". La herramienta creará una tabla llamada "test_table" con 10 regiones:

13/01/18 18:49:32 DEBUG hbase.HRegionInfo: Current INFO from scan results = {NAME => 'test_table,,1358563771069.acc1ad1b7962564fc3a43e5907e8db33.', STARTKEY => '', ENDKEY => '19999999', ENCODED => acc1ad1b7962564fc3a43e5907e8db33,}
13/01/18 18:49:32 DEBUG hbase.HRegionInfo: Current INFO from scan results = {NAME => 'test_table,19999999,1358563771096.37ec12df6bd0078f5573565af415c91b.', STARTKEY => '19999999', ENDKEY => '33333332', ENCODED => 37ec12df6bd0078f5573565af415c91b,}
...

Si tiene puntos de división a mano, también puede usar el shell HBase para crear la tabla con los puntos de división deseados.

hbase(main):015:0> create 'test_table', 'f1', SPLITS=> ['a', 'b', 'c']

o

$ echo -e  "anbnc" >/tmp/splits
hbase(main):015:0> create 'test_table', 'f1', SPLITSFILE=>'/tmp/splits'

Para una distribución de carga óptima, debe pensar en su modelo de datos y distribución de claves para elegir el algoritmo de división o los puntos de división correctos. Independientemente del método que elija para crear la tabla con un número predeterminado de regiones, ahora puede comenzar a cargar los datos en la tabla y ver que la carga se distribuye en todo su clúster. Puede dejar que la división automática se haga cargo una vez que comience la ingesta de datos y monitorear continuamente el número total de regiones para la tabla.

División automática

Independientemente de si se usa o no la división previa, una vez que una región llega a cierto límite, se divide automáticamente en dos regiones. Si está utilizando HBase 0.94 (que viene con HDP-1.2), puede configurar cuándo HBase decide dividir una región y cómo calcula los puntos de división a través de la API conectable RegionSplitPolicy. Hay un par de políticas de división de regiones predefinidas:ConstantSizeRegionSplitPolicy, IncreaseToUpperBoundRegionSplitPolicy y KeyPrefixRegionSplitPolicy.

La primera es la política dividida predeterminada y única para las versiones de HBase anteriores a la 0.94. Divide las regiones cuando el tamaño total de los datos de uno de los almacenes (correspondiente a una familia de columnas) en la región es mayor que el "hbase.hregion.max.filesize" configurado, que tiene un valor predeterminado de 10 GB. Esta política de división es ideal en los casos en los que ha realizado una división previa y está interesado en obtener una cantidad menor de regiones por servidor de región.

La política de división predeterminada para HBase 0.94 y el enlace troncal es IncrementarToUpperBoundRegionSplitPolicy, que realiza una división más agresiva según la cantidad de regiones alojadas en el mismo servidor de región. La política dividida usa el tamaño máximo de archivo de almacenamiento basado en Min (R^2 * “hbase.hregion.memstore.flush.size”, “hbase.hregion.max.filesize”), donde R es el número de regiones del mismo tabla alojada en el mismo servidor de regiones. Entonces, por ejemplo, con el tamaño de vaciado del almacén de memoria predeterminado de 128 MB y el tamaño de almacenamiento máximo predeterminado de 10 GB, la primera región en el servidor de la región se dividirá justo después del primer vaciado en 128 MB. A medida que aumente la cantidad de regiones alojadas en el servidor de la región, usará tamaños de división cada vez mayores:512 MB, 1152 MB, 2 GB, 3,2 GB, 4,6 GB, 6,2 GB, etc. Después de llegar a 9 regiones, el tamaño de división irá más allá del "hbase" configurado. .hregion.max.filesize”, momento en el que se utilizará un tamaño dividido de 10 GB a partir de ese momento. Para ambos algoritmos, independientemente de cuándo se produzca la división, el punto de división utilizado es la clave de fila que corresponde al punto medio en el "índice de bloque" para el archivo de almacenamiento más grande en el almacén más grande.

KeyPrefixRegionSplitPolicy es una adición curiosa al arsenal de HBase. Puede configurar la longitud del prefijo para sus claves de fila para agruparlas, y esta política de división garantiza que las regiones no se dividan en medio de un grupo de filas que tienen el mismo prefijo. Si ha establecido prefijos para sus claves, puede usar esta política de división para asegurarse de que las filas que tienen el mismo prefijo de clave de fila siempre terminen en la misma región. Esta agrupación de registros a veces se denomina "Grupos de entidades" o "Grupos de filas". Esta es una característica clave cuando se considera el uso de la función de "transacciones locales" (enlace alternativo) en el diseño de su aplicación.

Puede configurar la política de división predeterminada que se utilizará configurando la configuración "hbase.regionserver.region.split.policy" o configurando el descriptor de la tabla. Para sus almas valientes, también puede implementar su propia política de división personalizada y conectarla en el momento de la creación de la tabla, o modificando una tabla existente:

HTableDescriptor tableDesc = new HTableDescriptor("example-table");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, AwesomeSplitPolicy.class.getName());
//add columns etc
admin.createTable(tableDesc);

Si está realizando una división previa y desea administrar manualmente las divisiones de regiones, también puede deshabilitar las divisiones de regiones configurando "hbase.hregion.max.filesize" en un número alto y configurando la política de división en ConstantSizeRegionSplitPolicy. Sin embargo, debe usar un valor de protección de 100 GB, para que las regiones no crezcan más allá de las capacidades de un servidor de región. Puede considerar deshabilitar la división automática y confiar en el conjunto inicial de regiones de la división previa, por ejemplo, si está utilizando hashes uniformes para sus prefijos clave, y puede asegurarse de que la lectura/escritura se cargue en cada región, así como su tamaño. es uniforme en todas las regiones de la tabla.

Divisiones forzadas

HBase también permite a los clientes forzar la división de una tabla en línea desde el lado del cliente. Por ejemplo, el shell de HBase se puede usar para dividir todas las regiones de la tabla o dividir una región, opcionalmente proporcionando un punto de división.

hbase(main):024:0> split 'b07d0034cbe72cb040ae9cf66300a10c', 'b'
0 row(s) in 0.1620 seconds

Con un control cuidadoso de la distribución de carga de HBase, si ve que algunas regiones reciben cargas desiguales, puede considerar dividir manualmente esas regiones para nivelar la carga y mejorar el rendimiento. Otra razón por la que podría querer hacer divisiones manuales es cuando ve que las divisiones iniciales para la región resultan ser subóptimas y ha deshabilitado las divisiones automáticas. Eso podría suceder, por ejemplo, si la distribución de datos cambia con el tiempo.

Cómo se implementan las divisiones regionales

A medida que el servidor de región maneja las solicitudes de escritura, se acumulan en un sistema de almacenamiento en memoria llamado "memstore". Una vez que el memstore se llena, su contenido se escribe en el disco como archivos de almacenamiento adicionales. Este evento se denomina "descarga de memoria". A medida que se acumulan los archivos almacenados, el RegionServer los "compactará" en archivos combinados más grandes. Después de que finaliza cada vaciado o compactación, se pone en cola una solicitud de división de región si RegionSplitPolicy decide que la región debe dividirse en dos. Dado que todos los archivos de datos en HBase son inmutables, cuando ocurre una división, las regiones hijas recién creadas no reescribirán todos los datos en nuevos archivos. En su lugar, crearán pequeños archivos similares a enlaces simbólicos, llamados archivos de referencia, que apuntan a la parte superior o inferior del archivo de la tienda principal según el punto de división. El archivo de referencia se utilizará como un archivo de datos normal, pero solo la mitad de los registros. La región solo se puede dividir si no hay más referencias a los archivos de datos inmutables de la región principal. Esos archivos de referencia se limpian gradualmente mediante compactaciones, de modo que la región dejará de hacer referencia a sus archivos principales y se puede dividir aún más.

Aunque dividir la región es una decisión local que se toma en el RegionServer, el proceso de división en sí mismo debe coordinarse con muchos actores. El RegionServer notifica al Maestro antes y después de la división, actualiza el .META. table para que los clientes puedan descubrir las nuevas regiones hijas y reorganiza la estructura de directorios y los archivos de datos en HDFS. Split es un proceso de varias tareas. Para habilitar la reversión en caso de error, RegionServer mantiene un diario en memoria sobre el estado de ejecución. Los pasos tomados por RegionServer para ejecutar la división se ilustran en la Figura 1. Cada paso está etiquetado con su número de paso. Las acciones de RegionServers o Master se muestran en rojo, mientras que las acciones de los clientes se muestran en verde.

1. RegionServer decide localmente dividir la región y prepara la división. Como primer paso, crea un znode en zookeeper en /hbase/region-in-transition/region-name en estado SPLITTING.
2. El maestro aprende acerca de este znode, ya que tiene un observador para el znode principal de la región en transición.
3. RegionServer crea un subdirectorio llamado ".splits" en el directorio de la región principal en HDFS.
4. RegionServer cierra la región principal, fuerza un vaciado de la memoria caché y marca la región como fuera de línea en sus estructuras de datos locales. En este punto, las solicitudes de los clientes que lleguen a la región principal generarán NotServingRegionException. El cliente volverá a intentarlo con un retroceso.
5. RegionServer crea los directorios de regiones en el directorio .splits, para las regiones secundarias A y B, y crea las estructuras de datos necesarias. Luego, divide los archivos de almacenamiento, en el sentido de que crea dos archivos de referencia por archivo de almacenamiento en la región principal. Esos archivos de referencia apuntarán a los archivos de las regiones principales.
6. RegionServer crea el directorio de la región real en HDFS y mueve los archivos de referencia para cada hija.
7. RegionServer envía una solicitud Put al .META. y establece el padre como fuera de línea en el .META. table y agrega información sobre las regiones secundarias. En este punto, no habrá entradas individuales en .META. para las hijas. Los clientes verán que la región principal se divide si escanean .META., pero no sabrán acerca de las hijas hasta que aparezcan en .META. Además, si esto Poner a .META. tiene éxito, el padre se dividirá efectivamente. Si RegionServer falla antes de que este RPC tenga éxito, Master y el siguiente servidor de región que abre la región limpiarán el estado sucio de la división de la región. Después del .META. actualización, sin embargo, la división de regiones será implementada por Master.
8. RegionServer abre hijas en paralelo para aceptar escrituras.
9. RegionServer agrega las hijas A y B a .META. junto con la información que alberga las regiones. Después de este punto, los clientes pueden descubrir las nuevas regiones y enviar solicitudes a la nueva región. Los clientes almacenan en caché el .META. localmente, pero cuando realizan solicitudes al servidor de región o .META., sus cachés se invalidarán y aprenderán sobre las nuevas regiones de .META..
10. RegionServer actualiza znode /hbase/region-in-transition/region-name en zookeeper para indicar SPLIT, de modo que el maestro pueda conocerlo. El equilibrador puede reasignar libremente las regiones hijas a otros servidores de regiones si así lo desea.
11. Después de la división, meta y HDFS seguirán conteniendo referencias a la región principal. Esas referencias se eliminarán cuando las compactaciones en las regiones hijas vuelvan a escribir los archivos de datos. Las tareas de recolección de elementos no utilizados en el maestro verifican periódicamente si las regiones secundarias aún hacen referencia a los archivos principales. De lo contrario, se eliminará la región principal.

Fusiones de regiones

A diferencia de la división de regiones, HBase en este momento no proporciona herramientas utilizables para fusionar regiones. Aunque existen herramientas HMerge y Merge, no son muy adecuadas para el uso general. Actualmente no hay soporte para tablas en línea y funcionalidad de fusión automática. Sin embargo, con problemas como OnlineMerge, fusiones de regiones automáticas iniciadas por Master, bloqueos de lectura/escritura basados ​​en ZK para operaciones de tablas, estamos trabajando para estabilizar las divisiones de regiones y permitir un mejor soporte para las fusiones de regiones. ¡Estén atentos!

Conclusión

Como puede ver, bajo el capó, HBase realiza muchas tareas internas para administrar divisiones de regiones y realizar fragmentaciones automatizadas a través de regiones. Sin embargo, HBase también proporciona las herramientas necesarias en torno a la gestión de regiones, para que pueda gestionar el proceso de división. También puede controlar con precisión cuándo y cómo se realizan las divisiones de región a través de RegionSplitPolicy.

La cantidad de regiones en una tabla y cómo se dividen esas regiones son factores cruciales para comprender y ajustar la carga del clúster de HBase. Si puede estimar su distribución clave, debe crear la tabla con división previa para obtener el rendimiento de carga inicial óptimo. Puede comenzar con un múltiplo menor de la cantidad de servidores de la región como punto de partida para la cantidad inicial de regiones y dejar que la división automatizada se haga cargo. Si no puede estimar correctamente los puntos de división iniciales, es mejor simplemente crear la tabla con una región y comenzar una carga inicial con división automatizada y usar la política de división de región de límite superior. Sin embargo, tenga en cuenta que el número total de regiones se estabilizará con el tiempo y el conjunto actual de puntos de división de regiones se determinará a partir de los datos que la tabla ha recibido hasta el momento. Es posible que desee supervisar la distribución de la carga en las regiones en todo momento y, si la distribución de la carga cambia con el tiempo, utilice la división manual o establezca tamaños de división de región más agresivos. Por último, puede probar la próxima función de fusión en línea y contribuir con su caso de uso.