Capítulo 21 — Deadlock: Quando o Sistema Fica Esperando por Ele Mesmo
Uma falha que nos obrigou a parar tudo
Estávamos construindo o sistema.
Tudo parecia funcionar.
Até que, durante um teste de concorrência, colocamos cinco execuções fazendo a mesma operação praticamente ao mesmo tempo.
E então apareceu:
ER_LOCK_DEADLOCK
A princípio, parece apenas mais um erro técnico.
Mas a pergunta é muito mais interessante:
«O que significa, de verdade, um sistema entrar em deadlock?»
Foi assim que começou a nossa investigação.
🧑💻 Matondo Pedro
João, afinal, o que aconteceu aqui?
👨💻 João
Antes de falar de banco de dados, vamos esquecer programação por um momento.
Imagina duas pessoas organizando documentos.
👨 A está segurando um documento que B precisa.
👩 B está segurando outro documento que A precisa.
Então:
👨 A → espera B
👩 B → espera A
Quem continua?
🧑💻 Matondo Pedro
Ninguém.
A está esperando B.
B está esperando A.
Então fica tudo travado.
👨💻 João
Exatamente.
Agora temos uma descoberta.
Não é simplesmente esperar que causa o problema.
Se B estivesse esperando A, mas A pudesse terminar sozinho:
👩 B → espera 👨 A
👨 A → termina
↓
👩 B → continua
Tudo ficaria bem.
O problema aparece quando a espera volta para o início.
👨 A → espera 👩 B
↑ ↓
└───────┘
Temos um círculo.
🧑💻 Matondo Pedro
Então, se tivermos cinco pessoas, pode ficar ainda pior?
👨💻 João
Pode.
Imagina:
👨 A espera 👩 B
👩 B espera 👨 C
👨 C espera 👩 D
👩 D espera 👨 E
👨 E espera 👩 A
Agora ninguém consegue avançar.
E olha uma coisa interessante:
nenhuma pessoa necessariamente fez algo errado.
Cada uma simplesmente está esperando outra pessoa.
O problema só aparece quando olhamos para o conjunto inteiro.
Voltando para o nosso sistema
👨💻 João
Agora vamos voltar para o S04.
Tínhamos cinco execuções acontecendo simultaneamente:
Execução A ─┐
Execução B ─┤
Execução C ─┼──→ mesma interactionId
Execução D ─┤
Execução E ─┘
O cursor daquela interação ainda não existia.
Então todas chegaram praticamente à mesma conclusão:
«"Não existe cursor. Preciso criá-lo."»
E todas tentaram fazer isso.
Foi aí que apareceu o nosso:
ER_LOCK_DEADLOCK
🧑💻 Matondo Pedro
Ah! Então o problema que encontramos no nosso projeto é o mesmo padrão.
👨💻 João
Exatamente.
Mas com uma precisão importante:
não significa que o banco de dados inteiro parou.
Algumas operações ficaram envolvidas numa dependência circular.
O banco detectou a situação e escolheu uma ou mais transações como vítimas, desfazendo aquela operação para permitir que o sistema continuasse.
🧑💻 Matondo Pedro
Então o banco precisa "matar" alguns processos?
👨💻 João
De forma simplificada, podemos dizer isso.
Tecnicamente, ele pode abortar uma transação e fazer rollback.
E isso produz uma descoberta interessante:
«Às vezes, o erro é justamente o mecanismo que impede o sistema de ficar bloqueado para sempre.»
Mas isso só acontece em bancos de dados?
🧑💻 Matondo Pedro
Essa é uma coisa que fiquei curioso.
Deadlock só acontece em banco de dados?
👨💻 João
Não.
O banco é apenas um dos lugares onde esse problema aparece.
O padrão é muito mais amplo.
Pode acontecer quando:
- 👥 pessoas esperam umas pelas outras;
- 🏭 máquinas dependem umas das outras;
- 🚗 veículos ficam presos em uma passagem;
- 💻 programas aguardam recursos;
- 🗄️ transações aguardam recursos do banco.
A estrutura é sempre parecida:
A possui X
A precisa de Y
B possui Y
B precisa de X
E então:
A → espera B
↑ ↓
└───────┘
🧑💻 Matondo Pedro
Então, quando estamos projetando um sistema, precisamos levantar essas situações e tentar prever esses problemas?
👨💻 João
Sim.
Não conseguimos prever todos os problemas antes de construir um sistema.
Mas podemos investigar:
O que é compartilhado?
Quem pode utilizar?
Quem pode precisar esperar?
Enquanto espera, o que continua segurando?
Existe possibilidade de formar um ciclo?
Essa análise pode revelar riscos de concorrência antes que eles apareçam em produção.
Uma pequena experiência
👨💻 João
Agora olha para duas situações.
Primeira:
👨 A → X → Y
👩 B → Y → X
Existe possibilidade de formar um ciclo.
Agora mudamos a ordem:
👨 A → X → Y
👩 B → X → Y
O que acontece?
🧑💻 Matondo Pedro
Aí não temos círculo.
B pode esperar A.
Mas A não está esperando B.
Quando A terminar, B continua.
Então não temos deadlock.
👨💻 João
Exatamente.
Acabaste de descobrir uma das estratégias fundamentais para reduzir deadlocks:
«estabelecer uma ordem consistente para adquirir recursos.»
E se o banco não detectasse?
🧑💻 Matondo Pedro
Mas o que aconteceria se o banco nunca detectasse aquele deadlock?
👨💻 João
Imagina:
A ⏳
B ⏳
Se nenhuma pudesse sair da situação, poderiam ficar esperando indefinidamente.
E outras operações poderiam começar a esperar também:
A ⏳
B ⏳
C ⏳
D ⏳
E ⏳
...
Isso poderia consumir conexões e outros recursos, aumentar os tempos de resposta, provocar timeouts e degradar o sistema.
O sistema estaria gastando recursos sem produzir progresso útil.
🧑💻 Matondo Pedro
Agora lembrei de uma coisa!
Na 42 Luanda estudamos um problema chamado Dining Philosophers — O Jantar dos Filósofos.
👨💻 João
E agora a conexão fica muito interessante.
Nós não começamos pelos filósofos.
Encontramos o problema primeiro no nosso sistema.
Depois percebemos que existia um problema clássico que representa exatamente essa classe de situação.
🍝 Dining Philosophers Nosso sistema
🧑 Filósofo Execução
🍴 Garfo Recurso
⏳ Espera Espera
🔄 Ciclo Dependência circular
🔒 Bloqueio Deadlock
E essa é talvez a parte mais interessante da investigação.
Não estudamos deadlock porque alguém começou dizendo:
«"Deadlock é X."»
Nós começamos com:
«"Por que o nosso sistema travou?"»
Investigamos.
Fizemos perguntas.
Criamos hipóteses.
Simplificamos o problema.
Encontramos o padrão.
E só depois demos nome ao que havíamos descoberto:
«Deadlock.»
Esse é o espírito do Adaptive Inquiry: começar pelo problema real, investigar através de perguntas, descobrir o conceito e só então aprender o termo técnico.
A teoria veio depois da necessidade de entendê-la.
Top comments (0)