Contenção de lock em hot row Hot row lock contention
ID da causa db-hot-row · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de banco de dados (Equipe de infraestrutura)
Quando todos tentam alterar a mesma linha (baú da guilda, item popular na casa de leilões, contador global do servidor), só um de cada vez consegue o lock.
Por quê Eventos e itens populares concentram as alterações na mesma linha → Efeito As requisições esperam até conseguir o lock → Na tela Trocas falham, “tente novamente mais tarde”, timeouts
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de banco de dados (Equipe de infraestrutura)
O que fazer (Equipe de desenvolvimento)
Dividir a linha (contadores com sharding), manter as transações curtas, acumular em memória e gravar de uma vez.
O que fazer (Equipe de infraestrutura)
Monitorar o tempo e o número de esperas por lock de linha, encontrar as linhas onde a contenção se concentra e compartilhar.
Números de referência
Se cada requisição segura o lock por 10 ms, aquela linha só pode ser alterada no máximo 100 vezes por segundo. Se a transação incluir uma ida e volta a outro servidor, esse número cai ainda mais.
No gráfico
Sobe com a carga · Número e tempo de esperas por lock de linha
Onde olhar
No MySQL, ver o aumento de Innodb_row_lock_waits e Innodb_row_lock_time e o Innodb_row_lock_current_waits, e descobrir quem espera por quem com sys.innodb_lock_waits. No PostgreSQL, ver as sessões com wait_event_type igual a Lock no pg_stat_activity e as requisições com granted em false no pg_locks; com log_lock_waits ativado (desligado por padrão), as esperas longas por lock ficam no log
Confirma se
As esperas por lock crescem rápido acompanhando o evento e o número de jogadores, e a maioria das requisições em espera aponta para a mesma linha (mesma chave) da mesma tabela
Descarta se
Esperas espalhadas de forma uniforme por várias tabelas e linhas: mais provável, saturação de disco ou CPU. Uma sessão segura o lock por muito tempo e não solta: transação aberta por muito tempo (db-long-tx)
Como verificar
Ferramentas de infra (sem precisar do código do jogo)
Fontes
InnoDB LockingMySQL Quando uma transação põe lock em uma linha (registro do índice), as outras transações não conseguem alterar essa linha e esperam
How to Minimize and Handle DeadlocksMySQL Recomendação de manter as transações pequenas e curtas e fazer commit logo após as alterações relacionadas, para reduzir conflitos
Server Status VariablesMySQL Innodb_row_lock_waits e Innodb_row_lock_time mostram o número e o tempo de esperas por lock de linha; Innodb_row_lock_current_waits, quantas estão esperando agora