Habla sobre la optimización del rendimiento de Raft

Inserte la descripción de la imagen aquíEste trabajo está licenciado bajo el Acuerdo de Licencia Internacional de Atribución-Uso No Comercial-Compartir 4.0 de Creative Commons de la misma manera .
Inserte la descripción de la imagen aquíEste trabajo ( Lizhao Long Bowen por la creación de Li Zhaolong ) por la confirmación de Li Zhaolong , por favor indique los derechos de autor.

Introducción

El título de este artículo parece el intercambio de experiencias de un experto técnico, pero de hecho es solo mi conjetura personal, mezclada con ideas de algunos blogs en Internet. Debido a que no realicé ninguna prueba, puede que sea solo una fantasía.

Estrategia de optimización

La mayoría de estas optimizaciones son optimizaciones de implementación industrial, no la optimización del algoritmo en sí. Para cada punto, trato de dar a conocer cuál sería mi enfoque si me di cuenta, y haré que estos métodos sean lo más factibles posible.

Paralelización de registro adjunto y almacenamiento de registro

De hecho, Append Log se ejecuta en paralelo con la persistencia de elementos de registro. El registro de la balsa está naturalmente ordenado, y la escritura secuencial es mucho mejor que la escritura aleatoria en términos de los medios de almacenamiento del disco duro actuales. En términos generales, la persistencia de registros equivale a WAL y el conjunto es secuencial. La paralelización puede provocar escrituras aleatorias en casos extremos, como los siguientes:

Inserte la descripción de la imagen aquí

(C) En 2 (por supuesto, solo se colocan S1 y S2), se han colocado 3 entradas de registro y todas se sobrescribirán en (d).

Pero hacerlo no afectará la seguridad. Si el líder no se bloquea, el resultado del procesamiento es coherente con la secuencia. Si el líder se bloquea, si los seguidores mayores de n / 2 + 1 reciben este mensaje y la adición es exitosa, entonces el registro de la balsa se confirmará y el líder recién elegido responderá al cliente; de ​​lo contrario, el registro de la balsa no Confirmar, se sobrescribirá con el nuevo registro.

Procesamiento por lotes y canalización

Obviamente, estos dos métodos definitivamente pueden mejorar el rendimiento, pero la verdadera dificultad radica en cómo garantizar la corrección. Analicemos los dos por separado de la escena y la corrección.

En primer lugar, dónde aplicar estas dos estrategias de optimización, primero hable sobre la aplicación y luego hable sobre la corrección.

Canalización:

  1. La optimización aquí es necesaria, de lo contrario, el procesamiento general del registro no solo es lineal, sino que también hay un RTT entre el procesamiento de cada solicitud.Cuando el RTT no es pequeño, el rendimiento no debe ser mucho mejor.
  2. El proceso de canalización puede abrir varios subprocesos y enviar en paralelo, y el receptor puede garantizar el orden a través del subíndice.

Para garantizar la corrección de la canalización, debemos hacer dos cosas:

  1. Hace que todas las solicitudes de cada nodo sean procesadas de forma ordenada y en el mismo orden.
  2. El proceso de manejo de solicitudes de falla de conexión es similar al proceso de ventana deslizante, pero antes de que se reciba la entrada de registro con el índice T, la entrada de registro después de T no se puede aplicar incluso si llega. Cuando el seguidor recibe el mensaje Anexar, comprobará si coincide con el último registro de la balsa que se ha recibido. Si no coincide, devolverá un mensaje de rechazo. Luego, de acuerdo con el protocolo de la balsa, el líder volverá a intentarlo desde 3 después de recibir También se enviará el mensaje Rechazar., 4. Después de todo, la probabilidad de esta situación no es grande, por lo que personalmente creo que no habrá problemas importantes con reintentos adicionales.

Procesamiento por lotes:

  1. Podemos aplicarlo cuando el cliente envía una propuesta, fusionar varias propuestas en una obviamente tiene un mejor rendimiento y puede reducir muchos RTT.
  2. Se pueden combinar varias solicitudes cuando se agrega el registro, pero esto es lo que hace la balsa básica.
  3. Por supuesto, los pedidos también se pueden procesar por lotes.

El problema que puede surgir en el procesamiento por lotes de solicitudes es que hay un tiempo de inactividad cuando se ejecuta la mitad del lote, lo que da como resultado un lote de datos que solo se completa parcialmente. Personalmente, creo que la solución más simple es poner estas solicitudes en un registro De hecho, también es equivalente a una solicitud, y luego volver a comprometerse después de que todo esté completo. Es decir, el tiempo de inactividad antes de la confirmación puede hacer que la estructura de datos en esta máquina esté incompleta, pero ha estado inactiva, no importa, por lo que podemos escribir primero en el disco y luego escribir la estructura de datos, lo mismo es cierto. para seguidor De esta forma, el líder volverá a la solicitud cuando finalmente reciba la mayoría de las respuestas, así que eso es todo. Solo un simple pensamiento, puede haber algunas imperfecciones.

Conexión multiplex

Puede haber varios grupos de balsas dentro de una máquina, porque todas las copias de cada grupo establecerán conexiones, por lo que puede haber varios TCP entre varias máquinas, y la sobrecarga de cada conexión es relativamente grande. El costo no se analiza en detalle aquí . En lo que respecta a la parte de la balsa, solo puede haber una conexión entre cada máquina, y cada grupo de balsa tiene una etiqueta única, de modo que cada paquete se puede entregar a un grupo diferente.

Esto no parece difícil, personalmente creo que es bastante complicado de implementar, es necesario que varios subprocesos compartan esta conexión. El método simple es que un subproceso recibe datos de esta conexión y luego envía los datos a diferentes subprocesos receptores. Aquí hay un escenario con un solo escritor y varios lectores. Por supuesto, creo que la forma más elegante es que este único hilo recibe datos de la conexión, mantiene los kfifos del grupo de balsa y coloca diferentes datos en diferentes kfifos, de modo que el proceso de distribución sin bloqueos se completa con elegancia.

Registro de fragmentos comprimidos

En la implementación de ChubbyGo, la función de fragmentación no se implementa durante la compresión de registros, pero debido a que la posibilidad de que los registros se queden atrás es relativamente baja, todo el envío de todos los registros es muy poco elegante, por lo que la fragmentación es un enfoque muy necesario. 7 describe esta optimización.

Fusión de paquetes de latidos

El paquete de latidos es para asegurar la conectividad entre máquinas. Obviamente, varios grupos de balsa de una máquina no mantienen múltiples conexiones, lo cual no tiene sentido. La combinación de latidos de Raft, cuando hay muchos Raft-Group en un nodo, se puede guardar una gran cantidad de paquetes de latidos.

Esto también significa que necesitamos modificar varios temporizadores de grupos de balsa en la función de devolución de llamada del paquete de latidos. Por supuesto, la configuración de parámetros de la devolución de llamada aquí también se estima que es problemática, porque este proceso de procesamiento de latidos es independiente de la balsa. grupo, y es necesario pasar algunos parámetros.Pueden modificarse, por supuesto, estos grupos de balsa deben ser internos a un proceso. No puedo pensar en otros detalles en este momento.

Almacenamiento de registros

Esta parte es el punto débil de ChubbyGo. El diseño duradero en ese momento puede describirse como descuidado.

El enfoque correcto debe basarse en el proceso WAL.

El proceso general es el siguiente:

  1. balsa recibe un dato
  2. Resistencia
  3. Solicitar compromiso
  4. comprometerse con éxito
  5. Registro de ejecución de la aplicación superior

Esto garantiza que, si la confirmación se realiza correctamente, los datos se conservarán en la mayoría de los nodos del clúster.

La transición de estado general es así, el verde es in-memory, el azul es in-disk:
Inserte la descripción de la imagen aquí

Pero cuando los datos de nivel superior se appliedaplican realmente , los datos no están en la memoria, lo que requiere una E / S, y la E / S de disco es un asesino del rendimiento, operaciones de nivel de milisegundos (por supuesto, sin considerar la caché de página), por lo que podemos mantener una caché en modo de usuario, para mejorar el rendimiento.

Personalmente, creo que la organización de la caché aquí es en realidad una matriz y un subíndice de punto de compresión.

Leer optimización ReadIndex y LeaseRead

Si cada operación de lectura necesita pasar por el proceso de balsa, será demasiado lento, por lo que puede consultar la semántica de un cliente FIFO proporcionada por zk, cada cliente lleva uno en la solicitud ReadIndexy el registro debe ser mayor que este punto antes de que pueda ser devuelto En este caso, la semántica de un cliente FIFO puede satisfacerse y un solo nodo esclavo puede ejecutar la solicitud.

Para lograr la ReadIndexfunción esperada , es necesario ejecutar una devolución de llamada para cada paquete de datos entrante. Cuando aparece el valor objetivo, se llama a una serie de devoluciones de llamada, que es similar a la cola de espera del kernel. Hay un montón de procesos colgando Cuando llega el evento esperado, todos son activados.

Por supuesto, también es posible asegurar una fuerte consistencia, es decir, solo el nodo maestro puede recibir solicitudes de lectura. Esta Readindexsolución es mucho más rápida que la operación de lectura que se ejecuta a través del proceso . Por supuesto, LeaseReades una optimización para la primera. Por supuesto, solo en el caso del líder, en general, no habrá una situación en la que el índice solicitado sea mayor que el índice real actual, así que básicamente lo es wait-free.

PreVote

Para evitar un aumento repentino en el término de una partición, que afecta a todo el protocolo después de que finaliza la partición (el nodo con un término más alto se llama líder), se puede introducir el mecanismo PerVote para resolver el problema. se Candidateintroduce uno nuevo antes de convertir la identidad. Es decir PreCandidate, su función es enviar un paquete preelectoral, donde Término es su propio Término + 1. Tenga en cuenta que el Término real del nodo no aumenta ahora, y el La elección se lleva a cabo después de recibir la respuesta de la mayoría de los nodos El tiempo también es un término real de autoincremento.

Este mecanismo evita los problemas mencionados anteriormente, es decir, el costo de la elección es una ronda más de transmisión de mensajes, de hecho, el problema no es muy grande, porque el tiempo de inactividad del líder no es una ocurrencia común.

Eso sí, en cuanto a detalles de implementación, tenemos que poder distinguir la diferencia entre los dos paquetes de preelección y electoral, porque en el paquete de elecciones generales se detecta que el plazo del extremo opuesto es mayor, y establecerá directamente su propio Término como el tamaño del extremo opuesto. Por supuesto, esto no es difícil, solo ponga una marca en la bolsa.

gestión de instantáneas

Haidong hizo esta pregunta durante la entrevista simulada. En ese momento, habló sobre fragmentación, compresión y la misma E / S de red de optimización de subprocesos múltiples que redis.

Mirando hacia atrás en este problema nuevamente, en una RPC que instala una instantánea, si todas las instantáneas se envían en el pasado, existen varios problemas:

  1. El volumen de datos de una RPC es demasiado grande, lo que supone un desafío para la memoria y puede producirse un cuello de botella de E / S de red.
  2. Si falla, el reintento general es demasiado costoso (¿ha pensado en el uso de árboles merkle en Dynamo?).
  3. Difícil de controlar el flujo.

En Elasticellla Multi-Raftimplementación de este problema, los siguientes pasos de optimización se utilizan para reducir el costo de reintento y el tráfico es más uniforme (por supuesto, solo es efectivo cuando se encuentra realmente que la E / S de la red es el cuello de botella, pero una instantánea de solo unos pocos G no es demasiado, uno El rendimiento de una tarjeta de red gigabit es inferior a 125 MB / S, y la probabilidad de que se produzca un cuello de botella en la E / S de la red sigue siendo muy grande):

  1. Almacenamiento de datos en la instantánea RPC de Raft, metadatos del archivo de instantánea (incluido el ID del fragmento, el término actual de Raft, índice, época, etc.)
  2. Después de enviar el RPC de instantánea de Raft, envíe archivos de datos específicos de forma asincrónica
  3. Los archivos de datos se envían en trozos y el costo de volver a intentarlo es pequeño
  4. El enlace para enviar Chunk y el enlace a Raft RPC no se reutilizan
  5. Limite la cantidad de fragmentos que se pueden enviar en paralelo para evitar que el envío de archivos de instantáneas afecte el RPC normal de Raft (después de todo, el rendimiento de la tarjeta de red tiene un límite superior)
  6. La recepción de la copia fragmentada de la instantánea de Raft se bloquea hasta que se recibe el archivo de datos de la instantánea completo (no está claro cuál es el uso de esto)

Multi-balsa

El Sr. Zong Dai me hizo esta pregunta durante la entrevista. De hecho, esta no es la primera vez. Recuerdo que Huan Shen me mencionó esto cuando vino al grupo el año pasado, pero más tarde debido a asuntos triviales, no lo hizo ' Piense detenidamente en este problema. Afortunadamente, la entrevista se ha estabilizado recientemente y finalmente tengo tiempo para pensar.

En primer lugar, ¿cuáles son los tres vínculos mortales? ¿Por qué? ¿Qué puedes hacer?

La definición de cucaracha de Multi-Raft [5] [10] se cita aquí para explicar los dos primeros puntos:

  • En CockroachDB, utilizamos el algoritmo de consenso de Raft para garantizar que sus datos permanezcan consistentes incluso cuando las máquinas fallan. En la mayoría de los sistemas que utilizan Raft, como etcd y Consul, todo el sistema es un grupo de consenso de Raft. En CockroachDB, sin embargo, los datos se dividen en rangos, cada uno con su propio grupo de consenso. Esto significa que cada nodo puede participar en cientos de miles de grupos de consenso. Esto presenta algunos desafíos únicos, que hemos abordado mediante la introducción de una capa encima de Raft que llamamos MultiRaft.
  • Cuantos más nodos, peor es el rendimiento
    La capacidad de almacenamiento del sistema depende del tamaño del disco de la máquina líder
  • En CockroachDB, utilizamos el algoritmo de consenso de Raft para garantizar que sus datos sigan siendo consistentes incluso si la máquina falla. En la mayoría de los sistemas que utilizan Raft, como etcd y Consul, todo el sistema es un grupo de consenso de Raft. Sin embargo, en CockroachDB, los datos se dividen en varios rangos y cada rango tiene su propio grupo de consenso. Esto significa que cada nodo puede participar en miles de grupos de consenso. Esto presenta algunos desafíos únicos, que resolvimos al introducir una capa llamada MultiRaft en la parte superior de Raft .
  • Cuantos más nodos, peor es el rendimiento. La capacidad de almacenamiento del sistema depende del tamaño del disco host (líder).

La definición de Multi-balsa en TiKV es muy clara en [8]:

  • Si ha investigado Consensus antes, tenga en cuenta que comparar Multi-Raft con Raft no es en absoluto como comparar Multi-Paxos con Paxos. Aquí Multi-Raft solo significa que administramos múltiples grupos de consenso de Raft en un nodo. De la sección anterior, sabemos que hay varias particiones diferentes en cada nodo, si solo hay un grupo de balsa para cada nodo, las particiones pierden su significado. Por lo tanto, el grupo de balsa se divide en varios grupos de balsa en términos de particiones, es decir, Región.
    Si antes Habiendo estudiado el consenso, debe tener claro que comparar Multi-raft con raft no es como comparar multi-Paxos con Paxos en absoluto . Aquí, el protocolo de balsa múltiple solo significa que gestionamos varios grupos de consenso de balsa en un nodo. De la sección anterior, sabemos que hay múltiples particiones diferentes en cada nodo, si cada nodo tiene un solo grupo Raft, estas particiones perderán su significado. Por lo tanto, el grupo de balsa se divide en varios grupos de balsa según la partición (es decir, el área).
  • TiKV también puede dividir o fusionar regiones para hacer que las particiones sean más flexibles. Cuando el tamaño de una región excede el límite, se dividirá en dos o más regiones, y el rango puede cambiar como [a, c) [a, c) -> [a, b) [a, b) + [b, c) [b, c); cuando los tamaños de dos Regiones hermanas son lo suficientemente pequeños, se fusionarán en una Región más grande, y el rango puede cambiar como [a, b) [a, b) + [b, c) [b, c) -> [a, c) [a, c).
    TiKV también puede realizar división o fusión en regiones para hacer que el particionamiento sea más flexible. Cuando el tamaño del área excede el límite, se dividirá en dos o más áreas, el rango puede ser como [a, c) -> [a, b) + [b, c); si el tamaño es lo suficientemente pequeño , se fusionarán en un área más grande, y el rango puede ser como [a, b) + [b, c) -> [a, c).

+

La razón principal de este tipo de fragmentación es que una sola balsa es propensa a los siguientes problemas en el escenario KV:

  1. Cuello de botella de potencia de computación de una sola máquina (para una gran consistencia, solo Leader puede manejar solicitudes de escritura)
  2. Cuellos de botella de almacenamiento autónomo (excepto aquellos que utilizan sistemas de almacenamiento distribuido como motores de almacenamiento como bigtable, por supuesto),
  3. No es posible que todos los nodos puedan proporcionar servicios.

La solución a los problemas anteriores puede ser la fragmentación, y la balsa múltiple se basa en la fragmentación. Esto no solo aumenta el límite superior de potencia de cálculo y almacenamiento, sino que también paraleliza las operaciones en serie anteriores . Debido a que un nodo puede ser un líder o un seguidor, es equivalente a un tiempo de inactividad de la máquina a gran escala que aún puede garantizar el funcionamiento normal de la mayoría de los servicios .

Como se indica en [5], muchos problemas básicos deben resolverse, de la siguiente manera:

  1. Cómo fragmentar : Creo que el hash consistente es una solución deseable. TiKV puede basarse en hash y rango.
  2. Los datos de los fragmentos son cada vez más grandes, y es necesario dividir más fragmentos para formar más grupos de balsa .
  3. Programación de fragmentación : haga que la carga en el sistema sea más uniforme. Cucaracha se refiere al PD de TiKV en la parte de programación. Aquí, PD es responsable de la emisión de instrucciones de programación, de las cuales hay dos recursos más importantes, a saber, almacenamiento de almacenamiento y líder de computación . El PD recopila los datos necesarios para la programación a través de latidos. Estos datos incluyen: el número de fragmentos en el nodo, el número de líderes en el fragmento, el espacio de almacenamiento del nodo, el espacio de almacenamiento restante, etc.
  4. Cómo los nuevos fragmentos forman un grupo de balsa.

Las preguntas anteriores se responden en detalle en [5].

Sin embargo, todavía existen algunas dudas en este momento:

  1. ¿Se convertirá la propia DP en un solo punto?
  2. Se pueden fusionar dos particiones. Dado que el registro se separará cuando haya más de un intervalo, ¿cada grupo de balsa realiza la compresión del registro? Si este es el caso, ¿cómo sincronizar el tiempo de compresión del registro entre el maestro y el esclavo? ellos ya el líder? Los detalles aquí no se pueden resolver en poco tiempo.

Parece que la fragmentación de aplicaciones Multi-raft ha mejorado enormemente el rendimiento general, pero esto se parece más a una optimización a nivel industrial que a una optimización a nivel de algoritmo.

para resumir

La mayoría de ellos son optimización de detalles industriales y no hay mucha información sobre la optimización del nivel de algoritmo. Puede pertenecer a los secretos de grandes empresas como Multi-Paxos.

referencia

  1. Elasticell-Talk sobre la optimización de Raft
  2. Haz Raft 100 veces más rápido: optimización de escritura de Dragonboat
  3. Linealidad y Balsa
  4. Mecanismo de implementación de PreVote de Raft
  5. Implementación de Elasticell-Multi-Raft
  6. Uso de kfifo
  7. Introducción a la función TiKV-PD Scheduler
  8. Estante múltiple TiKV
  9. Fragmentación de datos TIKV
  10. Balsa múltiple Elasticell
  11. Basado en la optimización profunda de Raft, explicación detallada del algoritmo de alta confiabilidad CMQ de cola de mensajes de nivel financiero de Tencent Cloud

Supongo que te gusta

Origin blog.csdn.net/weixin_43705457/article/details/115014226
Recomendado
Clasificación