Introdução ao controle de simultaneidade de transações de banco de dados distribuído Yunxi

1. Visão geral dos princípios de controle de simultaneidade de transações

1.1 Por que controlar a concorrência
O banco de dados é um recurso compartilhado e geralmente há muitas transações sendo executadas ao mesmo tempo. Quando várias transações acessam o banco de dados simultaneamente, os mesmos dados são lidos ou modificados ao mesmo tempo. Se a operação concorrente não for controlada, dados incorretos podem ser acessados ​​e armazenados e a consistência do banco de dados pode ser destruída. Assim, o sistema de gerenciamento de banco de dados deve fornecer mecanismo de controle de simultaneidade.

A operação de escrita W(A) da transação à esquerda T2 na figura abaixo em t6 sobrescreve a operação de escrita da transação T1 no tempo t5, fazendo com que a atualização da transação T1 seja perdida; a transação à direita T2 na figura abaixo lê a operação de gravação foi revertida pela transação T1. Esses dados não são válidos e são chamados de leitura suja. Além disso, devido à execução concorrente de transações, também ocorrerão problemas como leitura não repetível, leitura fantasma e ordem parcial de leitura e escrita, os quais não serão apresentados aqui.

Figura 1 Esquerda é perda de atualização, direita é leitura suja

Para melhorar a utilização de recursos e a eficiência de execução de transações, e reduzir o tempo de resposta, o banco de dados permite a execução simultânea de transações. No entanto, quando várias transações operam no mesmo objeto ao mesmo tempo, deve haver conflitos. O estado intermediário de uma transação pode ser exposto a outras transações, fazendo com que algumas transações gravem valores errados no banco de dados de acordo com o estado intermediário de outras transações. É necessário fornecer um mecanismo para garantir que a execução da transação não seja afetada por transações concorrentes, para que os usuários sintam que apenas as transações iniciadas por eles mesmos estão sendo executadas no momento, o que é isolamento. Como o isolamento tem altos requisitos na ordem de execução das transações, muitos bancos de dados oferecem opções diferentes e os usuários podem sacrificar parte do isolamento para melhorar o desempenho do sistema. Essas diferentes opções são níveis de isolamento de transação. Os níveis de isolamento das transações são geralmente divididos em quatro, de baixo a alto: leitura não confirmada, leitura confirmada, leitura repetível e serializada. O objetivo final é realizar operações logicamente seriais em transações executadas simultaneamente em uma ordem razoável, de modo a evitar destruir a consistência do banco de dados executando em séries temporais.

Figura 2 Sequência de execução serial de operações simultâneas

1.2 Métodos
comuns de controle de simultaneidade Os métodos comuns de controle de simultaneidade incluem bloqueios, carimbos de data/hora, verificações de validade, instantâneos e mecanismos de várias versões.Aqui apresentamos vários controles de simultaneidade relacionados ao banco de dados Yunxi.

1.2.1 Bloqueio

Para maximizar a capacidade simultânea de transações de banco de dados, os bloqueios no banco de dados são projetados em dois modos, bloqueios compartilhados e bloqueios mutex. Quando uma transação adquire um bloqueio compartilhado, ela só pode realizar operações de leitura, então o bloqueio compartilhado também é chamado de bloqueio de leitura; e quando uma transação adquire um bloqueio mutex para uma linha de dados, ela pode ler e gravar a linha de dados, portanto, os bloqueios de exclusão mútuos também são chamados de bloqueios de gravação. Se a transação atual não tiver como adquirir o bloqueio correspondente à linha de dados, ela ficará em estado de espera, até que outras transações liberem o bloqueio correspondente aos dados atuais, o bloqueio poderá ser obtido e a operação correspondente poderá ser executada .

Figura 3 Compatibilidade de bloqueios de exclusão mútua e bloqueios compartilhados

O Two-Phase Locking Protocol (2PL) é um protocolo que garante a serialização das transações e divide a aquisição e liberação de bloqueios de uma transação em duas fases distintas: Crescer e Encolher. Durante a fase de crescimento, uma transação pode adquirir bloqueios, mas não pode liberar bloqueios; enquanto na fase de redução, as transações podem apenas liberar bloqueios e não podem adquirir novos bloqueios.

Deadlocks são frequentemente encontrados em programação multithread.Uma vez que vários threads estão envolvidos na competição por recursos, é necessário considerar se os threads ou transações atuais causarão deadlocks.Se o grafo de espera direcionado gerar um loop pode determinar se não é. Ocorre um impasse. Como recuperar de um deadlock é realmente muito simples.A solução mais comum é selecionar uma transação em todo o anel para reverter para quebrar o ciclo em todo o gráfico de espera.


Figura 4 Geração de impasse

1.2.2 Carimbo de data e hora

Atribua carimbos de data/hora a cada transação e use-os para determinar a ordem na qual as transações são executadas. Quando o carimbo de data/hora da transação 1 for menor que o da transação 2, o sistema de banco de dados deve garantir que a transação 1 execute o controle de simultaneidade baseado em T/O antes da transação 2. Nenhum bloqueio é necessário para leitura e gravação e cada linha de registros é marcada com a última transação que modificou e lê-lo. Quando o timestamp da transação é menor do que o timestamp registrado (os dados "futuros" não podem ser lidos), ele precisa ser executado novamente após o aborto. Assumindo que o registro X está marcado com dois timestamps para leitura e escrita: WTS(X) e RTS(X), o timestamp da transação é TTS, e a visibilidade é julgada da seguinte forma:

Ler:
TTS < WTS(X): O objeto não é visível para a transação, aborta a transação e recomeça com um novo timestamp.
TTS > WTS(X): O objeto está visível para a transação, atualize RTS(X) = max(TTS,RTS(X)). Para satisfazer leituras repetíveis, a transação replica o valor de X.

Escrever:
TTS < WTS(X) || TTS < RTS(X): abortar a transação, recomeçar.
TTS > WTS(X) && TTS > RTS(X): Atualizações da transação X, WTS(X) = TTS.

Seus defeitos incluem: transações longas são fáceis de morrer de fome, porque o timestamp de transações longas é pequeno e há uma alta probabilidade de que os dados atualizados sejam lidos após um período de execução, resultando em aborto; operações de leitura também gerarão gravações (escreva RT).

1.2.3 Controle de simultaneidade de várias versões

O banco de dados mantém várias versões físicas de um registro. Quando a transação é gravada, uma nova versão dos dados gravados é criada e a solicitação de leitura obtém a versão mais recente dos dados que já existem naquele momento de acordo com as informações do instantâneo no início da transação/instrução. Os benefícios mais imediatos que ele traz são: gravações não bloqueiam leituras, leituras não bloqueiam gravações e solicitações de leitura nunca falharão devido a conflitos (como T/O de versão única) ou espera (como 2PL de versão única). Para solicitações de banco de dados, as solicitações de leitura tendem a superar as solicitações de gravação. Quase todos os bancos de dados convencionais adotaram essa tecnologia de otimização.

Figura 5 Operações de leitura e gravação simultâneas de várias versões

 

2. Mecanismo de controle de simultaneidade do banco de
dados Yunxi O banco de dados Yunxi adota o modelo de controle de simultaneidade do Percolator, os valores no banco de dados Yunxi não são gravados diretamente na camada de armazenamento; em vez disso, tudo é escrito em um estado temporário, chamado "Write Intent", e adiciona um valor adicional que identifica o registro de transação ao qual o valor pertence. Sempre que uma operação encontra um Write Intent, ela procura o estado do registro da transação para saber como ele deve lidar com o valor Write Intent.

2.1 Registro de Transação
Para rastrear o status de execução da transação, gravamos o valor de um registro de transação no armazenamento KV e as intenções de gravação da transação apontam para esse registro, o que permite que todas as transações verifiquem as intenções de gravação que encontram. Isso é importante para suporte de simultaneidade em um ambiente distribuído. Um registro de transação expressa o estado de uma das seguintes transações:

  1. PENDENTE: O estado inicial de todos os valores, indicando que a transação Write Intent ainda está em andamento.
  2. COMMITTED: Após a conclusão da transação, este status indica que o valor pode ser lido.
  3. STAGING: Usado para habilitar o recurso de confirmação paralela. Dependendo do estado da intenção de gravação referenciada por este registro, a transação pode ou não ser confirmada.
  4. ABORTED: Se a transação falhar ou for abortada pelo cliente, ela entrará neste estado.
  5. O registro não existe: se uma transação encontrar uma intenção de gravação para a qual não existe nenhum registro de transação, ela usará o carimbo de data/hora da intenção de gravação para determinar como proceder. Uma transação de intenção de gravação é considerada uma transação se seu carimbo de data/hora estiver dentro do limite de atividade da transação PENDING, caso contrário, é considerada uma transação ABORTED.

2.2 Write Intent
São valores essencialmente de controle de simultaneidade multi-versão (também conhecido como MVCC, explicado com mais profundidade na camada de armazenamento) com um valor agregado que identifica o registro da transação ao qual o valor pertence. Pense neles como uma combinação de bloqueios replicados e valores temporários replicados.

Sempre que uma operação encontra um Write Intent (em vez de um valor MVCC), ela pesquisa o estado do registro da transação para ver como ele deve lidar com o valor Write Intent. Se o registro da transação for perdido, a ação verifica o carimbo de data/hora das intenções de gravação e avalia se ele expirou.

Sempre que uma operação encontra um Write Intent para a chave, ela tenta "resolvê-lo", e o resultado depende do registro de transação do Write Intent:

  1. COMMITTED: Esta operação lê o Write Intent e o converte em um valor MVCC removendo o ponteiro do Write Intent para o registro da transação.
  2. ABORTED: A intenção de gravação é ignorada e removida.
  3. PENDENTE: Isso indica que há um conflito de transação e deve ser resolvido.
  4. STAGING: O coordenador da transação precisa verificar se a pulsação do registro da transação ainda está lá e, se existir, você precisa aguardar

2.3 Resolução de conflitos
2.3.1 Conflito de gravação

1. Se a transação tiver uma configuração de prioridade clara, a prioridade é comparada para determinar a operação push, e a transação com prioridade mais alta reverterá a transação com prioridade mais baixa.

2. Se não houver prioridade, a transação com um carimbo de data/hora grande entrará na fila da transação com um carimbo de data/hora pequeno e aguardará que o registro da transação seja confirmado ou abortado.

2.3.2 Conflitos de gravação e leitura
1. Se a transação tiver uma configuração de prioridade clara, a prioridade é comparada para determinar a operação de envio. A transação com alta prioridade enviará o carimbo de data e hora da transação com baixa prioridade para o carimbo de data e hora da transação com alta prioridade.

2. Se não houver prioridade, a transação com um carimbo de data/hora grande entrará na fila da transação com um carimbo de data/hora pequeno e aguardará que o registro da transação seja confirmado ou abortado.

2.3.3 Escrever depois de ler

Quando uma operação de leitura lê um valor, o carimbo de data/hora de leitura é armazenado em um cache de carimbo de data/hora, que mostra a marca d'água alta do valor lido. que a hora Carimbe o valor mais recente do cache, então ocorre uma leitura após a gravação. O carimbo de data/hora da transação de gravação será empurrado de volta, o que pode afetar a reinicialização da transação (leitura de atualização)

 

3. Yunxi Database Concurrency Controller
3.1 Por que você quer ser um controlador concorrente?

  1. Centraliza o tratamento de sincronização de solicitações e o tratamento de conflitos de transações em um só lugar, permitindo que os tópicos sejam registrados, compreendidos e testados individualmente.
  2. Simplifica o enfileiramento de transações, reduz a frequência com que as transações enviam RPCs e permite que os garçons continuem imediatamente após a resolução da intenção.
  3. Crie uma estrutura de bloqueio que possa fazer SELECT de nível kv para atualização e SELECT para funções de compartilhamento.
  4. Forneça garantias mais fortes em relação à justiça quando as transações entram em conflito para reduzir a latência de cauda em cenários de contenção

3.2 Estrutura básica do controlador simultâneo

Um gerenciador de simultaneidade é uma estrutura que ordena solicitações recebidas e fornece isolamento entre as transações que emitem essas solicitações para realizar operações conflitantes. Durante o processo de classificação, os conflitos são encontrados e quaisquer conflitos encontrados são resolvidos por uma combinação de enfileiramento passivo e push ativo. Uma vez que um pedido é solicitado, é livre para avaliar sem medo de entrar em conflito com outros pedidos. Esse isolamento é garantido durante a vida útil da solicitação, mas termina quando a solicitação é concluída.

Cada solicitação em uma transação deve ser isolada de outras solicitações, seja durante o tempo de vida da solicitação ou após a conclusão da solicitação (supondo que ela adquira o bloqueio), mas todas as solicitações devem estar dentro do tempo de vida da transação.

O núcleo é composto por duas partes: gerenciador de travas e tabela de travas.

  1. lm é classificar solicitações para garantir seu isolamento
  2. Ele fornece bloqueios e ordenação de solicitações.É uma estrutura de dados na memória em cada nó que contém o conjunto de transações em andamento que adquiriram bloqueios. O mecanismo de bloqueio é compatível com a intenção de gravação, portanto, quando a solicitação encontrar um bloqueio externo durante o processo de avaliação, essas informações serão importadas.

3.3 Processo de Controle do Controlador Simultâneo

  1. Obtenha o latch da solicitação SequenceReq para garantir que não haja conflito de req e verifique a tabela de bloqueio de memória. Se houver conflito, solte o latch e aguarde o bloqueio correspondente
  2. Após isso, a requisição será executada normalmente, e as informações de bloqueio da transação atual serão adicionadas à tabela de bloqueio após aplicar o apply.
  3. E depois que a solicitação for concluída, FinishReq libera o Latch para continuar outras solicitações
  4. Por fim, após a conclusão da intenção de resolução após a transação ser confirmada ou revertida, o bloqueio ocupado pela transação na tabela de bloqueio é liberado e outras solicitações que aguardam a transação são despertadas.

3.4 gerenciador de travas

O gerenciador de travas ordena as solicitações recebidas e fornece isolamento entre essas solicitações sob a supervisão do gerenciador simultâneo. Uma trava é como um mutex de duração de baixo nível

Modo de trabalhar:

       1. O pedido de gravação de um intervalo será serializado pelo LeaseHolder do intervalo e colocado em uma determinada ordem

       2. Para fortalecer essa serialização, a LeaseHolder usa a trava para fornecer acesso não competitivo a esses valores escritos

       3. Outras solicitações que entram no LeaseHolder solicitam o mesmo conjunto de chaves que estão travadas pela trava e devem obter a trava antes de continuar.

       4. As solicitações de leitura também podem gerar travas, e várias solicitações de leitura podem conter travas para a mesma chave ao mesmo tempo (compatível), mas as travas de leitura e as travas de gravação são incompatíveis.

Outra maneira de ver a trava é semelhante a um mutex, que é necessário apenas para a duração de uma única solicitação de baixo nível. Para coordenar solicitações de nível superior e de execução mais longa (ou seja, transações do lado do cliente), usamos um sistema de intenção de gravação persistente.

3.5 mesa de bloqueio

É uma estrutura de dados na memória em cada nó que contém o conjunto de transações em andamento que adquiriram bloqueios. Cada bloqueio tem uma fila associada a ele e as transações que aguardam a liberação do bloqueio são enfileiradas nele. Os itens no lockWaitQueue armazenados localmente serão propagados pelo RPC para o TxnWaitQueue existente, que é armazenado no nó líder do Raft Group onde o registro da transação está localizado.

Nem todos os bloqueios são armazenados diretamente sob o controle do gerente, portanto, nem todos os bloqueios são detectáveis ​​durante o processo de classificação. Especificamente, as intenções de gravação (copiadas, bloqueios exclusivos) são armazenadas em linha no espaço de chave MVCC, portanto, não são detectadas até que a avaliação seja solicitada. Para acomodar essa forma de armazenamento de bloqueios, o gerenciador integra informações sobre bloqueios externos na estrutura do gerenciador simultâneo.

O tempo de vida de um bloqueio é maior do que o tempo de vida do detentor do bloqueio (transação), e um bloqueio estende a duração do isolamento fornecido em uma chave específica para o tempo de vida da própria transação do detentor do bloqueio. Eles são (geralmente) liberados apenas quando a transação é confirmada ou abortada.

No entanto, nem todos os bloqueios são armazenados diretamente sob o controle do gerente, portanto, nem todos os bloqueios podem ser descobertos durante o processo de classificação. Especificamente, as intenções de gravação (copiadas, bloqueios exclusivos) são armazenadas em linha no MVCC, portanto, não são detectadas até que a avaliação seja solicitada. Atualmente, o gerenciador simultâneo opera em uma estrutura de tabela de bloqueio não replicada

3.6 TxnWaitQueue

O TxnWaitQueue mantém o controle de todas as transações encontradas que não podem enviar a transação de gravação e devem aguardar a conclusão da transação de bloqueio antes de continuar. É uma estrutura de dados que armazena IDs de transação de bloqueio

Importante: Essas atividades ocorrem em um único nó, que é o líder do grupo Raft para o intervalo que contém os registros de transações.

Assim que a transação for resolvida, um sinal é enviado para o TxnWaitQueue, que permite que todas as transações bloqueadas por essa transação comecem a ser executadas.

As transações bloqueadas verificam o status de suas próprias transações para garantir que ainda estejam ativas. Se a transação bloqueada for abortada, ela só precisa ser excluída.

Se houver um impasse entre as transações (ou seja, cada uma delas é bloqueada pelas intenções de gravação umas das outras), uma das transações é abortada aleatoriamente.

3.7 lock TableGarçom

lockTableWaiter é responsável por transações conflitantes que mantêm bloqueios na fila de espera de bloqueio, o que garante que as solicitações possam continuar no caso de uma viagem ou impasse do coordenador de negócios

Waiter implementa a lógica de pedir para aguardar a liberação de bloqueios conflitantes na tabela de bloqueios. Da mesma forma, implementa a lógica de aguardar solicitações conflitantes antes do chamador. A fila de espera de bloqueio faz parte do chamador.

Este estado de espera responde a um conjunto de transições de estado na tabela de bloqueio:

1. Bloqueios conflitantes são liberados

2. Os conflitos são atualizados para que não entrem em conflito

3. Solicitações conflitantes na fila de espera de bloqueio adquirem bloqueios

4. Solicitações conflitantes na fila de espera de bloqueio saem da fila de espera de bloqueio

Essas transições de estado de estado geralmente são reflexivas e os waiters podem aguardar a liberação dos bloqueios ou a saída de outros participantes.

LockManager suporta reagir a transições de estado de bloqueios conflitantes

A interface RequestSequencer suporta a reação a transições de estado de filas de espera de bloqueio conflitantes

No entanto, no caso de uma falha do coordenador de transação ou deadlock de transação, a transição de estado pode nunca acontecer sem a intervenção do garçom. Para garantir o progresso de encaminhamento, o garçom pode precisar empurrar ativamente o detentor de bloqueio conflitante ou o chefe da fila de espera de bloqueio conflitante. Esse push de comportamento requer um RPC para o locatário do registro de transação conflitante, o que geralmente faz com que o RPC seja enfileirado no txnWaitQueue do locatário. Como é caro fazer isso, o push não é executado imediatamente, ele só é executado após um atraso.

{{o.name}}
{{m.name}}

Acho que você gosta

Origin my.oschina.net/u/5148943/blog/5383766
Recomendado
Clasificación