As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Níveis de isolamento de transação no Neptune
O Amazon Neptune implementa diferentes níveis de isolamento de transação para consultas somente leitura e de mutação. As consultas SPARQL e Gremlin são classificadas como somente leitura ou de mutação com base nos seguintes critérios:
-
No SPARQL, há uma distinção clara entre consultas de leitura (
SELECT
,ASK
,CONSTRUCT
eDESCRIBE
conforme definido na especificação SPARQL 1.1 Query Language) e consultas de mutação ( INSERT
eDELETE
conforme definido na especificação SPARQL 1.1 Update). Observe que o Neptune trata várias consultas de mutação enviadas juntas (por exemplo, em uma mensagem
POST
, separada por ponto e vírgula) como uma única transação. Elas são garantidas para obter sucesso ou falhar como uma unidade atômica e, no caso de falha, alterações parciais serão revertidas. No entanto, no Gremlin, o Neptune classifica uma consulta como uma somente leitura ou de mutação dependendo de ela conter ou não etapas de caminho de consulta, como
addE()
,addV()
,property()
oudrop()
que manipula dados. Se a consulta contiver uma etapa de caminho desse tipo, ela será classificada e executada como uma consulta de mutação.
Também é possível usar sessões permanentes no Gremlin. Para obter mais informações, consulte Sessões baseadas em script do Gremlin. Nessas sessões, todas as consultas, incluindo consultas somente leitura, são executadas sob o mesmo isolamento das consultas de mutação no endpoint de gravador.
Usando sessões somente leitura Bolt no openCypher, todas as consultas, incluindo consultas somente leitura, são executadas sob o mesmo isolamento das consultas de mutação no endpoint de gravador.
Tópicos
Isolamento de consulta somente leitura no Neptune
O Neptune avalia consultas somente leitura em semântica de isolamento de snapshot. Isso significa que uma consulta somente leitura opera logicamente em um snapshot consistente do banco de dados obtido quando a avaliação da consulta começa. O Neptune pode então garantir que nenhum dos seguintes fenômenos aconteça:
Dirty reads
: consultas somente leitura no Neptune nunca verão dados não confirmados de uma transação simultânea.Non-repeatable reads
: uma transação somente leitura que lê os mesmos dados mais de uma vez sempre obterá os mesmos valores.Phantom reads
: uma transação somente leitura nunca lerá os dados que foram adicionados após o início da transação.
Como o isolamento de snapshots é obtido usando o controle de simultaneidade multiversão (MVCC — multiversion concurrency control), as consultas somente leitura não precisam bloquear dados e, portanto, não bloqueiam consultas de mutação.
As réplicas de leitura só aceitam consultas somente leitura, portanto, todas as consultas em réplicas de leitura são executadas sob semântica de isolamento de SNAPSHOT
.
A única consideração adicional ao consultar uma réplica de leitura é que pode haver um pequeno atraso de replicação entre o gravador e as réplicas de leitura. Isso significa que uma atualização feita no gravador pode demorar um pouco para ser propagada para a réplica de leitura na qual você está lendo. O tempo real de replicação depende da carga de gravação na instância primária. A arquitetura Neptune oferece suporte à replicação de baixa latência e o atraso de replicação é instrumentado em uma métrica da Amazon. CloudWatch
Ainda assim, devido ao nível de isolamento de SNAPSHOT
, as consultas de leitura sempre veem um estado consistente do banco de dados, mesmo que não seja o mais recente.
Nos casos em que você precise de uma forte garantia de que uma consulta observa o resultado de uma atualização anterior, envie a consulta para o próprio endpoint gravador em vez de para uma réplica de leitura.
Isolamento de consulta de mutação no Neptune
As leituras feitas como parte de consultas de mutação são executadas sob o isolamento de transação READ COMMITTED
, o que exclui a possibilidade de leituras contaminadas. Indo além das garantias normais fornecidas para o isolamento da transação READ COMMITTED
, o Neptune fornece a forte garantia de que nem leituras NON-REPEATABLE
nem PHANTOM
possam acontecer.
Essas fortes garantias são obtidas bloqueando registros e intervalos de registros ao ler dados. Isso evita que transações simultâneas façam inserções ou exclusões em intervalos de índice após serem lidas, o que garante as leituras repetíveis.
nota
No entanto, uma transação de mutação simultânea Tx2
pode começar após o início da transação de mutação de Tx1
e pode confirmar uma alteração antes que o Tx1
bloqueie os dados para lê-los. Nesse caso, o Tx1
verá a alteração do Tx2
como se o Tx2
tivesse concluído antes do Tx1
começar. Como isso se aplica apenas a alterações confirmadas, uma dirty
read
nunca poderá ocorrer.
Para entender o mecanismo de bloqueio que o Neptune usa para consultas de mutação, é útil primeiro entender os detalhes do Neptune Modelo de dados de grafo e Estratégia de indexação. O Neptune gerencia dados usando três índices, a saber, SPOG
, POGS
e GPSO
.
Para obter leituras repetidas para o nível de transação READ COMMITTED
, o Neptune usa bloqueios de intervalos no índice que está sendo usado. Por exemplo, se uma consulta de mutação ler todas as propriedades e bordas de saída de um vértice chamado person1
, o nó bloqueará todo o intervalo definido pelo prefixo S=person1
no índice SPOG
antes de ler os dados.
O mesmo mecanismo se aplica ao usar outros índices. Por exemplo, quando uma transação de mutação pesquisa todos os pares de vértices de origem-destino de um determinado rótulo de borda usando o índice POGS
, o intervalo do rótulo de borda na posição P
será bloqueado. Qualquer transação simultânea, independentemente de ser uma consulta somente leitura ou de mutação, ainda poderá executar leituras dentro do intervalo bloqueado. No entanto, qualquer mutação que envolva a inserção ou a exclusão de novos registros no intervalo de prefixos bloqueados exigirá um bloqueio exclusivo e será impedida.
Em outras palavras, quando um intervalo do índice tiver sido lido por uma transação de mutação, há uma forte garantia de que esse intervalo não será modificado por nenhuma transação simultânea até o final da transação de leitura. Isso garante que nenhuma non-repeatable
reads
ocorrerá.
Resolução de conflitos usando tempos limite de espera de bloqueio
Se uma segunda transação tentar modificar um registro em um intervalo que uma primeira transação bloqueou, o Neptune detectará o conflito imediatamente e bloqueará a segunda transação.
Se nenhum deadlock de dependência for detectado, o Neptune aplicará automaticamente um mecanismo de tempo limite de espera de bloqueio, no qual a transação bloqueada aguardará até sessenta segundos para que a transação que mantém o bloqueio seja concluída e libera o bloqueio.
Se o tempo limite de espera de bloqueio expirar antes que o bloqueio seja liberado, a transação bloqueada será revertida.
Se o bloqueio for liberado dentro do tempo limite de espera de bloqueio, a segunda transação será desbloqueada e poderá ser concluída com êxito sem a necessidade de repetição.
No entanto, se o Neptune detectar um deadlock de dependência entre as duas transações, a reconciliação automática do conflito não será possível. Nesse caso, o Neptune cancela e reverte imediatamente uma das duas transações sem iniciar um tempo limite de espera de bloqueio. O Neptune se esforça ao máximo para reverter a transação que tem o menor número de registros inseridos ou excluídos.
Bloqueios de intervalo e falsos conflitos
O Neptune obtém bloqueios de intervalo usando bloqueios de lacuna. Bloqueio de lacuna é um bloqueio em uma lacuna entre os registros do índice ou um bloqueio na lacuna antes do primeiro ou depois do último registro do índice.
O Neptune usa a chamada tabela de dicionário para associar valores de ID numéricos a literais de string específicos. Veja um exemplo de estado dessa tabela de dicionário do Netuno:
String | ID |
---|---|
type |
1 |
default_graph |
2 |
person_3 |
3 |
person_1 |
5 |
knows |
6 |
person_2 |
7 |
idade |
8 |
edge_1 |
9 |
lives_in |
10 |
Nova York |
11 |
Pessoa |
12 |
Local |
13 |
edge_2 |
14 |
As strings acima pertencem a um modelo de grafo de propriedades, mas os conceitos também se aplicam igualmente a todos os modelos de grafo de RDF.
O estado correspondente do índice SPOG (Subject-Predicate-Object_Graph) é mostrado abaixo, à esquerda. À direita, as strings correspondentes são mostradas para ajudar a entender o que significam os dados do índice.
S (ID) | P (ID) | O (ID) | G (ID) | S (string) | P (string) | O (string) | G (string) | |
---|---|---|---|---|---|---|---|---|
3 |
1 |
12 |
2 |
person_3 |
type |
Pessoa |
default_graph |
|
5 |
1 |
12 |
2 |
person_1 |
type |
Pessoa |
default_graph |
|
5 |
6 |
3 |
9 |
person_1 |
knows |
person_3 |
edge_1 |
|
5 |
8 |
40 |
2 |
person_1 |
idade |
40 |
default_graph |
|
5 |
10 |
11 |
14 |
person_1 |
lives_in |
Nova York |
edge_2 |
|
7 |
1 |
12 |
2 |
person_2 |
type |
Pessoa |
default_graph |
|
11 |
1 |
13 |
2 |
Nova York |
type |
Local |
default_graph |
Agora, se uma consulta de mutação ler todas as propriedades e bordas de saída de um vértice chamado person_1
, o nó bloqueará todo o intervalo definido pelo prefixo S=person_1
no índice SPOG antes de ler os dados. O bloqueio de intervalo colocaria bloqueios de lacuna em todos os registros correspondentes e no primeiro registro que não correspondesse. Os registros correspondentes seriam bloqueados, mas não os não correspondentes. O Neptune colocaria os bloqueios de lacuna da seguinte forma:
5 1 12 2
(lacuna 1)5 6 3 9
(lacuna 2)5 8 40 2
(lacuna 3)5 10 11 14
(lacuna 4)7 1 12 2
(lacuna 5)
Isso bloqueia os seguintes registros:
5 1 12 2
5 6 3 9
5 8 40 2
5 10 11 14
Nesse estado, as seguintes operações estão legitimamente bloqueadas:
Inserção de uma nova propriedade ou borda para
S=person_1
. Uma nova propriedade diferente detype
ou uma nova borda precisaria entrar nas lacunas 2, 3, 4 ou 5, todas bloqueadas.Exclusão de qualquer um dos registros existentes.
Ao mesmo tempo, algumas operações simultâneas seriam bloqueadas falsamente (gerando falsos conflitos):
Todas as inserções de borda ou propriedade para
S=person_3
são bloqueadas porque precisariam entrar na lacuna 1.Todas as novas inserções de vértice às quais seja atribuído um ID entre 3 e 5 seriam bloqueadas porque teriam que entrar na lacuna 1.
Todas as novas inserções de vértice às quais seja atribuído um ID entre 5 e 7 seriam bloqueadas porque teriam que entrar na lacuna 5.
Os bloqueios de lacuna não são precisos o suficiente para bloquear a lacuna de um predicado específico (por exemplo, para bloquear a lacuna 5 para o predicado S=5
).
Os bloqueios de intervalo são colocados apenas no índice em que a leitura acontece. No caso acima, os registros são bloqueados somente no índice SPOG, não no POGS nem no GPSO. As leituras de uma consulta podem ser realizadas em todos os índices, dependendo dos padrões de acesso, que podem ser listados usando o explain
APIs (para Sparql e para Gremlin).
nota
Bloqueios de lacunas também podem ser usados para atualizações simultâneas seguras nos índices subjacentes, o que também pode gerar falsos conflitos. Esses bloqueios de lacuna são colocados independentemente do nível de isolamento ou das operações de leitura realizadas pela transação.
Falsos conflitos podem ocorrer não apenas quando transações simultâneas colidem devido a bloqueios de lacuna, mas também em alguns casos quando uma transação está sendo repetida após qualquer tipo de falha. Se a reversão acionada pela falha ainda estiver em andamento e os bloqueios anteriormente utilizados para a transação ainda não tiverem sido totalmente liberados, a nova tentativa encontrará um falso conflito e falhará.
Sob uma carga alta, você normalmente pode descobrir que de 3% a 4% das consultas de gravação falham em virtude de falsos conflitos. Para um cliente externo, esses conflitos falsos são difíceis de prever e devem ser tratados com novas tentativas.