Sin categoría

Reequilibrio con Couchbase Parte I

Esta es la primera de dos entradas de blog que se adentran en algunos de los detalles de la tecnología de reequilibrio de Couchbase. El primero detalla la funcionalidad de reequilibrio en sí, y el segundo explica cómo controlarlo y trabajar con él.

Guía práctica para el reequilibrio con Couchbase

A mediados de 2010, una pequeña empresa llamada NorthScale presentó un producto llamado Membase. Una de sus muchas características revolucionarias era la posibilidad de ampliar (o reducir) dinámicamente un clúster de "nodos" (instancias del software). Por su diseño, se trata de una operación en línea, es decir, que no afecta a la disponibilidad de los datos almacenados en el clúster ni al rendimiento de las aplicaciones que acceden a ellos.

Un avance rápido hasta ahora (finales de 2011... vale, fue un avance rápido). Desde entonces, la empresa ha cambiado de nombre (dos veces) a Couchbase, y ha aprendido muchísimo sobre cómo funciona el producto "en el mundo real". Se está desplegando en entornos drásticamente diferentes (piense en su propio centro de datos frente a la nube de Amazon) bajo aplicaciones drásticamente diferentes (piense en el registro frente a los juegos sociales frente a la orientación de anuncios). La misma tecnología de "reequilibrio" se está empleando no sólo en Membase, sino también en el próximo Couchbase Server 2.0. Pensé que ahora podría ser un buen momento para escribir este artículo bastante largo para responder a muchas de las preguntas que rodean este proceso, así como abordar algunos de los problemas conocidos. La versión actual es 1.7.1.1, y ha recorrido un largo camino desde la primera versión beta de 1.6.0 en aquel memorable verano de 2010.

Basta de introducción, veamos hasta dónde podemos llegar en la madriguera del conejo...

¿Qué es un reequilibrio?

Empecemos por el principio. El reequilibrio es el proceso de redistribución de datos a nodos añadidos o eliminados dentro de un clúster de Membase/Couchbase Server.

Suena bastante sencillo, ¿verdad? Para el observador casual, lo es. Y eso es lo que pretendemos. Al igual que la mayoría de las demás tecnologías, se necesita bastante complejidad para lograr esta simplicidad (distracción total: https://plus.google.com/112218872649456413744/posts/dfydM2Cnepe).

Un nivel abajo ahora.

Para empezar a entender cómo funciona Membase/Couchbase Server, el principal concepto subyacente son los vbuckets (http://dustin.github.com/2010/06/29/memcached-vbuckets.html). Un vbucket es una "porción" lógica de un conjunto de datos global (en nuestro caso, un bucket... perdón por el nombre, todavía no teníamos un equipo de marketing de producto cuando surgió esto). Hay un número estático de estos vbuckets y las claves se codifican (mediante CRC32) en esa lista estática. De esta forma, se garantiza que una clave determinada siempre se hasheará con el mismo vbucket. Cada vbucket se asigna a un servidor determinado dentro del clúster. Con 256 vbuckets y un servidor, todos estarían en el mismo servidor. Con 2 servidores, se repartirían a partes iguales entre los dos con 128 buckets cada uno, a cuatro servidores se les asignarían 64 a cada uno y así sucesivamente.

Un 'vbucket map' es simplemente la enumeración de esta lista de vbuckets y los servidores que los poseen.

Por el momento estoy ignorando a propósito la replicación... volveré a ella, pero no es importante en este momento.

Un reequilibrio es simplemente (ahí está esa palabra otra vez...) el proceso de mover un cierto número de vbuckets de unos servidores a otros. El objetivo final es que cada servidor dentro del cluster termine con el mismo número de vbuckets. Esto garantiza que los datos se distribuyan uniformemente por todo el clúster y, por lo tanto, el acceso de la aplicación a esos datos también se equilibra uniformemente entre todos los nodos del clúster.

¿Estás conmigo hasta ahora? (si no, envía un correo electrónico a perry@couchbase.com).

Y otro nivel.

Cuando se inicia un reequilibrio, un proceso llamado "orquestador" examina el mapa de vbuckets actual y lo combina con cualquier adición/eliminación de nodos para calcular cómo debe ser el nuevo mapa de vbuckets. El orquestador comienza entonces a iniciar el movimiento de vbuckets de un nodo a otro. Es importante tener en cuenta que el orquestador simplemente "inicia el proceso" entre dos nodos, pero no transfiere realmente los datos en sí... eso se deja a propósito para que los nodos de origen y destino se coordinen para evitar cuellos de botella o puntos de fallo. Desde la perspectiva del orquestador, no importa si se añade o se elimina un nodo del clúster. De hecho, se pueden añadir y/o eliminar varios nodos del clúster en el mismo reequilibrio. Lo único que ocurre es que se calcula un nuevo mapa de vbucket y se inician los movimientos de vbucket para hacer realidad ese mapa.

Cada vbucket se mueve de forma individual e independiente de los demás (se pueden mover varios en paralelo, pero la cuestión es que no hay relación entre vbuckets únicos). El nodo de destino inicia un proceso llamado 'ebucketmigrator' que abre una conexión TAP (http://www.couchbase.org/wiki/display/membase/TAP+Protocol) a un vbucket en el nodo de origen. Esta conexión tiene banderas específicas que indican que a) quiere todos los datos que contiene y b) planea "tomar el control" de ese vbucket cuando todo esté hecho.

Esta última parte indica al nodo de origen que inicie el proceso de conmutación tan pronto como se envíen todos los datos. (lección de historia: ebucketmigrator solía llamarse vbucketmigrator pero lo trasladamos a la VM Erlang...de ahí la 'e')

Mientras se traslada cada vbucket, el acceso del cliente (lecturas y escrituras) sigue yendo a la ubicación original. Una vez que todos los datos se han copiado, se produce una conmutación atómica en la que la ubicación original dice "ya no soy el maestro de este vbucket" y envía un "token" al vbucket recién creado diciendo "tú lo eres". El vbucket original pasa de activo a muerto, y el nuevo pasa de pendiente a activo. Los clientes inteligentes y Moxi se actualizan con un nuevo mapa vbucket para saber que esto ha tenido lugar y las solicitudes de datos posteriores se dirigen a la nueva ubicación. (ver unas secciones más abajo para una discusión aún más profunda de Moxi y el comportamiento del cliente inteligente)

Y ahora el nivel inferior

Al menos hasta donde yo voy a llegar. Aviso: Esto se va a poner bastante técnico. Sáltate una sección si tienes poco tiempo.

Como se mencionó anteriormente, el orquestador dirigirá el proceso ebucketmigrator en el nodo de destino para "extraer" un vbucket del nodo de origen a través de TAP.

Conexiones TAP en el nodo de origen

Cuando se inicia la conexión TAP con el nodo de origen, un "cursor" comienza a recorrer la tabla hash dentro del vbucket en cuestión. Paralelamente, un proceso de 'backfiller' se inicia y decide si cargar los datos desde el disco. Como probablemente sepas, Membase/Couchbase soporta sin problemas tener más datos en el sistema que RAM disponible. En este caso, puede haber una cantidad significativa de datos que necesiten ser leídos del disco para ser transferidos a otro nodo. El proceso de backfiller se fija en el "ratio de elementos residentes" (cantidad de datos almacenados en caché en la RAM frente a los que no). Si ese ratio es inferior a 90%, carga todo el vbucket desde el disco a un búfer RAM temporal (hay topes y retrocesos incorporados para garantizar que no se sobrepase la capacidad RAM del nodo). Si el ratio de elementos residentes es superior a 90%, este proceso no tiene lugar.

A medida que el cursor recorre la tabla hash, comienza a transmitir las claves y los documentos a través de la conexión TAP. Todo lo que ya está en caché en la RAM se envía muy rápidamente, cualquier otra cosa se toma de ese espacio de búfer temporal (si está disponible) o se lee de forma puntual desde el disco.

Durante este proceso, las mutaciones de los datos que ya se han enviado se transmiten a través del flujo TAP a medida que se producen (técnicamente se ponen en cola, pero de todos modos se producen rapidísimamente). Las mutaciones de los datos que aún no se han enviado se aplican únicamente al vbucket de origen y se recogerán cuando se transmita ese documento concreto.

Una vez que todos los datos se han copiado y sincronizado, se produce la conmutación. Técnicamente, sería posible transmitir los cambios tan rápidamente a un vbucket que éste nunca pudiera ponerse al día y conmutar. En la práctica, esto nunca ocurre. Cualquier breve retraso en el lado del cliente entre peticiones es suficiente para conseguir los últimos bits y sería extremadamente raro que la comunicación entre nodos fuera drásticamente más lenta que la comunicación cliente-servidor.

Conexiones TAP en el nodo de destino

En general, el extremo receptor de una conexión TAP no recibe un trato muy diferente al de un cliente normal que introduce datos en el vbucket concreto de ese nodo. Hay algunas excepciones:

  • El vbucket del lado de destino está en estado "pendiente". Esto significa que los datos que contiene no son accesibles más que para el flujo TAP que envía el tráfico al vbucket.
  • Los datos no se replican. Tradicionalmente, la introducción de datos en un vbucket provocaba su replicación en la réplica de ese vbucket. Esto no ocurre con los vbuckets pendientes.
  • Backoffs TAP (éste es importante): Para evitar que un nodo de origen rápido abrume a un nodo de destino más lento, existe una parte especial del protocolo TAP llamada "backoffs". Esto permite al destino decirle al emisor "¡PARA! ¡ESPERA! Necesito más tiempo...". Cuando el remitente recibe este mensaje, retrocede y vuelve a intentar la petición tras un breve periodo de tiempo. Actualmente, estos retrocesos se activan cuando la cola de escritura en disco del destino alcanza 1 millón de elementos. Esto se mide a través de todos los vbuckets en ese nodo, y puede ser una combinación de tráfico de aplicación, así como el tráfico de reequilibrio. Más adelante se explica cómo monitorizarlo.

Enhorabuena, ahora eres un reequilibrador de nivel 4. Sé que ha sido un viaje vertiginoso, gracias por seguir conmigo.

Replicación y reequilibrio

No hay mucho que decir aquí, pero no quería omitirlo por completo. Cada vbucket se replica 1, 2 o 3 veces a sus vbuckets "réplica". Durante un rebalanceo, estas réplicas de vbuckets se mueven también para asegurar un cluster equilibrado, y se crean si no existían ya. Por ejemplo, un único nodo no tiene réplicas. Cuando añades el segundo, se crean esas réplicas. Si el número de réplicas es superior a 1, al añadir más nodos se crearán aún más réplicas. Es importante ser consciente de esto ya que hay una multiplicación de los datos que se mueven cuando hay múltiples réplicas involucradas.

Hay algunos trucos especiales empleados durante un reequilibrio para no tener que mover tanto un vbucket activo como su réplica. Si el algoritmo lo dicta, el software es capaz de conmutar un vbucket activo y una réplica "en su sitio" y luego sólo mover la réplica.

Por último (al menos para este tema), todo el proceso de reequilibrio no se completa hasta que las réplicas se han "puesto al día" suficientemente con sus vbuckets activos, lo que también puede aumentar el tiempo que tarda un reequilibrio. Se trata de una evolución de la implementación original, que sólo se ocupaba de los vbuckets activos. Esto causaba dos problemas. Uno es que el reequilibrio se "realizaba" antes de que el clúster estuviera realmente seguro. En segundo lugar, se producía una carga inmensa en todo el clúster cuando finalizaba el reequilibrio para reinstalar las réplicas. La versión actual (1.7.1) ha cambiado este comportamiento para que coincida con lo que he descrito anteriormente en este párrafo.

Clientes Moxi y Smart durante un reequilibrio

Aunque este no es el lugar para una descripción completa del funcionamiento interno, usted querrá entender las ideas básicas para todos los clientes inteligentes y Moxi.

Cuando un cliente o Moxi se inicia, se conecta a la URL de cualquier nodo Membase (a través del puerto 8091 utilizando HTTP). Se autentica si es necesario (sólo no es necesario para el bucket por defecto) y recibe un mapa vbucket. Esto es lo que se denomina una 'conexión streaming' o 'comet stream' y la conexión HTTP permanece abierta (al igual que la conexión TCP, creo). Ese es el final de la comunicación cuando todo es estable.

Si el cliente sale o se reinicia, volverá a pasar por ese proceso. Si se cierra la conexión, también intentará reconectarse. Si el nodo con el que estaba hablando primero no responde, irá al siguiente de su lista (suponiendo que hayas proporcionado una lista... la mejor práctica aquí). Da vueltas hasta que consigue que uno responda, y entonces permanece conectado. Ten en cuenta que no se conecta a todos los nodos de su lista, sólo a uno cada vez.

Ahora, durante un reequilibrio, hay algunos matices. Por diseño, cada movimiento de vbucket se comunica al cliente a través de esta conexión. En realidad, no es así. Las versiones anteriores esperaban hasta el final del reequilibrio para enviar una nueva lista. Ahora, la lista actualizada se envía antes de que hagamos el reequilibrio (lo que se llama un "mapa de avance rápido") y depende del cliente "averiguarlo" a medida que avanza el proceso (más sobre esto más adelante).

Cuando un cliente (o Moxi) envía peticiones al clúster, toma la clave y la compara con la lista de vbuckets. Luego mira el mapa que tiene para determinar qué servidor está activo para ese vbucket. Si su mapa es correcto, el servidor aceptará la petición (sea cual sea, todas las operaciones tienen una clave y un id de vbucket). Si el vbucket id que el cliente/Moxi está enviando a un servidor no está activo en ese servidor, responderá con un error diciendo 'no es mi vbucket'. Durante un rebalanceo, si un cliente/Moxi no se actualiza a tiempo, tiene algunas peticiones 'en vuelo' o de alguna manera se pierde el memo, el nodo antiguo responderá con un error 'not my vbucket' a cualquier petición después de este punto en el tiempo.

Aunque técnicamente es un error, este mensaje es en realidad una señal para el cliente/Moxi de que tiene que ir a buscar el lugar correcto para esa petición y retransmitirla. Esto es para asegurar que nunca haya clientes accediendo a los mismos documentos en más de un lugar. En el nivel más bajo, esto es sólo un error diciendo que la solicitud no era correcta para este servidor. Más arriba en la pila, depende del cliente/Moxi entender que esto significa que necesita encontrar el lugar correcto.

Aquí es donde las cosas empiezan a divergir un poco en cada implementación. Por ejemplo, Moxi originalmente sólo la fuerza bruta intentó cada servidor en el clúster. Si ninguno respondía, enviaba ese error al cliente (memcached heredado) que no tenía ni idea de qué hacer con él. Ahora, manejamos eso mucho mejor y la implementación actual es hacer que Moxi consulte el nuevo mapa 'fast-forward' que obtuvo al principio del reequilibrio. La idea básica es que los clientes inteligentes sigan la misma lógica, aunque cada implementación sea ligeramente diferente.

En general, hay muy poco tráfico en este "canal de gestión" para clientes/Moxi. Realmente sólo cuando un cliente se conecta o durante un reequilibrio e incluso entonces es una cantidad muy baja de tráfico.

Hace poco surgieron las siguientes preguntas, así que pensé en abordarlas aquí:

"Hola Perry, tengo un usuario que tiene lo que ellos describen como una red inestable, ya sea debido a las reglas del cortafuegos o la conectividad y quería saber lo que sucede durante un reequilibrio cuando el mapa vbucket se actualiza, pero la máquina cliente no está disponible? Veo que el cluster empuja cosas como esta al cliente a través de 8091 y HTTP pero ¿mantiene una conexión persistente o el cluster sólo se conecta al cliente cuando hay una actualización que necesita saber?

Les preocupa que tras un reequilibrio el cliente pueda tener un mapa obsoleto y quieren saber más detalles sobre cómo se gestiona eso".

Y mi respuesta detallaba estos dos puntos:

  • La conexión se mantiene siempre abierta. Los clientes siempre se conectan al clúster, no al revés... el clúster empujará un nuevo mapa sobre las conexiones existentes.
  • Un cliente que pierda la conexión con el clúster intentará restablecerla (configurable). Cada vez que se vuelva a conectar (por primera vez o no) obtendrá el último mapa que tenga el clúster. Irónicamente, una red defectuosa en teoría podría ayudar aquí a mantener el mapa constantemente actualizado durante un reequilibrio, pero eso es para otra discusión.

Resumen

Si has llegado hasta aquí, no sólo sabes lo que es el reequilibrio, sino que también sabes cómo funciona. Eso debería ayudarte enormemente cuando hagas crecer tu clúster para que entiendas mejor lo que está pasando entre bastidores, tanto en tus servidores como en tus clientes.

En segunda parte examina cómo supervisar el clúster y el progreso del reequilibrado, cómo gestionar los fallos y cómo puede verse afectado (y mitigado) el rendimiento del clúster durante el proceso de reequilibrado.

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por Perry Krug

Perry Krug es Arquitecto en la Oficina del CTO centrado en soluciones para clientes. Lleva más de 8 años en Couchbase y más de 12 trabajando con sistemas de caché y bases de datos de alto rendimiento.

4 Comentarios

  1. Gracias por la entrada del blog. Realmente útil para entender un poco más acerca de cómo funciona la replicación couchbase. Una pregunta extra, ¿ha cambiado esto de manera significativa en la versión actual de couchbase 3.0 o la idea general de una aplicación sigue siendo como se describe en la entrada del blog.
    Actualmente estoy probando couchbase para ver si se adapta a las necesidades de nuestra empresa. Estamos creando millones de documentos y realizando lecturas casi instantáneas después. Queríamos saber cómo se comportaría Couchbase durante un fallo de nodo. Durante una prueba, mato un nodo servidor en mi cluster para ver como couchbase maneja esto usando failover automático. Parece que puede manejar las peticiones de una manera aceptable hasta que llego al reequilibrio, entonces obtengo errores de conexión en el cliente java 2.0.1. ¿Hay alguna razón por la que esto sucede?
    ¿Debo reequilibrar sólo cuando haya terminado el proceso de inserción? Si es así, esto no suena muy bien porque tenemos un gran número de transacciones y en caso de fallo, vamos a conmutar por error un nodo, y luego reequilibrar hasta que tengamos todos nuestros nodos de nuevo y el clúster a un estado óptimo de nuevo.
    Salud,
    Ivan

  2. Gracias por escribir, Iván.

    Este post es bastante antiguo, pero los conceptos básicos siguen siendo los mismos. El mayor cambio en la versión 3.0 fue la desaparición de TAP y la introducción de un Protocolo de Cambio de Base de Datos (DCP) que nos da mucha más flexibilidad y funcionalidad para mover/replicar datos alrededor del cluster, a otros clusters y eventualmente a herramientas de terceros. DCP se utiliza básicamente de la misma forma que TAP para los fines de replicación y reequilibrio descritos anteriormente.

    En cuanto a los problemas que está viendo, eso no es de esperar. El reequilibrio se realiza con poco o ningún impacto en la aplicación y es muy utilizado por nuestros clientes, así como muy probado en QA. Le ruego que se ponga en contacto con nosotros a través de las listas de correo o directamente (perry@couchbase.com) para que un técnico pueda ayudarle.

    Gracias de nuevo, espero poder ayudarte.

    Perry

    1. ¿Ustedes soportan el rebalanceo usando SSL o alguna otra conexión segura? Tenemos requisitos de seguridad para SSL en todas partes, incluso de nodo a nodo en nuestra pila.

      1. Hola Kevin, gracias por escribirnos. Por el momento no tenemos encriptación entre nodos de un cluster (sí soportamos encriptación entre clusters) pero es algo que ha sido discutido como parte de nuestra hoja de ruta de seguridad. Si quieres enviarme un correo electrónico privado, podría ponerte en contacto con nuestro Gerente de Producto de Seguridad para ayudar a entender tus necesidades y cómo podríamos abordarlas.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.