Transações e modos de bloqueio nas coleções confiáveis do Azure Service Fabric
Transação
Uma transação é uma sequência de operações realizadas como uma única unidade lógica de trabalho. Ele exibe as propriedades ACID comuns (atomicidade, consistência, isolamento, durabilidade) das transações de banco de dados:
- Atomicidade: Uma transação deve ser uma unidade atômica de trabalho. Em outras palavras, ou todas as suas modificações de dados são realizadas, ou nenhuma delas é realizada.
- Consistência: Quando concluída, uma transação deve deixar todos os dados em um estado consistente. Todas as estruturas de dados internas devem estar corretas no final da transação.
- Isolamento: As modificações feitas por transações simultâneas devem ser isoladas das modificações feitas por quaisquer outras transações simultâneas. O nível de isolamento usado para uma operação dentro de um ITransaction é determinado pelo IReliableState que executa a operação.
- Durabilidade: Após a conclusão de uma transação, os seus efeitos são permanentemente instalados no sistema. As modificações persistem mesmo em caso de falha do sistema.
Níveis de isolamento
O nível de isolamento define o grau em que a transação deve ser isolada das modificações feitas por outras transações. Há dois níveis de isolamento que são suportados em Coleções confiáveis:
- Leitura repetível: especifica que as instruções não podem ler dados que foram modificados, mas ainda não confirmados por outras transações, e que nenhuma outra transação pode modificar dados que foram lidos pela transação atual até que a transação atual seja concluída.
- Instantâneo: especifica que os dados lidos por qualquer instrução em uma transação são a versão transacionalmente consistente dos dados que existiam no início da transação. A transação pode reconhecer apenas modificações de dados que foram confirmadas antes do início da transação. As modificações de dados feitas por outras transações após o início da transação atual não são visíveis para as instruções executadas na transação atual. O efeito é como se as instruções em uma transação obtivessem um instantâneo dos dados confirmados como existiam no início da transação. Os instantâneos são consistentes em todas as coleções confiáveis.
As Coleções Confiáveis escolhem automaticamente o nível de isolamento a ser usado para uma determinada operação de leitura, dependendo da operação e da função da réplica no momento da criação da transação. A seguir está a tabela que mostra os padrões de nível de isolamento para operações de Dicionário Confiável e Fila.
Operação \ Função | Primário | Secundária |
---|---|---|
Leitura de entidade única | Leitura repetível | Instantâneo |
Enumeração, Contagem | Instantâneo | Instantâneo |
Nota
Exemplos comuns de operações de entidade única são IReliableDictionary.TryGetValueAsync
, IReliableQueue.TryPeekAsync
.
Tanto o Dicionário Confiável quanto o Suporte para Fila Confiável Read Your Writes. Em outras palavras, qualquer gravação dentro de uma transação será visível para uma leitura a seguir que pertence à mesma transação.
Bloqueios
Em Coleções Confiáveis, todas as transações implementam um bloqueio rigoroso em duas fases: uma transação não libera os bloqueios adquiridos até que a transação termine com um abortamento ou uma confirmação.
O Dicionário Confiável usa o bloqueio em nível de linha para todas as operações de entidade única.
A fila confiável troca a simultaneidade por uma propriedade FIFO transacional estrita.
A fila confiável usa bloqueios no nível de operação, permitindo uma transação com TryPeekAsync
e/ou TryDequeueAsync
e uma transação com EnqueueAsync
de cada vez.
Observe que, para preservar o FIFO, se um TryPeekAsync
ou TryDequeueAsync
mais observar que a fila confiável está vazia, eles também bloquearão EnqueueAsync
.
As operações de escrita utilizam sempre fechaduras exclusivas. Para operações de leitura, o bloqueio depende de alguns fatores:
- Qualquer operação de leitura feita usando o isolamento de instantâneo é livre de bloqueio.
- Qualquer operação de Leitura Repetível por padrão usa bloqueios compartilhados.
- No entanto, para qualquer operação de leitura que suporte Leitura Repetível, o usuário pode solicitar um bloqueio de Atualização em vez do bloqueio Compartilhado. Um bloqueio de atualização é um bloqueio assimétrico usado para evitar uma forma comum de bloqueio que ocorre quando várias transações bloqueiam recursos para possíveis atualizações em um momento posterior.
A matriz de compatibilidade de bloqueio pode ser encontrada na tabela a seguir:
Pedido \ Concedido | Nenhuma | Partilhado | Atualizar | Exclusivo |
---|---|---|---|---|
Partilhado | Sem conflito | Sem conflito | Conflito | Conflito |
Atualizar | Sem conflito | Sem conflito | Conflito | Conflito |
Exclusivo | Sem conflito | Conflito | Conflito | Conflito |
O argumento timeout em APIs de coleções confiáveis é usado para deteção de deadlock. Por exemplo, duas transações (T1 e T2) estão tentando ler e atualizar K1. É possível que eles bloqueiem, porque ambos acabam tendo o bloqueio compartilhado. Neste caso, uma ou ambas as operações expirarão. Nesse cenário, um bloqueio de atualização poderia evitar esse impasse.