Interessante | Como bancos de dados e caches garantem consistência?

Autor: Xiaolin Coding
Graphical Computer Basics Site: https://xiaolincoding.com/

Um dia, o chefe disse: "Recentemente, a empresa tem cada vez mais usuários, mas a velocidade de acesso do servidor está cada vez pior. Awang me ajudou a otimizá-lo, e fiz um bom trabalho desenhando um bolo para você! ".

foto

O programador Awang estava muito ansioso para ouvir o "bolo de pintura" da boca do chefe e aceitou a tarefa dada pelo chefe sem qualquer hesitação.

Awang fez login no servidor e, após alguma investigação, foi confirmado que o gargalo de desempenho do servidor estava no banco de dados .

Isso é fácil de fazer, adicione o Redis ao servidor e use-o como cache para o banco de dados.

Dessa forma, quando o cliente solicita dados, se os dados podem ser atingidos no cache, o cache pode ser consultado em vez de consultar o banco de dados, reduzindo assim a pressão no banco de dados e melhorando o desempenho do servidor.

Atualize primeiro o banco de dados ou o cache primeiro?

Depois que Awang teve essa ideia, ele estava pronto para começar a otimizar o servidor, mas havia um problema à sua frente.

foto

Devido à introdução do cache, quando os dados são atualizados, não apenas o banco de dados, mas também o cache devem ser atualizados. Existem problemas antes e depois dessas duas operações de atualização :

  • Atualize primeiro o banco de dados e, em seguida, atualize o cache;
  • Atualize primeiro o cache, depois atualize o banco de dados;

Awang não esperava muito. Ele sentiu que os dados mais recentes devem primeiro atualizar o banco de dados, para garantir que os dados no banco de dados estejam atualizados, então ele adotou o plano de " atualizar o banco de dados primeiro, e em seguida, atualize o cache".

Depois de várias noites jogando, Awang finalmente "otimizou o servidor", e então ficou online diretamente, e correu para se reportar ao chefe cheio de confiança.

O chefe não entende de tecnologia, então naturalmente ele não se preocupou muito, então ele pediu a Ngawang para observar a situação do servidor.

Awang observou por vários dias e descobriu que a pressão no banco de dados foi bastante reduzida e a velocidade de acesso também melhorou muito.

Os bons tempos não duraram muito. De repente, o chefe recebeu uma reclamação de um cliente. O cliente disse que havia acabado de iniciar duas operações para atualizar a idade , mas a idade exibida era de fato a idade da primeira atualização, e o segunda atualização não entrou em vigor.

O chefe imediatamente encontrou Ngawang e repreendeu Ngawang: " Há bugs em uma operação de atualização tão simples? Onde eu coloco meu rosto? Você ainda quer seu bolo? "

Awang entrou em pânico quando soube que o bolo que estava prestes a receber estava prestes a desaparecer e imediatamente se conectou ao servidor para solucionar o problema.Awang encontrou o problema após consultar o cache e os dados do banco de dados.

Os dados do banco de dados são os dados da segunda operação de atualização do cliente, e o cache de fato são os dados da primeira operação de atualização, ou seja, há um problema de inconsistência entre o banco de dados e os dados armazenados em cache .

Este problema é grande.Após uma rodada de análise, Awang causou a inconsistência entre os dados no cache e o banco de dados devido a problemas de simultaneidade !

Atualize o banco de dados primeiro e, em seguida, atualize o cache

Por exemplo, se duas solicitações, "solicitação A" e "solicitação B", atualizarem os dados "mesmos" ao mesmo tempo, esta sequência pode aparecer:

foto

A solicita para atualizar os dados do banco de dados para 1 primeiro e, em seguida, solicita B para atualizar os dados do banco de dados para 2 antes de atualizar o cache, depois também atualiza o cache para 2 e, em seguida, A solicita para atualizar o cache para 1.

Neste momento, os dados no banco de dados são 2, mas os dados no cache são 1 e os dados no cache e no banco de dados são inconsistentes .

Atualize o cache primeiro e, em seguida, atualize o banco de dados

Ainda haveria algum problema com a solução de " atualizar primeiro o cache, depois atualizar o banco de dados "?

Ainda existem problemas de simultaneidade, e o mesmo vale para a análise.

Assumindo que duas requisições, "solicitação A" e "solicitação B", atualizem os "mesmos" dados ao mesmo tempo, pode ocorrer a seguinte sequência:

foto

A solicita a atualização dos dados em cache para 1 primeiro e, em seguida, antes de atualizar o banco de dados, B solicita a atualização dos dados em cache para 2, depois atualiza o banco de dados para 2 e, em seguida, A solicita para atualizar os dados do banco de dados para 1.

Neste momento, os dados no banco de dados são 1, mas os dados no cache são 2 e há uma inconsistência entre os dados no cache e o banco de dados .

Portanto, seja "atualize o banco de dados primeiro, depois atualize o cache" ou "atualize o cache primeiro e depois atualize o banco de dados", ambos os esquemas apresentam problemas de simultaneidade. Quando duas solicitações atualizam os mesmos dados simultaneamente, pode haver um cache. Inconsistência com os dados no banco de dados .

Atualizar o banco de dados primeiro ou excluir o cache primeiro?

Após localizar o problema, Awang decidiu excluir os dados do cache em vez de atualizar o cache ao atualizar os dados. Então, quando os dados são lidos, verifica-se que não há dados no cache e, em seguida, os dados são lidos do banco de dados e atualizados no cache.

A estratégia que Awang acha que tem um nome, é chamada de estratégia de Cache Aside , e a chinesa é chamada de estratégia de bypass de cache.

Essa estratégia pode ser subdividida em "estratégia de leitura" e "estratégia de gravação".

foto

Passos para escrever uma estratégia:

  • atualizar dados no banco de dados;
  • Exclua os dados no cache.

Passos para ler a estratégia:

  • Se os dados lidos atingirem o cache, os dados serão retornados diretamente;
  • Se os dados lidos não atingirem o cache, leia os dados do banco de dados, grave os dados no cache e devolva-os ao usuário.

Quando Nga Wang pensou em "estratégia de escrita", ele caiu em um pensamento mais profundo, qual ordem ele deveria escolher?

  • Exclua o cache primeiro e, em seguida, atualize o banco de dados;
  • Atualize o banco de dados primeiro e, em seguida, exclua o cache.

Após a última lição, Ngawang já não "dá como certo" com o plano de eleição aleatória, porque o chefe deu um grande bolo desta vez, então ele deve agarrá-lo.

Assim, Awang analisa-o da perspectiva da simultaneidade para ver qual dos dois esquemas pode garantir a consistência dos dados entre o banco de dados e o cache.

Exclua o cache primeiro e, em seguida, atualize o banco de dados

Awang ainda analisa a cena da tabela do usuário.

Suponha que a idade de um usuário seja 20 anos, a solicitação A deseja atualizar a idade do usuário para 21 anos, portanto, excluirá o conteúdo do cache. Neste momento, outra solicitação B deseja ler a idade do usuário. Depois de consultar o cache e encontrar uma falha, ele lerá a idade de 20 do banco de dados e a gravará no cache e solicitará que A continue para alterar o banco de dados e colocar o usuário A idade foi atualizada para 21.

foto

Em última análise, a idade do usuário é 20 (valor antigo) no cache e 21 (novo valor) no banco de dados, e os dados do cache e do banco de dados são inconsistentes.

Pode-se ver que se o cache for excluído primeiro, e depois o banco de dados for atualizado, o problema de inconsistência de dados entre o cache e o banco de dados ainda ocorrerá quando "ler + escrever" for simultâneo .

Atualize o banco de dados primeiro e, em seguida, exclua o cache

Continue a analisar o cenário simultâneo de solicitações de "leitura + gravação".

Se os dados de um usuário não existirem no cache, solicite A para consultar o banco de dados para encontrar a idade de 20 anos ao ler os dados e outro solicite B para atualizar os dados quando não estiverem gravados no cache. Ele atualiza a idade no banco de dados para 21 e limpa o cache. Neste momento, a solicitação A grava os dados com a idade de 20 lidos do banco de dados no cache.

foto

Em última análise, a idade do usuário é 20 (valor antigo) no cache e 21 (novo valor) no banco de dados, e os dados do cache e do banco de dados são inconsistentes.

A partir da análise teórica acima, atualizar o banco de dados primeiro e depois deletar o cache também causará o problema de inconsistência de dados, mas na prática, a probabilidade desse problema não é alta .

Como a gravação no cache geralmente é muito mais rápida do que a gravação no banco de dados , é difícil, na prática, solicitar que A atualize o cache após a solicitação B ter atualizado o banco de dados e excluído o cache.

E uma vez que a solicitação A atualiza o cache antes que a solicitação B exclua o cache, as solicitações subsequentes irão reler os dados do banco de dados devido a uma falta de cache, portanto, não há tal inconsistência.

Portanto, a solução de "atualizar primeiro o banco de dados e depois excluir o cache" pode garantir a consistência dos dados .

Além disso, para ser infalível, Awang também adicionou um " tempo de expiração " aos dados em cache. Mesmo que haja inconsistência nos dados em cache durante esse período, há um tempo de expiração para obter o resultado final, para que pode ser conseguida.

Depois de pensar sobre este passo, Awang sentiu que ele era realmente um pequeno gênio, porque ele realmente pensou em um plano "sem costura", ele adotou esse plano sem dizer uma palavra, e depois de alguns dias jogando, ele finalmente foi concluído.

Ele confiantemente relatou ao chefe que havia resolvido a reclamação do último cliente. O chefe acha que Ngawang é um cara legal, ele resolveu o problema tão rápido e então deixou Ngawang observar por alguns dias.

Como as coisas podem ir tão bem? Como resultado, não demorou muito para que o chefe recebesse outra reclamação do cliente, dizendo que havia atualizado claramente os dados, mas os dados demorariam um pouco para entrar em vigor , e o cliente não poderia aceitá-lo.

O chefe procurou Awang com um rosto inexpressivo e pediu a Awang que descobrisse o problema o mais rápido possível.

Awang ficou ainda mais em pânico quando soube que havia outro bug. Ele imediatamente se conectou ao servidor para solucionar o problema. Depois de verificar o log, ele descobriu o motivo.

"Atualizar o banco de dados primeiro, depois excluir o cache" são na verdade duas operações. Todas as análises anteriores são baseadas no fato de que essas duas operações podem ser executadas com sucesso ao mesmo tempo. O problema desta reclamação do cliente é que o cache é excluído at **** (a segunda operação) falhou, fazendo com que os dados no cache fossem o valor antigo .

Felizmente, um tempo de expiração foi adicionado ao cache antes, então o fenômeno de que o cliente disse que a atualização entrará em vigor após um período de tempo. lido no cache.Dados antigos, então o problema é maior.

Então, surge uma nova pergunta, como garantir que as duas operações de "atualizar o banco de dados primeiro e depois excluir o cache" possam ser executadas com sucesso?

Depois de analisar o problema, Awang relatou o problema ao chefe em pânico.

Depois que o chefe soube do assunto, ele deu a Ngawang mais alguns dias para resolver o problema, e a questão de pintar bolos não foi mencionada novamente desta vez.

Como Awang resolverá esse problema?

A coisa do bolo desenhada pelo chefe pode ser cumprida para Ngawang?

Preveja o futuro e ouça a história de Ngawang da próxima vez.

foto

resumo

É isso para Ngawang, vamos falar de outra coisa.

Embora a solução de "atualizar o banco de dados primeiro, depois excluir o cache" garanta a consistência dos dados entre o banco de dados e o cache, mas toda vez que os dados forem atualizados, os dados armazenados em cache serão excluídos, o que afetará a taxa de acertos do cache.

Portanto, se nosso negócio tiver altos requisitos na taxa de acerto do cache, podemos adotar a solução "atualizar banco de dados + atualizar cache", pois atualizar o cache não causará faltas de cache .

No entanto, já analisamos essa solução anteriormente. Quando duas solicitações de atualização são executadas simultaneamente, haverá um problema de inconsistência de dados, pois as duas operações de atualização do banco de dados e atualização do cache são independentes, e não fazemos nenhum controle de concorrência de a operação. , então quando duas threads as atualizam simultaneamente, a inconsistência de dados será causada pela diferença na ordem de escrita.

Portanto, temos que adicionar alguns meios para resolver esse problema, aqui estão duas abordagens:

  • Antes de atualizar o cache, adicione um bloqueio distribuído para garantir que apenas uma solicitação para atualizar o cache seja executada ao mesmo tempo e não haverá problemas de simultaneidade. .
  • Quando o cache é atualizado, um tempo de expiração curto é adicionado ao cache , de modo que, mesmo que o cache seja inconsistente, os dados armazenados em cache expirarão rapidamente, o que ainda é aceitável para o negócio.

A propósito, a solução para a inconsistência de cache causada por solicitações simultâneas de "leitura + gravação" para o esquema "excluir o cache primeiro e depois excluir o banco de dados" é " exclusão dupla atrasada ".

O pseudocódigo da implementação de exclusão dupla atrasada é o seguinte:

#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)

Um tempo de suspensão é adicionado, principalmente para garantir que, quando a solicitação A estiver em suspensão, a solicitação B possa concluir a operação de "ler dados do banco de dados e, em seguida, gravar o cache ausente no cache" durante esse período e, em seguida, solicitar que A conclua o sleep. e, em seguida, exclua o cache.

Portanto, o tempo de suspensão da solicitação A precisa ser maior que o tempo da solicitação B para "ler dados do banco de dados + gravar no cache".

No entanto, o tempo de sono específico é na verdade uma metafísica , e é difícil de avaliar, então essa solução é apenas para garantir a consistência o máximo possível. Em casos extremos, ainda haverá inconsistências de cache.

Portanto, é mais recomendável usar a solução "atualize primeiro o banco de dados e, em seguida, exclua o cache".


Revisão da situação anterior

Da última vez, o programador Awang introduziu o Redis como a camada de cache do MySQL para melhorar o desempenho do acesso aos dados, mas isso não é tão simples, porque o problema da consistência de gravação dupla entre o Redis e o MySQL deve ser considerado.

Depois de muitos contratempos, Awang finalmente escolheu a estratégia de " atualizar o banco de dados primeiro, depois excluir o cache ", pois essa estratégia pode maximizar a consistência dos dados mesmo ao ler e gravar simultaneamente.

O Awang inteligente também apresentou uma solução de baixo para cima, que é adicionar um tempo de expiração ao cache.

Achei que não haveria problema de consistência de dados dessa forma. Como resultado, após o lançamento da função, o chefe ainda recebeu uma reclamação do usuário "que ele atualizou claramente os dados, mas os dados entrarão em vigor após um período de tempo", e o cliente não poderia aceitá-lo.

O chefe disse a Awang, que entrou em pânico ainda mais quando soube que havia outro bug e imediatamente entrou no servidor para solucionar o problema.Após verificar o log, ele descobriu o motivo.

"Atualize o banco de dados primeiro, depois exclua o cache" são na verdade duas operações. O problema com a reclamação do cliente desta vez é que a exclusão do cache (a segunda operação) falhou, resultando nos dados no cache sendo o valor antigo, enquanto o banco de dados é o valor mais recente .

Felizmente, um tempo de expiração foi adicionado ao cache antes, então o fenômeno de que o cliente disse que a atualização entrará em vigor após um período de tempo. lido no cache.Dados antigos, então o problema é maior.

Então, surge uma nova pergunta, como garantir que as duas operações de "atualizar o banco de dados primeiro e depois excluir o cache" possam ser executadas com sucesso?

Depois de analisar o problema, Awang relatou o problema ao chefe em pânico.

Depois que o chefe soube do assunto, ele deu a Ngawang mais alguns dias para resolver o problema, e a questão de pintar bolos não foi mencionada novamente desta vez.

  • Como Awang resolverá esse problema?
  • A coisa do bolo desenhada pelo chefe pode ser cumprida para Ngawang?

Como garantir que ambas as operações possam ser executadas com sucesso?

A reclamação do usuário desta vez é porque a exclusão do cache (segunda operação) falhou, resultando no valor antigo do cache, enquanto o banco de dados é o valor mais recente, causando o problema de inconsistência entre o banco de dados e os dados armazenados em cache, o que afetará negócios sensíveis.

Por exemplo, para ilustrar.

O aplicativo precisa atualizar o valor dos dados X de 1 para 2, primeiro atualizar o banco de dados com êxito e, em seguida, excluir o cache de X no cache do Redis, mas essa operação falha. Neste momento, o novo valor de X no banco de dados é 2 e o valor no Redis é 2. O valor de cache de X é 1 e há um problema de inconsistência entre o banco de dados e os dados armazenados em cache.

foto

Então, se houver uma solicitação subsequente para acessar o dado X, ele será consultado primeiro no Redis. Como o cache não é excluído, ele atingirá o cache, mas o valor antigo de 1 será lido.

Na verdade, se você operar o banco de dados primeiro ou o cache primeiro, desde que a segunda operação falhe, haverá um problema de consistência de dados.

A causa do problema é conhecida, como resolvê-lo? Existem duas maneiras:

  • mecanismo de repetição.
  • Assine o log binário do MySQL e, em seguida, opere o cache.

Vamos falar sobre o primeiro.

mecanismo de repetição

Podemos introduzir uma fila de mensagens , adicionar os dados a serem operados pela segunda operação (excluir o cache) à fila de mensagens e deixar os consumidores operarem os dados.

  • Se o aplicativo não excluir o cache , ele poderá reler os dados da fila de mensagens e excluir o cache novamente.Esse é o mecanismo de repetição . Obviamente, se a repetição exceder um certo número de vezes e ainda falhar, precisamos enviar uma mensagem de erro para a camada de negócios.
  • Se a exclusão do cache for bem-sucedida , os dados devem ser removidos da fila de mensagens para evitar operações repetidas, caso contrário, continue tentando novamente.

Tome um exemplo para ilustrar o processo do mecanismo de repetição.

foto

Assine o log binário do MySQL e, em seguida, opere o cache

O primeiro passo da estratégia de " atualizar o banco de dados primeiro, depois excluir o cache " é atualizar o banco de dados. Se o banco de dados for atualizado com sucesso, um log de alterações será gerado e registrado no binlog.

Assim, podemos obter os dados específicos a serem operados assinando o log binlog e, em seguida, executar a exclusão do cache. O middleware Canal de código aberto do Alibaba é baseado nessa implementação.

O Canal simula o protocolo interativo de replicação mestre-escravo do MySQL, disfarça-se como um nó escravo do MySQL e envia uma solicitação de despejo para o nó mestre do MySQL. Após o MySQL receber a solicitação, ele começará a enviar o Binlog para o Canal. Após o Canal analisar o Binlog byte stream, convertido em dados estruturados legíveis para assinaturas de programas downstream.

O diagrama a seguir mostra como o Canal funciona:

foto

Portanto, se quisermos garantir que a segunda operação da estratégia "atualize o banco de dados primeiro e depois exclua o cache" possa ser executada com sucesso, podemos usar "fila de mensagens para tentar novamente a exclusão do cache" ou "inscrever-se no MySQL binlog e depois operar o cache", esses dois métodos têm uma característica comum, todos eles usam o cache de operação assíncrona.

O chefe está fazendo um bolo

Como Awang está familiarizado com filas de mensagens, ele decidiu usar o esquema "fila de mensagens para repetir a exclusão do cache" para resolver esse problema do usuário.

Após vários dias e noites de operação, o servidor está pronto e eu imediatamente reporto ao chefe.

O chefe pediu a Ngawang que observasse por mais algum tempo e, se não houver problema, ele discutirá a questão do "bolo" durante o Festival do Meio Outono.

O tempo voa e o Mid-Autumn Festival está aqui. Durante esse período, não houve problemas de dados inconsistentes de feedback do usuário.

O chefe viu que Ngawang teve um desempenho muito bom desta vez, não houve mais erros, e o desempenho de acesso do servidor também melhorou, então ele enviou para Ngawang este bolo de lua super grande. Você pode ver que esse bolo é grande e redondo, assim como seu código Longo e muito mais.

foto

Quando Nga Wang viu este bolo de lua, não pôde deixar de rir, não esperava que fosse um bolo desenhado pelo chefe, era um bolo muito grande. . . .

A história acima é puramente fictícia, se houver alguma coincidência, fica a seu critério.

Acho que você gosta

Origin blog.csdn.net/qq_34827674/article/details/123866483
Recomendado
Clasificación