Lidiar con grandes transacciones siempre fue un problema en Galera Cluster. La forma en que funciona la certificación de conjunto de escritura de Galera causa problemas cuando las transacciones son largas o cuando una sola fila se modifica con frecuencia en varios nodos. Como resultado, las transacciones deben revertirse y volver a intentarse, lo que provoca caídas en el rendimiento. Afortunadamente, este problema se solucionó en Galera 4, una nueva versión de Galera de Codership. Esta biblioteca se usa en MariaDB 10.4, por lo que la instalación de MariaDB 10.4 es la forma más fácil de probar las funciones recién introducidas. En esta publicación de blog, veremos cómo se puede usar la replicación de transmisión para mitigar los problemas que solían ser un problema estándar en las versiones anteriores de Galera.
Usaremos tres nodos del clúster MariaDB Galera versión 10.4.6, que viene con la versión 26.4.2 de Galera.
MariaDB [(none)]> show global status like 'wsrep_provider%';
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| wsrep_provider_capabilities | :MULTI_MASTER:CERTIFICATION:PARALLEL_APPLYING:TRX_REPLAY:ISOLATION:PAUSE:CAUSAL_READS:INCREMENTAL_WRITESET:UNORDERED:PREORDERED:STREAMING:NBO: |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <[email protected]> |
| wsrep_provider_version | 26.4.2(r4498) |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.001 sec)
Hay tres puntos débiles principales que la replicación de transmisión pretende abordar:
- Transacciones largas
- Grandes transacciones
- Puntos calientes en las tablas
Considerémoslos uno por uno y veamos cómo la replicación de transmisión puede ayudarnos a lidiar con ellos, pero primero concentrémonos en la certificación del conjunto de escritura:la causa raíz de esos problemas que aparecen.
Certificación Writeset en Galera Cluster
El clúster de Galera consta de varios nodos grabables. Cada transacción ejecutada en el clúster de Galera forma un conjunto de escritura. Cada conjunto de escritura debe enviarse a todos los nodos del clúster para su certificación, un proceso que garantiza que todos los nodos puedan aplicar una determinada transacción. Los conjuntos de escritura deben ejecutarse en todos los nodos del clúster, por lo que si hay algún conflicto, la transacción no puede confirmarse. ¿Cuáles son las razones típicas por las que la transacción no se puede comprometer? Bueno, los tres puntos que enumeramos anteriormente:
- Transacciones largas:la transacción demora más, lo más probable es que, mientras tanto, otro nodo ejecute actualizaciones que eventualmente entrarán en conflicto con el conjunto de escritura y evitarán que pase la certificación
- Transacciones grandes:en primer lugar, las transacciones grandes también son más largas que las pequeñas, lo que desencadena el primer problema. El segundo problema, estrictamente relacionado con las grandes transacciones, es el volumen de los cambios. Se actualizarán más filas, lo más probable es que alguna escritura en otro nodo genere un conflicto y toda la transacción tenga que revertirse.
- Puntos calientes en las tablas:lo más probable es que se actualice una fila dada, lo más probable es que dicha actualización ocurra simultáneamente en varios nodos, lo que provocará que algunas de las transacciones se reviertan
El problema principal aquí es que Galera no introduce ningún bloqueo en los nodos que no sean el nodo inicial, en el que se abrió la transacción. El proceso de certificación se basa en la esperanza de que si un nodo puede ejecutar una transacción, otros también deberían poder hacerlo. Es cierto pero, como comentamos, hay casos extremos en los que la probabilidad de que esto suceda se reduce significativamente.
En Galera 4, con la replicación de transmisión, el comportamiento ha cambiado y todos los bloqueos se realizan en todos los nodos. Las transacciones se dividirán en partes y cada parte se certificará en todos los nodos. Después de una certificación exitosa, las filas se bloquearán en todos los nodos del clúster. Hay un par de variables que rigen cómo se hace esto exactamente:wsrep_trx_fragment_size y wsrep_trx_fragment_unit definen qué tan grande debe ser el fragmento y cómo debe definirse. Es un control muy detallado:puede definir la unidad de fragmento como bytes, declaraciones o filas, lo que hace posible ejecutar la certificación para cada fila modificada en la transacción. Echemos un vistazo a cómo puede beneficiarse de la replicación de transmisión en la vida real.
Trabajar con Streaming Replication
Consideremos el siguiente escenario. Tenemos que ejecutar una transacción que demora al menos 30 segundos:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
Luego, mientras se ejecuta, ejecutaremos SQL que toca filas similares. Esto se ejecutará en otro nodo:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
¿Cuál sería el resultado?
La primera transacción se revierte tan pronto como se ejecuta la segunda:
MariaDB [sbtest]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
Query OK, 0 rows affected (0.001 sec)
Query OK, 667 rows affected (0.020 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.010 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.009 sec)
Rows matched: 667 Changed: 667 Warnings: 0
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Query OK, 0 rows affected (0.001 sec)
La transacción en el segundo nodo tuvo éxito:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (0.002 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.004 sec)
Lo que podemos hacer para evitarlo es usar la replicación de transmisión para la primera transacción. Le pediremos a Galera que certifique cada cambio de fila:
MariaDB [sbtest]> BEGIN; SET SESSION wsrep_trx_fragment_size=1 ; SET SESSION wsrep_trx_fragment_unit='rows' ; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT; SET SESSION wsrep_trx_fragment_size=0;
Query OK, 0 rows affected (0.001 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 667 rows affected (1.757 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.708 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.685 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Como puede ver, esta vez funcionó bien. En el segundo nodo:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (33.942 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.026 sec)
Lo que es interesante, puede ver que la ACTUALIZACIÓN tardó casi 34 segundos en ejecutarse; esto se debió al hecho de que la transacción inicial, a través de la replicación de transmisión, bloqueó todas las filas modificadas en todos los nodos y nuestra segunda transacción tuvo que esperar. el primero en completarse aunque ambas transacciones se ejecutaron en nodos diferentes.
Esto es básicamente todo cuando se trata de la replicación de transmisión. Dependiendo de los requisitos y el tráfico, puede usarlo de una manera menos estricta:certificamos cada fila, pero puede cambiar eso a cada n-ésima fila o cada declaración. Incluso puede decidir el volumen de datos a certificar. Esto debería ser suficiente para cumplir con los requisitos de su entorno.
Hay un par de cosas más que nos gustaría que tenga en cuenta y recuerde. En primer lugar, la replicación de transmisión no es de ninguna manera una solución que deba usarse de forma predeterminada. Esta es la razón por la que, por defecto, está deshabilitado. El caso de uso recomendado es decidir manualmente las transacciones que se beneficiarían de la replicación de transmisión y habilitarla a nivel de sesión. Esta es la razón por la que nuestros ejemplos terminan con:
SET SESSION wsrep_trx_fragment_size=0;
Esta declaración (que establece wsrep_trx_fragment_size en 0) deshabilita la replicación de transmisión para la sesión actual.
Otra cosa que vale la pena recordar:si usa la replicación de transmisión, usará la tabla 'wsrep_streaming_log' en el esquema 'mysql' para almacenar de manera persistente los datos que se transmiten. Con esta tabla, puede hacerse una idea de los datos que se transfieren a través del clúster mediante la replicación de transmisión.
Finalmente, la actuación. Esta es también una de las razones por las que no desea utilizar la replicación de transmisión todo el tiempo. La razón principal de esto es el bloqueo:con la replicación de transmisión, debe adquirir bloqueos de fila en todos los nodos. Esto toma tiempo para obtener los bloqueos y, si tiene que revertir la transacción, también ejercerá presión sobre todos los nodos para realizar la reversión. Realizamos una prueba muy rápida del impacto en el rendimiento que tiene la replicación de transmisión. El entorno es estrictamente de prueba, así que no asuma que esos resultados son los mismos en el hardware de grado de producción, es más para que usted vea cuál podría ser el impacto.
Probamos cuatro escenarios:
- Línea base, establecer global wsrep_trx_fragment_size=0;
- establecer global wsrep_trx_fragment_unit='filas'; establecer global wsrep_trx_fragment_size=1;
- establecer global wsrep_trx_fragment_unit='declaraciones'; establecer global wsrep_trx_fragment_size=1;
- establecer global wsrep_trx_fragment_unit='declaraciones'; establecer global wsrep_trx_fragment_size=5;
Utilizamos la prueba r/w de sysbench:
sysbench /root/sysbench/src/lua/oltp_read_write.lua --threads=4 --events=0 --time=300 --mysql-host=10.0.0.141 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=3306 --tables=32 --report-interval=1 --skip-trx=off --table-size=100000 --db-ps-mode=disable run
Los resultados son:
- Transacciones:82,91 por segundo, consultas:1658,27 por segundo. (100%)
- Transacciones:54,72 por segundo, consultas:1094,43 por segundo. (66%)
- Transacciones:54,76 por segundo, consultas:1095,18 por segundo. (66%)
- Transacciones:70,93 por segundo, consultas:1418,55 por segundo. (86%)
Como puede ver, el impacto es significativo, el rendimiento cae incluso un 33%.
Esperamos que esta publicación de blog le haya resultado informativa y le haya brindado información sobre la replicación de transmisión que viene con Galera 4 y MariaDB 10.4. Intentamos cubrir los casos de uso y los posibles inconvenientes relacionados con esta nueva tecnología.