Conteúdo original em https://twitter.com/zanfranceschi/status/1742406772139430162
Ei dev,
Esses dias postei provocações sobre lock otimista x pessimista. Alguns disseram que até certo nível de concorrência/conflito uma opção vale mais a pena que outra.
Vamos pensar nisso juntos? Não vou dar uma resposta – quero apenas aprofundar nosso senso analítico.
↓
https://twitter.com/zanfranceschi/status/1738927304372371552
DISCLAIMER: Essa thread vale mais a pena se você souber pelo menos por cima o que é um lock otimista e um lock pessimista de banco de dados. Se não souber e mesmo assim quiser continuar lendo, tem todo meu apoio. rsrs
Mas sério, dá uma pesquisada – não são conceitos difíceis.
→ O primeiro passo é termos números concretos. Bora pensar um pouco sobre a probabilidade de conflitos. Pra isso, vamos imaginar o seguinte cenário: requisições simultâneas para comprar algum produto – para simplicidade, vamos imaginar que todos os produtos vendem a mesma coisa.
Vamos então supor que temos 10 requisições simultâneas para 8 produtos diferentes. Queremos calcular a probabilidade de p.ex. 2 dessas requisições concorrerem para afetar o estoque do mesmo produto. Lembre-se, é um cenário síncrono e simplista!
Para chegar nisso, precisamos achar o número de combinações de conflitos (R ÷ C × P × P ^ (R - C)) e dividí-lo pelo número total de combinações (P ^ R), onde R = número de requisições simultâneas, P = produtos disponíveis, C = número de conflitos.
R ÷ C × P × P ^ (R - C) / P ^ R
Meio mala essa fórmula, eu sei. O resultado dela é 0,625 – ou seja, ~62% de chance de conflito/concorrência com os parâmetros mencionados. Se quiséssemos a probabilidade com, p.ex., 3 conflitos, essa porcentagem cairia para ~5%; com 4, iria para ~0,4%. Com 5, 4,8828125E-4. 🥲
Agora a gente precisa entender quanto tempo >MAIS OU MENOS< cada abordagem – pessimista e otimista – leva pra processar cada requisição.
Vamos começar pela abordagem pessimista chutando um valor para o processamento da requisição: ~10ms. Como existe a concorrência de 2 requisições, a gente teria por cima um tempo de processamento de ~20ms para as 10 requisições simultâneas.
Se fossem 3 conflitos, ~30ms; 4, ~40ms para 10 requisições; e assim por diante. Por favor, note que essa é uma estimativa simplificada.
Nesse cenário pessimista, a gente geralmente precisa de menos mecanismos para tratar problemas de inconsistência nos dados.
Lembre-se, estamos fazendo mais locks para termos mais consistência de dados ao preço de uma possível maior contenção – menos paralelismo.
Bora pro otimismo – aqui a porca torce o rabo. No cenário Poliana, a gente geralmente introduz mais mecanismos para compensar os conflitos/não possibilidade de realização dos comandos no banco. Isso pode se traduzir em retentativas, rollbacks, mensagens de erro, etc, e etc.
Pra nossa comparação fazer sentido, deveríamos incluir o tempo de processamento desses possíveis mecanismos de compensação. Por exemplo, 1 retentativa automática pode levar o dobro do tempo; 2 retentativas o triplo; devolver uma mensagem de erro pode ser muito rápido, etc.
Se devolver uma mensagem de erro, talvez não haja acréscimo de tempo como há para uma compensação automática, mas talvez o usuário final o irá fazer manualmente gerando mais requisições subsequentes. Isso tudo precisa ser considerado. 🤔
A maior diferença entre os dois cenários é que o pessimista é (mais ou menos) mais serial durante os conflitos (porque há o lock de mais registros) e o cenário pessimista é menos serial porque um processo interfere menos em outros (não há lock por toda a transação).
Uma estimativa super simplificada do cenário otimista, onde apenas uma mensagem de erro é devolvida, se tivéssemos 2, 3 ou N conflitos simultâneos e cada processamento levasse ~10ms, nós ainda teríamos os mesmos ~10ms para as 10 requisições simultâneas – com ou sem conflitos.
Vou deixar pra você fazer um exercício sobre como calcular o cenário otimista duma maneira melhor, pois estou com 2% de life estatística. 🙂
Espero que agora você tenha pelo menos uma intuição sobre alguns cálculos para obter números relevantes.
Obviamente, num cenário real muitas outras dimensões seriam consideradas. P.ex.: produtos que vendem mais (ponderação), picos de acesso, promoções, publicidade, etc. Em outros domínios, outras dimensões devem ser consideradas.
O resumo é o seguinte:
- Tente se basear em números;
- Entenda as dimensões específicas do seu problema/domínio;
- Faça experimentos! A prática muitas vezes nos dá insights muito mais tangíveis do que algumas teorias, ainda mais quando não temos experiência.
Talvez eu tenha sido filosófico/genérico demais nessa thread porque na verdade muita coisa nela serve pra outras coisas não relacionadas a simplesmente escolher entre usar uma abordagem de lock pessimista x otimista de banco de dados (inclusive, existem abordagens híbridas!).
Mas olha só: muito obrigado se você chegou até aqui – mesmo!
Um abraço pra quem é de abraço e um beijo pra quem é de beijo. ♥️
Top comments (0)