Como a Escalabilidade do MySQL Pode Ser Melhorada para o BenchmarkSQL TPC-C Testing?

Estado Atual do MySQL 5.7

O MySQL 5.7 não é ideal em termos de escalabilidade. A figura a seguir ilustra a relação entre o throughput TPC-C e a concorrência no MySQL 5.7.39 sob uma configuração específica. Isso inclui definir o nível de isolamento de transação para Lido Comitado e ajustar o parâmetro innodb_spin_wait_delay para mitigar a degradação do throughput.

Figura 1: Problemas de escalabilidade no MySQL 5.7.39 durante o teste BenchmarkSQL

A partir da figura, é evidente que os problemas de escalabilidade limitam significativamente aumento no throughput do MySQL. Por exemplo, após 100 concorrências, o throughput começa a decair.

Para addressar o mencionado problema de colapso de desempenho, o pool de threads da Percona foi empregado. A seguinte figura ilustra a relação entre o throughput TPC-C e a concorrência após a configuração do pool de threads Percona.

Figura 2: Pool de threads Percona mitiga problemas de escalabilidade no MySQL 5.7.39

Embora o pool de threads introduza algum sobrecarga e o pico de desempenho tenha diminuído, ele mitigou o problema de colapso de desempenho sob alta concorrência.

Estado Atual do MySQL 8.0

Vamos olhar para os esforços que o MySQL 8.0 fez em relação à escalabilidade.

Otimização do Log Redo

A primeira melhoria importante é a otimização do log redo [3].

C++

 

commit 6be2fa0bdbbadc52cc8478b52b69db02b0eaff40
Author: Paweł Olchawa <[email protected]>
Date:   Wed Feb 14 09:33:42 2018 +0100
    
    WL#10310 Redo log optimization: dedicated threads and concurrent log buffer.

    0. Log buffer became a ring buffer, data inside is no longer shifted.
    1. User threads are able to write concurrently to log buffer. 
    2. Relaxed order of dirty pages in flush lists - no need to synchronize
       the order in which dirty pages are added to flush lists.
    3. Concurrent MTR commits can interleave on different stages of commits.
    4. Introduced dedicated log threads which keep writing log buffer: 
        * log_writer: writes log buffer to system buffers,
        * log_flusher: flushes system buffers to disk.
       As soon as they finished writing (flushing) and there is new data to 
       write (flush), they start next write (flush).
    5. User threads no longer write / flush log buffer to disk, they only
       wait by spinning or on event for notification. They do not have to 
       compete for the responsibility of writing / flushing.
    6. Introduced a ring buffer of events (one per log-block) which are used
       by user threads to wait for written/flushed redo log to avoid:
        * contention on single event
        * false wake-ups of all waiting threads whenever some write/flush
          has finished (we can wake-up only those waiting in related blocks)
    7. Introduced dedicated notifier threads not to delay next writes/fsyncs:
        * log_write_notifier: notifies user threads about written redo,
        * log_flush_notifier: notifies user threads about flushed redo.
    8. Master thread no longer has to flush log buffer.
    ...
    30. Mysql test runner received a new feature (thanks to Marcin):
        --exec_in_background.
    Review: RB#15134
    Reviewers:
        - Marcin Babij <[email protected]>,
        - Debarun Banerjee <[email protected]>.
    Performance tests:
        - Dimitri Kravtchuk <[email protected]>,
        - Daniel Blanchard <[email protected]>,
        - Amrendra Kumar <[email protected]>.
    QA and MTR tests:
        - Vinay Fisrekar <[email protected]>.

Um teste que compara o throughput TPC-C com diferentes níveis de concorrência antes e depois da otimização foi realizado. Detalhes específicos são mostrados na seguinte figura:

Figura 3: Impacto da otimização do log de redo em diferentes níveis de concorrência

Os resultados na figura mostram uma melhoria significativa no throughput em níveis de concorrência baixos.

Otimizando Lock-Sys por meio de Sharding de Latch

A segunda melhoria importante é a otimização de Lock-Sys [5].

C++

 

commit 1d259b87a63defa814e19a7534380cb43ee23c48
Author: Jakub Łopuszański <[email protected]>
Date:   Wed Feb 5 14:12:22 2020 +0100
    
    WL#10314 - InnoDB: Lock-sys optimization: sharded lock_sys mutex

    The Lock-sys orchestrates access to tables and rows. Each table, and each row,
    can be thought of as a resource, and a transaction may request access right for
    a resource. As two transactions operating on a single resource can lead to
    problems if the two operations conflict with each other, Lock-sys remembers
    lists of already GRANTED lock requests and checks new requests for conflicts in
    which case they have to start WAITING for their turn.
    
    Lock-sys stores both GRANTED and WAITING lock requests in lists known as queues.
    To allow concurrent operations on these queues, we need a mechanism to latch
    these queues in safe and quick fashion.
    
    In the past a single latch protected access to all of these queues.
    This scaled poorly, and the managment of queues become a bottleneck.
    In this WL, we introduce a more granular approach to latching.
    
    Reviewed-by: Pawel Olchawa <[email protected]>
    Reviewed-by: Debarun Banerjee <[email protected]>
      RB:23836

Com base no programa antes e depois da otimização com Lock-Sys, usando BenchmarkSQL para comparar o throughput TPC-C com a concorrência, os resultados específicos são mostrados na figura abaixo:

Figura 4: Impacto da otimização de Lock-Sys em diferentes níveis de concorrência

Ao olhar para a figura, é possível ver que a otimização de Lock-Sys melhora significativamente o throughput em condições de alta concorrência, enquanto o efeito é menos pronunciado em níveis de baixa concorrência devido a menos conflitos.

Sharding de Latch para trx-sys

A terceira melhoria importante é o sharding de latch para trx-sys.

C++

 

commit bc95476c0156070fd5cedcfd354fa68ce3c95bdb
Author: Paweł Olchawa <[email protected]>
Date:   Tue May 25 18:12:20 2021 +0200
    
    BUG#32832196 SINGLE RW_TRX_SET LEADS TO CONTENTION ON TRX_SYS MUTEX
    
    1. Introduced shards, each with rw_trx_set and dedicated mutex.
    2. Extracted modifications to rw_trx_set outside its original critical sections
       (removal had to be extracted outside trx_erase_lists).
    3. Eliminated allocation on heap inside TrxUndoRsegs.
    4. [BUG-FIX] The trx->state and trx->start_time became converted to std::atomic<>
       fields to avoid risk of torn reads on egzotic platforms.
    5. Added assertions which ensure that thread operating on transaction has rights
       to do so (to show there is no possible race condition).
    
    RB: 26314
    Reviewed-by: Jakub Łopuszański [email protected]

Com base nestas melhorias antes e depois, usando BenchmarkSQL para comparar o throughput TPC-C com a concorrência, os resultados específicos são mostrados na figura abaixo:

Figura 5: Impacto do sharding de latch em trx-sys em diferentes níveis de concorrência

Ao olhar para a figura, é possível ver que esta melhoria aumenta significativamente o throughput TPC-C, alcançando seu pico em 200 concorrências. Note-se que o impacto diminui em 300 concorrências, principalmente devido a problemas de escalabilidade em subsistema trx-sys relacionados a MVCC ReadView.

Refinando o MySQL 8.0

As melhorias restantes são nossas melhorias independentes.

Melhorias na Estrutura de Leitura MVCC ReadView

A primeira melhoria importante é a melhoria na estrutura de dados de Leitura MVCC ReadView [1].

Foi realizada uma comparação de desempenho para avaliar a eficácia da otimização da MVCC ReadView. A figura abaixo mostra a comparação de throughput TPC-C com níveis de concorrência variantes, antes e depois da modificação da estrutura de dados MVCC ReadView.

Figura 6: Comparação de desempenho antes e depois da adoção de nova estrutura híbrida de dados em NUMA

A partir da figura, é evidente que essa transformação principalmente otimizou a escalabilidade e melhorou o pico de throughput do MySQL em ambientes NUMA.

Evitando problemas de duplo latente

A segunda melhoria importante que fizemos é a resolução do problema de duplo latente, onde “duplo latente” se refere à necessidade do latente global trx-sys por ambos o view_open e o view_close [1].

Usando a versão optimizada MVCC ReadView, compare o throughput TPC-C antes e depois das modificações. Detalhes são mostrados na figura abaixo:

Figura 7: Melhoria no desempenho após eliminado o bottleneck de duplo latente

A partir da figura, é evidente que as modificações melhoraram significativamente a escalabilidade sob condições de alta concorrência.

Mecanismo de Redução de Transações

A última melhoria é a implementação de um mecanismo de redução de transações para proteger contra a colapso de desempenho sob concorrência extrema [1] [2] [4].

O seguinte gráfico representa a avaliação de carga de escalabilidade TPC-C realizada após a implementação de mecanismos de throttling de transações. O teste foi executado em um cenário com o NUMA BIOS desativado, limitando a entrada de até 512 threads de usuário no sistema de transações.

Figura 8: Máxima throughput TPC-C em BenchmarkSQL com mecanismos de throttling de transações

A partir do gráfico, é óbvio que a implementação de mecanismos de throttling de transações melhora significativamente a escalabilidade do MySQL.

Resumo

Geralmente, é totalmente fechável que o MySQL mantenha desempenho sem colapso em dezenas de milhares de conexões concorrentes em cenários de baixo conflito na avaliação TPC-C do BenchmarkSQL.

Referências

  1. Bin Wang (2024). O Arte da Solução de Problemas na Engenharia de Software: Como tornar o MySQL melhor.
  2. O Novo Piscina de Threads do MySQL
  3. Paweł Olchawa. 2018. MySQL 8.0: Novo design de WAL escalável e sem bloqueio. Arquivo de Blog do MySQL.
  4. Xiangyao Yu. Uma avaliação de controle de concorrência com mil núcleos. Tese de Doutorado, Instituto de Tecnologia de Massachusetts, 2015.
  5. Manual de Referência do MySQL 8.0

Source:
https://dzone.com/articles/mysql-scalability-improvement-for-benchmarksql