Caso de deadlock 7

Fonte: conta pública yangyidba

I. Introdução

Deadlock é, na verdade, um problema técnico muito interessante e desafiador. Provavelmente, todo DBA e alguns alunos de desenvolvimento o encontrarão no decorrer do trabalho. Com relação ao impasse, continuarei a escrever uma série de estudos de caso, na esperança de ajudar amigos que desejam entender o impasse.

2. Análise de caso

2.1 Cenário de negócios

Os alunos de desenvolvimento de negócios desejam sincronizar os dados. Sua lógica é atualizar por meio da operação de atualização. Se o afeta_rows retornado pelo registro atualizado for 0, a instrução insert é chamada para inicializar a inserção . Se a inserção falhar, a operação de atualização é executada novamente e um deadlock ocorre no caso de operações simultâneas de várias sessões.

2.2 Descrição ambiental

O nível de isolamento de transação do MySQL 5.6.24 é RR

create table ty (
  id int not null primary key auto_increment ,
  c1 int not null default 0,
  c2 int not null default 0,
  c3 int not null default 0,
  unique key uc1(c1),
  unique key uc2(c2)
) engine=innodb ;
insert into ty(c1,c2,c3)
values(1,3,4),(6,6,10),(9,9,14);

2.3 Caso de teste

2.4 Registro de deadlock

2018-03-27 17:59:23 0x7f75bf39d700
*** (1) TRANSACTION:
TRANSACTION 1863, ACTIVE 76 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 382150, OS thread handle 56640, query id 28 localhost root update
insert into ty (c1,c2,c3) values(3,4,2)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 5 n bits 72 index uc2 of table `test`.`ty` trx id 1863 lock_mode X locks gap before rec insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 1864, ACTIVE 65 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 382125, OS thread handle 40032, query id 62 localhost root update
insert into ty (c1,c2,c3) values(3,4,2)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 28 page no 5 n bits 72 index uc2 of table `test`.`ty` trx id 1864 lock_mode X locks gap before rec
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 4 n bits 72 index uc1 of table `test`.`ty` trx id 1864 lock mode S waiting
*** WE ROLL BACK TRANSACTION (2)

2.5 Analise o log de deadlock

Em primeiro lugar, precisamos enfatizar novamente a lógica de bloqueio da operação de inserção.

O primeiro estágio: verificação de restrição de exclusividade, primeiro aplique para  LOCK_S + LOCK_ORDINARY

A segunda etapa: Após adquirir o bloqueio do estágio 1 e inserir com sucesso, há um bloqueio GAP na posição inserida: LOCK_INSERT_INTENTION, a fim de evitar outros conflitos de chave única de inserção.

Após os novos dados serem inseridos: LOCK_X + LOCK_REC_NOT_GAP

Para a operação de inserção, se ocorrer um conflito de restrição exclusivo, você precisa adicionar o bloqueio de próxima tecla S ao índice exclusivo conflitante. A partir daqui, você descobrirá que, mesmo no nível de isolamento da transação RC, também haverá um bloqueio de próxima chave, bloqueando assim a simultaneidade. No entanto, o que o documento não diz é que para o índice exclusivo onde o conflito é detectado, o thread de espera precisa bloquear o próximo registro após obter o Bloqueio S. O código-fonte é usado para determinar a função row_ins_scan_sec_index_for_duplicate.

Em segundo lugar, precisamos da matriz de compatibilidade desbloqueada.

A partir da matriz de compatibilidade, podemos tirar as seguintes conclusões:

Não haverá conflitos entre as operações INSERT.

GAP, Next-Key bloqueará o Insert.

GAP e Record, Next-Key não entrarão em conflito.

Gravar e gravar, conflito de próxima chave entre si.

O bloqueio de inserção existente não impede que nenhum bloqueio seja adicionado.

Os bloqueios de GAP já mantidos bloquearão o bloqueio de intenção de inserção INSERT_INTENTION.

Além disso , bloqueios GAP serão aplicados para atualizar ou excluir registros inexistentes por meio de um índice exclusivo.

análise

Compreendendo o conhecimento básico acima, começamos a analisar o log de deadlock:

T1: sess1 atualiza os dados através da chave única.Como c2 = 4 não existe, a linha afetada é retornada como 0, e o MySQL será aplicado para o bloqueio GAP entre (3,6).

T2: A situação da sessão2 é semelhante à da sessão1, e o bloqueio GAP entre (3,6) também será aplicado.A partir da matriz de compatibilidade acima, os dois bloqueios GAP não entrarão em conflito.

T3: sess1 retorna a linha afetada como 0 de acordo com a instrução de atualização e executa a operação de inserção. Neste momento, é necessário aplicar um bloqueio de intenção de inserção. O bloqueio de GAP mantido pela sessão sess2 entra em conflito com o bloqueio de intenção de inserção aplicado por sess1, e há uma espera.

índice uc2 da tabela test.ty trx id 1863 lock_mode X bloqueia a lacuna antes de rec inserir intenção esperando

T4: sess2 é semelhante a sess 1. De acordo com a instrução de atualização, a linha afetada é retornada como 0 e a operação de inserção é executada. O bloqueio de intenção de inserção aplicado entra em conflito com o bloqueio GAP mantido pela instrução de atualização de sess1. sess1 (segurando o bloqueio GAP), sess2 (segurando o bloqueio GAP), sess1 (bloqueio de intenção de inserção aguardando a liberação do bloqueio GAP de sess2) sess2 (bloqueio de intenção de inserção aguardando a liberação do bloqueio GAP de sess1)  constituem uma espera circular, que leva ao deadlock.

2.6 Solução

Do ponto de vista da lógica de processamento do cenário de negócios, o negócio precisa enviar duas solicitações, uma atualização e uma inserção para completar a lógica de negócios, que não é amigável e otimizada.

Na verdade, podemos nos comunicar bem com os colegas de desenvolvimento, confirmar a idempotência do negócio, usar o método inserir na chave duplicada, inserir se não houver, atualizar se houver, uma chamada pode completar a função das 2 operações anteriores e melhorar o desempenho.

Três, resumo

Por fim, quero falar sobre a ideia de resolver o problema do impasse:

1. Ter um conhecimento básico sólido de fechaduras.

2. É difícil julgar a situação específica de execução de SQL com base apenas no log de deadlock.É necessário se comunicar com os colegas de desenvolvimento para esclarecer a lógica SQL de execução de negócios e, em seguida, simular o teste.

Leitura estendida

O texto completo acabou.

Aproveite o MySQL :)

A aula "MySQL Core Optimization" do professor Ye foi atualizada para o MySQL 8.0, leia o código para iniciar a jornada de prática do MySQL 8.0

Acho que você gosta

Origin blog.csdn.net/n88Lpo/article/details/108924174
Recomendado
Clasificación