MariaDB
 sql >> Base de Dados >  >> RDS >> MariaDB

Manipulando grandes transações com replicação de streaming e MariaDB 10.4


Lidar com grandes transações sempre foi um ponto problemático no Galera Cluster. A forma como a certificação do conjunto de escrita Galera funciona causa problemas quando as transações são longas ou quando uma única linha está sendo modificada com frequência em vários nós. Como resultado, as transações precisam ser revertidas e repetidas, causando quedas de desempenho. Felizmente, esse problema foi resolvido no Galera 4, uma nova versão do Galera da Codership. Essa biblioteca é usada no MariaDB 10.4, portanto, instalar o MariaDB 10.4 é a maneira mais fácil de testar os recursos recém-introduzidos. Nesta postagem do blog, veremos como a replicação de streaming pode ser usada para mitigar problemas que costumavam ser um problema padrão nas versões anteriores do Galera.

Usaremos três nós do cluster MariaDB Galera versão 10.4.6, que vem com a versão 26.4.2 do 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)

Existem três principais pontos problemáticos com os quais a replicação de streaming deve lidar:
  • Transações longas
  • Grandes transações
  • Pontos de acesso nas tabelas

Vamos considerá-los um por um e ver como a replicação de streaming pode nos ajudar a lidar com eles, mas primeiro vamos nos concentrar na certificação do conjunto de escrita - a causa raiz desses problemas aparecerem.

Certificação de Writeset no Galera Cluster


O cluster Galera consiste em vários nós graváveis. Cada transação executada no cluster Galera forma um writeset. Cada conjunto de escrita deve ser enviado a todos os nós do cluster para certificação - um processo que garante que todos os nós possam aplicar determinada transação. Os conjuntos de gravação devem ser executados em todos os nós do cluster, portanto, se houver algum conflito, a transação não poderá ser confirmada. Quais são as razões típicas pelas quais a transação não pode ser confirmada? Bem, os três pontos que listamos anteriormente:
  • Transações longas - quanto mais a transação demorar, o mais provável é que, enquanto isso, outro nó execute atualizações que eventualmente entrarão em conflito com o conjunto de gravação e impedirão que ele passe na certificação
  • Transações grandes - em primeiro lugar, transações grandes também são mais longas que as pequenas, então isso desencadeia o primeiro problema. O segundo problema, estritamente relacionado às grandes transações, é o volume das mudanças. Mais linhas serão atualizadas, o mais provável é que alguma gravação em outro nó resulte em conflito e toda a transação precise ser revertida.
  • Pontos de acesso nas tabelas - é mais provável que uma determinada linha seja atualizada, mais provavelmente essa atualização ocorrerá simultaneamente em vários nós, resultando em algumas das transações a serem revertidas

O principal problema aqui é que o Galera não introduz nenhum bloqueio em nós além do nó inicial, no qual a transação foi aberta. O processo de certificação é baseado na esperança de que, se um nó puder executar uma transação, outros também possam fazê-lo. É verdade, mas, como discutimos, há casos de canto em que a probabilidade de isso acontecer é significativamente reduzida.

No Galera 4, com replicação de streaming, o comportamento mudou e todos os bloqueios estão sendo realizados em todos os nós. As transações serão divididas em partes e cada parte será certificada em todos os nós. Após a certificação bem-sucedida, as linhas serão bloqueadas em todos os nós do cluster. Existem algumas variáveis ​​que controlam exatamente como isso é feito - wsrep_trx_fragment_size e wsrep_trx_fragment_unit definem o tamanho do fragmento e como ele deve ser definido. É um controle muito refinado:você pode definir a unidade de fragmento como bytes, instruções ou linhas, o que possibilita executar a certificação para cada linha modificada na transação. Vamos dar uma olhada em como você pode se beneficiar da replicação de streaming na vida real.

Trabalhando com a replicação de streaming


Vamos considerar o seguinte cenário. Temos uma transação para executar que leva pelo 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;

Então, enquanto estiver em execução, executaremos o SQL que toca em linhas semelhantes. Isso será executado em outro nó:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;

qual seria o resultado?

A primeira transação é revertida assim que a segunda é executada:
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)

A transação no segundo nó foi bem-sucedida:
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)

O que podemos fazer para evitar isso é usar a replicação de streaming para a primeira transação. Pediremos à Galera para certificar cada mudança de linha:
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 você pode ver, desta vez funcionou muito bem. No segundo nó:
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)

O que é interessante, você pode ver que o UPDATE levou quase 34 segundos para ser executado - isso foi causado pelo fato de que a transação inicial, através da replicação de streaming, bloqueou todas as linhas modificadas em todos os nós e nossa segunda transação teve que esperar o primeiro a ser concluído, embora ambas as transações tenham sido executadas em nós diferentes.

É basicamente isso quando se trata da replicação de streaming. Dependendo dos requisitos e do tráfego, você pode usá-lo de maneira menos rigorosa - certificamos todas as linhas, mas você pode alterar isso para todas as n-ésimas linhas ou todas as declarações. Você pode até decidir sobre o volume de dados a certificar. Isso deve ser suficiente para atender aos requisitos do seu ambiente.

Há mais algumas coisas que gostaríamos que você tivesse em mente e se lembrasse. Em primeiro lugar, a replicação de streaming não é de forma alguma uma solução que deve ser usada por padrão. Esta é a razão pela qual ele está, por padrão, desabilitado. O caso de uso recomendado é decidir manualmente as transações que se beneficiariam da replicação de streaming e habilitá-la no nível da sessão. Esta é a razão pela qual nossos exemplos terminam com:
SET SESSION wsrep_trx_fragment_size=0;

Essa instrução (configurando wsrep_trx_fragment_size como 0) desativa a replicação de streaming para a sessão atual.

Outra coisa que vale a pena lembrar - se você usar a replicação de streaming, ela usará a tabela 'wsrep_streaming_log' no esquema 'mysql' para armazenar persistentemente os dados que estão sendo transmitidos. Usando esta tabela, você pode ter uma ideia sobre os dados que estão sendo transferidos no cluster usando a replicação de streaming.

Por fim, o desempenho. Esse também é um dos motivos pelos quais você não deseja usar a replicação de streaming o tempo todo. A principal razão para isso é o bloqueio - com a replicação de streaming, você precisa adquirir bloqueios de linha em todos os nós. Isso leva tempo para obter os bloqueios e, caso você precise reverter a transação, também pressionará todos os nós para realizar a reversão. Executamos um teste muito rápido do impacto no desempenho que a replicação de streaming tem. O ambiente é estritamente de teste, portanto, não assuma que esses resultados sejam os mesmos no hardware de nível de produção, é mais para você ver qual poderia ser o impacto.

Testamos quatro cenários:
  1. Linha de base, definir global wsrep_trx_fragment_size=0;
  2. definir global wsrep_trx_fragment_unit='rows'; definir global wsrep_trx_fragment_size=1;
  3. definir global wsrep_trx_fragment_unit='statements'; definir global wsrep_trx_fragment_size=1;
  4. definir global wsrep_trx_fragment_unit='statements'; definir global wsrep_trx_fragment_size=5;

Usamos o teste sysbench r/w:
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

Os resultados são:
  1. Transações:82,91 por segundo, consultas:1.658,27 por segundo. (100%)
  2. Transações:54,72 por segundo, consultas:1.094,43 por segundo. (66%)
  3. Transações:54,76 por segundo, consultas:1.095,18 por segundo. (66%)
  4. Transações:70,93 por segundo, consultas:1.418,55 por segundo. (86%)

Como você pode ver, o impacto é significativo, o desempenho cai até 33%.

Esperamos que você tenha achado esta postagem de blog informativa e que tenha lhe dado alguns insights sobre a replicação de streaming que vem com Galera 4 e MariaDB 10.4. Tentamos cobrir casos de uso e possíveis desvantagens relacionadas a essa nova tecnologia.