Tema: distributed-systems
-
Tracing distribuído em resumo: spans, IDs de pai e W3C Trace Context
Um trace é uma árvore de spans, cada um com ID do trace, ID próprio, ID do span pai, timestamps, atributos e status; o cabeçalho W3C traceparent leva o ID do trace, o ID do pai e um flag sampled entre processos, e um serviço que apenas repassa os dois cabeçalhos já mantém os traces unidos.
-
O que um cluster Raft garante: maiorias, um único líder e leituras linearizáveis
Sistemas de consenso como o etcd (Raft) permitem que uma maioria de servidores concorde sobre um log ordenado; permanecem corretos diante de qualquer número de falhas, mas só avançam enquanto uma maioria estiver acessível. Leituras linearizáveis passam pelo consenso e custam latência; leituras serializáveis são atendidas localmente e podem estar desatualizadas.
-
Projetar operações idempotentes e repetições seguras
Uma operação é idempotente quando executá-la várias vezes tem o mesmo efeito que executá-la uma só vez; a RFC 9110 define isso para os métodos HTTP, e o cabeçalho Idempotency-Key estende a propriedade ao POST. Guarde a chave com impressão digital e resultado, sinalize conflitos com 409 e 422 e apague as chaves após um prazo documentado.
-
Sagas: fluxos de trabalho em várias etapas entre serviços, com compensação em vez de rollback
Uma saga é uma sequência de transações locais em serviços diferentes, em que cada uma dispara a seguinte; se uma etapa falha, as anteriores são desfeitas por transações compensatórias escritas pelo desenvolvedor. As sagas restauram a consistência sem transações distribuídas, mas abrem mão do isolamento: os estados intermediários ficam visíveis e as compensações precisam ser projetadas, não presumidas.
-
Amplificação da latência de cauda: quando uma requisição espera pela mais lenta de cem
Uma requisição que se distribui por N backends é tão lenta quanto a resposta mais lenta; assim, uma resposta lenta em 1 de cada 100 por backend torna lentas cerca de 63% das requisições com cem destinos. O p99 da folha vira a mediana da raiz; as soluções são menos folhas, requisições hedged ou tied após um atraso baseado em percentil, deadlines com resultados parciais e a eliminação das causas das caudas nas folhas.
-
Publicação confiável de eventos com transactional outbox
O evento é gravado em uma tabela de outbox na mesma transação de banco de dados que a mudança de estado, e um relay separado o publica no broker. Isso elimina a janela em que o estado é salvo mas o evento se perde (ou o contrário), ao custo de entrega at-least-once e de um relay a mais para operar.
-
Bulkheads por dependência mantêm endpoints não relacionados disponíveis quando uma dependência fica lenta
Hipótese: quando um serviço chama várias dependências a partir de um único pool compartilhado de threads ou slots de concorrência, uma dependência que fica lenta (e não fora do ar) arrasta consigo endpoints não relacionados assim que o pool se esgota; dar a cada dependência seu próprio pool limitado mantém os demais endpoints próximos da latência e da taxa de erro de referência durante a mesma lentidão.
-
Réplicas de leitura e atraso de replicação: como se manifestam as leituras desatualizadas e como limitá-las
Uma réplica em streaming aplica o log do primário com algum atraso, e por isso uma leitura logo após uma escrita pode não enxergar essa escrita. Direcione as leituras conforme a defasagem que cada chamador tolera, use modos de replicação síncrona apenas onde a latência for aceitável e lembre que a reaplicação do log pode cancelar consultas longas na réplica.
-
Fundamentos do gRPC: contratos protobuf, streaming e onde ele se encaixa
O gRPC chama métodos definidos em um arquivo .proto, usando Protocol Buffers como linguagem de definição de interface e formato de transmissão; oferece chamadas unárias e de streaming, deadlines, metadados e um conjunto fixo de códigos de status sobre HTTP/2. É adequado para comunicação entre serviços e backends móveis; navegadores exigem gRPC-Web e integradores públicos costumam esperar JSON sobre HTTP.
-
Hashing consistente: posicionamento estável de chaves quando nós entram e saem
Aplicar o hash de uma chave módulo o número de nós remapeia a maioria das chaves sempre que um nó é adicionado ou removido. O hashing consistente coloca nós e chaves em um anel, de modo que só se movem as chaves vizinhas ao nó alterado; nós virtuais equilibram a carga, e variantes baseadas em tabela, como o Maglev, trocam parte da estabilidade de posicionamento por consultas mais rápidas.
-
Rastreamento distribuído em resumo: spans, IDs de pai e propagação do W3C Trace Context
Um trace é uma árvore de spans, cada um com trace ID, span ID próprio, ID do span pai, timestamps, atributos e status; o cabeçalho W3C traceparent transporta o trace ID, o ID do pai e o flag sampled entre processos, e um serviço que apenas repasse os dois cabeçalhos já mantém os traces íntegros.
-
CAP e PACELC como apoio à decisão, não como slogans
O CAP proíbe apenas um canto do espaço de projeto: disponibilidade perfeita e consistência linearizável enquanto dura uma partição de rede. O PACELC acrescenta o compromisso cotidiano entre latência e consistência quando não há partição. Usados como perguntas e não como rótulos, ambos ajudam a decidir, operação a operação, onde um sistema pode devolver dados desatualizados e onde precisa coordenar.
-
Backpressure e filas limitadas: deixar o estágio mais lento ditar o ritmo
Uma fila sem limite transforma sobrecarga em esgotamento de memória e latência ilimitada. Backpressure significa que o consumidor informa ao produtor quanto consegue receber, da demanda do Reactive Streams ao write() do Node.js que retorna false; uma fila limitada com um comportamento definido para quando está cheia é o mínimo que todo estágio de um serviço precisa ter.
-
Em que sinal de sobrecarga um serviço pequeno deve basear o descarte de carga: tempo de espera na fila, requisições em andamento ou CPU?
Pergunta em aberto: as referências citam CPU, latência, tamanho da fila e número de threads como possíveis gatilhos para descartar carga, e deixam a escolha a cargo de cada serviço. Para um serviço com poucas instâncias e sem sistema global de cotas, que sinal, limite e regra de prioridade as equipes de fato mantiveram em produção, e como os ajustaram?
-
Locks distribuídos e leases de líder: expiração, fencing tokens e o que um lock não consegue garantir
Um lock distribuído é um lease que expira: um processo pausado por garbage collection, disputa de CPU ou atraso de rede pode continuar agindo depois que o lease já passou para outro cliente. Só um fencing token monotonicamente crescente, verificado pelo recurso protegido, torna esse lock seguro para fins de correção; um lock usado apenas para evitar trabalho duplicado exige menos.
-
Relógios lógicos: timestamps de Lamport, vector clocks e relógios híbridos
Os relógios de parede de máquinas diferentes divergem, por isso ordenar eventos por timestamp faz perder atualizações. Os timestamps de Lamport dão uma ordem consistente com a causalidade, os vector clocks detectam também atualizações concorrentes, e os relógios lógicos híbridos mantêm um valor próximo da hora real sem perder a ordem causal.
-
Circuit breakers: falhar rápido quando uma dependência está fora do ar ou lenta
Um circuit breaker conta as falhas e as chamadas lentas a uma dependência; ao ultrapassar um limite, abre e rejeita as chamadas imediatamente, depois deixa passar algumas chamadas de teste (half-open) antes de fechar de novo. Protege as threads de quem chama e dá à dependência espaço para se recuperar, mas só com janelas bem escolhidas, um fallback e um timeout por baixo.
-
Entrega at-most-once, at-least-once e exactly-once
Sistemas de mensageria entregam uma mensagem no máximo uma vez (pode haver perda), pelo menos uma vez (pode haver duplicação) ou, na prática, exatamente uma vez (com deduplicação pelo consumidor); at-least-once com consumidores idempotentes é o padrão prático, e "exactly once" é uma propriedade do pipeline inteiro, não do broker.
-
Pipelines de exclusão entre serviços, armazenamentos derivados e backups
Modele a exclusão dos dados de uma pessoa como um job com um estado por armazenamento do mapa de dados: dispare um evento, exija que cada serviço responsável informe a conclusão com contagens, trate explicitamente o armazenamento de objetos versionado e os armazenamentos derivados, limite por quanto tempo os backups retêm os dados ou destrua chaves por titular, e mantenha uma lista de supressão para repetir a exclusão após restaurações.
Legível por máquina: JSON