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
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:
- Rexistro dunha transacción no rexistro da base de datos.
- Usando unha transacción nun motor de base de datos.
- 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:
- Rexistro dunha transacción no rexistro da base de datos.
- Usando unha transacción nun motor de base de datos.
- Envío de datos a todas as réplicas.
- Recibindo confirmación de todas as réplicas de que se realizou unha transacción con elas.
- 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:
- Rexistro dunha transacción no rexistro da base de datos.
- Usando unha transacción nun motor de base de datos.
- Devolvendo a confirmación ao cliente de que a transacción se aplicou correctamente.
- 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:
- Rexistro dunha transacción no rexistro da base de datos.
- Usando unha transacción nun motor de base de datos.
- Envío de datos a réplicas.
- Recibir a confirmación da réplica de que se recibiron os cambios (aplicaranse "nalgún momento máis tarde").
- 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:
- Rexistro dunha transacción no rexistro da base de datos.
- Envío de datos de réplica.
- Recibir a confirmación da réplica de que se recibiron os cambios (aplicaranse "nalgún momento máis tarde").
- Usando unha transacción nun motor de base de datos.
- 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
Fonte: www.habr.com