Por que podes necesitar unha replicación semisíncrona?

Ola a todos. Vladislav Rodin está en contacto. Actualmente imparto cursos de Arquitectura de software e Arquitectura de software de alto estrés en OTUS. En previsión do inicio dun novo curso de fluxo "Arquitecto de alta carga" Decidín escribir un pequeno anaco de material orixinal que quero compartir con vós.

Por que podes necesitar unha replicación semisíncrona?

Introdución

Debido ao feito de que o disco duro só pode realizar unhas 400-700 operacións por segundo (o que é incomparable cos rps típicos nun sistema de alta carga), a base de datos de disco clásica é o pescozo de botella da arquitectura. Polo tanto, é necesario prestar especial atención aos patróns de escala deste almacenamento.

Actualmente, hai 2 patróns de escalado de bases de datos: replicación e fragmentación. Sharding permítelle escalar a operación de escritura e, como resultado, reducir os rps por escritura por servidor no seu clúster. A replicación permítelle facer o mesmo, pero con operacións de lectura. É a este patrón ao que se dedica este artigo.

Replicación

Se miras a replicación a un nivel moi alto, é unha cousa sinxela: tiñas un servidor, había datos nel e entón este servidor xa non podía soportar a carga de ler estes datos. Engades un par de servidores máis, sincronizas os datos en todos os servidores e o usuario pode ler desde calquera servidor do teu clúster.

A pesar da súa aparente sinxeleza, hai varias opcións para clasificar varias implementacións deste esquema:

  • Por roles no clúster (mestre-mestre ou mestre-escravo)
  • Por obxectos enviados (baseados en filas, en instrucións ou mixtos)
  • Segundo o mecanismo de sincronización de nodos

Hoxe trataremos o punto 3.

Como se produce un compromiso de transacción?

Este tema non está directamente relacionado coa replicación; pódese escribir un artigo separado sobre el, pero como unha lectura adicional é inútil sen comprender o mecanismo de commit transacción, permíteme lembrarche as cousas máis básicas. Un compromiso de transacción ocorre en 3 etapas:

  1. Rexistro dunha transacción no rexistro da base de datos.
  2. Usando unha transacción nun motor de base de datos.
  3. Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.

En diferentes bases de datos, este algoritmo pode ter matices: por exemplo, no motor InnoDB da base de datos MySQL hai 2 rexistros: un para replicación (rexistro binario) e outro para manter ACID (rexistro desfacer/refacer), mentres que en PostgreSQL hai un rexistro que realiza ambas funcións (rexistro de escritura anticipada = WAL). Pero o que se presenta anteriormente é precisamente o concepto xeral, que permite non ter en conta tales matices.

Replicación síncrona (sincronizada).

Engademos lóxica para replicar os cambios recibidos no algoritmo de confirmación da transacción:

  1. Rexistro dunha transacción no rexistro da base de datos.
  2. Usando unha transacción nun motor de base de datos.
  3. Envío de datos a todas as réplicas.
  4. Recibindo confirmación de todas as réplicas de que se realizou unha transacción con elas.
  5. Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.

Con este enfoque temos unha serie de desvantaxes:

  • o cliente agarda a que se apliquen os cambios a todas as réplicas.
  • a medida que aumenta o número de nodos do clúster, diminuímos a probabilidade de que a operación de escritura teña éxito.

Se todo está máis ou menos claro co 1o punto, vale a pena explicar os motivos do 2o punto. Se durante a replicación síncrona non recibimos unha resposta de polo menos un nodo, retrocedemos a transacción. Así, ao aumentar o número de nodos do clúster, aumenta a probabilidade de que falle unha operación de escritura.

Podemos esperar a confirmación de só unha determinada porcentaxe de nós, por exemplo, do 51% (quórum)? Si, podemos, pero na versión clásica é necesaria a confirmación de todos os nodos, porque é así como podemos garantir a total coherencia dos datos no clúster, o que é unha vantaxe indubidable deste tipo de replicación.

Replicación asíncrona (asíncrona).

Imos modificar o algoritmo anterior. Enviaremos datos ás réplicas "nalgún momento máis tarde" e "nalgún momento máis tarde" os cambios aplicaranse ás réplicas:

  1. Rexistro dunha transacción no rexistro da base de datos.
  2. Usando unha transacción nun motor de base de datos.
  3. Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.
  4. Envío de datos a réplicas e aplicación de cambios a elas.

Este enfoque leva a que o clúster funcione rapidamente, porque non mantemos ao cliente esperando a que os datos cheguen ás réplicas e mesmo se comprometan.

Pero a condición de verter datos nas réplicas "nalgún momento máis tarde" pode levar á perda dunha transacción e á perda dunha transacción confirmada polo usuario, porque se os datos non tiveran tempo para ser replicados, unha confirmación ao cliente. sobre o éxito da operación foi enviada, eo nodo ao que chegaron os cambios estrelou HDD, perdemos a transacción, o que pode levar a consecuencias moi desagradables.

Replicación semisincronizada

Finalmente chegamos á replicación semisíncrona. Este tipo de replicación non é moi coñecido nin moi común, pero é de considerable interese porque pode combinar as vantaxes da replicación síncrona e asincrónica.

Tentemos combinar os 2 enfoques anteriores. Non manteremos o cliente por moito tempo, pero esixiremos que se repliquen os datos:

  1. Rexistro dunha transacción no rexistro da base de datos.
  2. Usando unha transacción nun motor de base de datos.
  3. Envío de datos a réplicas.
  4. Recibir a confirmación da réplica de que se recibiron os cambios (aplicaranse "nalgún momento máis tarde").
  5. Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.

Teña en conta que con este algoritmo, a perda de transaccións ocorre só se o nodo que recibe os cambios e o nodo réplica fallan. A probabilidade de tal fallo considérase baixa e estes riscos son aceptados.

Pero con este enfoque hai un posible risco de lecturas fantasma. Imaxinemos o seguinte escenario: no paso 4, non recibimos a confirmación de ningunha réplica. Debemos revertir esta transacción e non devolver unha confirmación ao cliente. Dado que os datos se aplicaron no paso 2, hai un intervalo de tempo entre o final do paso 2 e a recuperación da transacción, durante o cal as transaccións paralelas poden ver cambios que non deberían estar na base de datos.

Replicación semisincronizada sen perder

Se pensas un pouco, podes simplemente inverter os pasos do algoritmo e solucionar o problema das lecturas fantasmas neste escenario:

  1. Rexistro dunha transacción no rexistro da base de datos.
  2. Envío de datos de réplica.
  3. Recibir a confirmación da réplica de que se recibiron os cambios (aplicaranse "nalgún momento máis tarde").
  4. Usando unha transacción nun motor de base de datos.
  5. Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.

Agora cometemos cambios só se foron replicados.

Saída

Como sempre, non hai solucións ideais; hai un conxunto de solucións, cada unha delas ten as súas propias vantaxes e inconvenientes e é adecuada para resolver diferentes clases de problemas. Isto é absolutamente certo para escoller un mecanismo para sincronizar datos nunha base de datos replicada. O conxunto de vantaxes que posúe a replicación semisíncrona é o suficientemente sólido e interesante como para que poida considerarse digno de atención, a pesar da súa baixa prevalencia.

Iso é todo. Vémonos en curso!

Fonte: www.habr.com

Engadir un comentario