Catálogo de Concorrência
Cenários Canônicos & Mitigações
Explore 10 cenários de falhas de concorrência baseados em pesquisas acadêmicas de isolamento e casos reais de sistemas financeiros e distribuídos.
Desvio de Escrita Hospitalar (Write Skew)
Dois médicos cancelam plantão simultaneamente sob Snapshot Isolation porque seus conjuntos de escrita não colidem.
Dois médicos cancelam plantão simultaneamente sob Snapshot Isolation porque seus conjuntos de escrita não colidem.
Schema e dados iniciais
-- Schema
CREATE TABLE doctors (
id INT PRIMARY KEY,
name TEXT NOT NULL,
on_duty BOOLEAN NOT NULL
);
-- Seed
INSERT INTO doctors VALUES (1, 'Dr. Alice', true), (2, 'Dr. Bob', true);Carga concorrente (chaos.yaml)
version: "1.0"
name: "hospital_write_skew"
operations:
- name: "sign_off_alice"
steps:
- "SELECT count(*) AS active FROM doctors WHERE on_duty = true -> act"
- "UPDATE doctors SET on_duty = false WHERE id = 1 AND {act >= 2}"
- name: "sign_off_bob"
steps:
- "SELECT count(*) AS active FROM doctors WHERE on_duty = true -> act"
- "UPDATE doctors SET on_duty = false WHERE id = 2 AND {act >= 2}"
invariants:
- name: "at_least_one_doctor_on_duty"
query: "SELECT count(*) AS active FROM doctors WHERE on_duty = true;"
assert: "active >= 1"Por que a invariante quebra
Sob Snapshot Isolation, T1 e T2 leem o mesmo snapshot (2 médicos ativos). T1 altera Alice, T2 altera Bob. Como seus conjuntos de escrita são disjuntos, o SI padrão permite ambos os commits, deixando o hospital sem médicos.
T1 ──(rw)──► T2 ──(rw)──► T1Delta debugging reduz 40 operações às 2 que causam a falha.
Correção em produção
Elevação para Serializable Snapshot Isolation (SSI) ou Bloqueio de Conflito
Write Skew (A5B) é o exemplo clássico de falha sob Snapshot Isolation (SI): como T1 altera a linha 1 e T2 altera a linha 2, os conjuntos de escrita não colidem (sem conflito ww), mas geram um ciclo de anti-dependência de leitura-escrita (rw). A solução canônica é configurar SERIALIZABLE (onde motores modernos com SSI rastreiam dependências rw e abortam transações concorrentes com serialization_failure) ou serializar os acessos através de um lock FOR UPDATE em uma linha mestre de escala.
PostgreSQL (SSI), CockroachDB, MySQL (SERIALIZABLE)
-- Solução A: Elevação do Nível de Isolamento para SERIALIZABLE (SSI)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT count(*) FROM doctors WHERE on_duty = true;
-- Se count >= 2:
UPDATE doctors SET on_duty = false WHERE id = 1;
COMMIT; -- O motor PostgreSQL detectará o ciclo rw e abortará T2 com código 40001!
-- Solução B: Bloqueio Pessimista Compartilhado em Linha Pai de Plantão
BEGIN;
SELECT shift_id FROM duty_shifts WHERE shift_id = 1 FOR UPDATE;
SELECT count(*) FROM doctors WHERE on_duty = true;
UPDATE doctors SET on_duty = false WHERE id = 1;
COMMIT;