Surpresa fsync () PostgreSQL

Os desenvolvedores de DBMS, por necessidade, estão preocupados com o fato de os dados caírem com segurança no armazenamento permanente. Portanto, quando a comunidade do PostgreSQL descobriu que a maneira como o kernel lida com erros de E / S pode levar à perda de dados sem que nenhum erro seja relatado ao espaço do usuário, surgiu muito descontentamento. O problema, que é agravado pelo fato de o PostgreSQL executar E / S com buffer, não é exclusivo do Linux e não será fácil de resolver mesmo lá.

Craig Ringer relatou o problema pela primeira vez à lista de emails pgsql-hackers no final de março. Em resumo, o PostgreSQL assume que uma chamada fsync() bem-sucedida indica que todos os dados registrados desde a última chamada bem-sucedida foram transferidos com segurança para o armazenamento persistente. Quando as gravações de E / S em buffer falham devido a um erro de hardware, os sistemas de arquivos reagem de maneira diferente, mas esse comportamento geralmente envolve a exclusão de dados nas páginas correspondentes e a marcação como limpa. Portanto, os blocos de leitura que foram escritos provavelmente retornarão outra coisa, mas não os dados registrados.

E o relatório de erros? Há um ano, a cúpula Linux File System, Storage and Memory-Management Summit (LSFMM) incluiu uma sessão de relatório de erros , na qual tudo era chamado de "bagunça"; erros podem ser facilmente perdidos; portanto, nenhum aplicativo os verá. Alguns patches incluídos no 4.13 melhoraram a situação um pouco durante o ciclo de desenvolvimento (e no 4.16 houve algumas alterações para melhorá-lo ainda mais), no entanto, existem maneiras de perder as notificações de erro, conforme descrito abaixo. Se isso acontecer em um servidor PostgreSQL, poderá levar à corrupção automática do banco de dados.

Os desenvolvedores do PostgreSQL ficaram descontentes. Tom Lane descreveu isso como " dano cerebral ao núcleo " , enquanto Robert Haas o chamou de " 100% estúpido ". No início da discussão, os desenvolvedores do PostgreSQL entenderam claramente como, na opinião deles, o kernel deveria funcionar: as páginas que não puderam ser escritas deveriam ser armazenadas na memória em um estado "sujo" (para tentativas subseqüentes), e o descritor de arquivo correspondente deveria ser traduzido para Status de erro permanente para que o servidor PostgreSQL não possa ignorar o problema.

Onde algo deu errado


No entanto, mesmo antes da comunidade do kernel entrar na discussão, ficou claro que a situação não era tão simples quanto poderia parecer. Thomas Munro disse que o Linux não é único nesse comportamento; O OpenBSD e o NetBSD também podem não reportar erros de gravação no espaço do usuário. E, como se viu, a maneira como o PostgreSQL lida com operações de E / S com buffer complica muito a imagem.

Este mecanismo foi descrito em detalhes por Haas. Um servidor PostgreSQL funciona como um conjunto de processos, muitos dos quais podem executar E / S em arquivos de banco de dados. O fsync() chamada fsync() , no entanto, é tratado em um único processo de checkpointer (processo "checkpointer"), que consiste em manter o armazenamento em disco em um estado consistente para se recuperar de falhas. O Checkpointer geralmente não mantém todos os arquivos relevantes abertos, portanto, muitas vezes é necessário abrir o arquivo antes de chamar fsync() . É aqui que o problema surge: mesmo no kernels 4.13 e nas versões posteriores, o checkpointer não verá nenhum erro que ocorreu antes da abertura do arquivo. Se algo ruim acontecer antes de chamar open() checkpointer-a, a próxima chamada para fsync() retornará êxito. Existem várias maneiras de causar um erro de E / S fora do fsync() ; por exemplo, o kernel pode encontrar um deles durante a gravação em segundo plano. Alguém chamando sync() também pode encontrar um erro de E / S e "absorver" o estado de erro resultante.

Haas descreveu esse comportamento como incapaz de atender às expectativas do PostgreSQL:
Tudo o que você (ou alguém) tem é basicamente uma suposição não comprovada de que
quais descritores de arquivo podem ser relevantes para um erro específico, mas aconteceu que o PostgreSQL nunca o correspondeu. Você pode continuar dizendo que o problema está em nossos palpites, mas me parece errado supor que somos o único programa que já os executou.

Como resultado, Joshua Drake mudou a conversa para a lista de desenvolvimento do ext4, incluindo parte da comunidade de desenvolvimento do kernel. Dave Chinner descreveu rapidamente esse comportamento como "uma receita para o desastre, especialmente no código de plataforma cruzada, em que cada plataforma do sistema operacional se comporta de maneira diferente e quase nunca corresponde ao esperado ." Em vez disso, Ted Tso explicou por que as páginas afetadas são marcadas como limpas após um erro de E / S; em resumo, a causa mais comum de erros de E / S é quando o usuário ejeta a unidade USB na hora errada. Se um processo copia muitos dados nesse disco, o resultado será o acúmulo de páginas sujas na memória, possivelmente até o ponto em que o sistema não possui memória suficiente para outras tarefas. Portanto, essas páginas não podem ser salvas e serão limpas se o usuário desejar que o sistema permaneça utilizável após esse evento.

Tanto Chinner quanto Tso, juntamente com outros, disseram que o PostgreSQL tinha a solução certa - mudar para E / S direta (DIO). O uso do DIO oferece um maior nível de controle sobre write-back e E / S em geral; isso inclui acesso a informações sobre quais operações de E / S podem ter falhado. Andres Freund, como vários outros desenvolvedores do PostgreSQL, reconheceu que o DIO é a melhor solução a longo prazo. Mas ele também observou que não se deve esperar que os desenvolvedores mergulhem profundamente na implementação dessa tarefa. Enquanto isso, ele disse que existem outros programas (ele mencionou o dpkg) que também são propensos a esse comportamento.

Rumo a uma solução de curto prazo


Durante a discussão, foi prestada atenção considerável à idéia de que uma falha de gravação deve levar ao fato de que as páginas afetadas serão armazenadas na memória em seu estado sujo. Mas os desenvolvedores do PostgreSQL se afastaram rapidamente dessa idéia e não a exigiram. O que eles realmente precisam é, em última análise, uma maneira confiável de descobrir se algo deu errado. Com isso em mente, os mecanismos usuais de tratamento de erros do PostgreSQL podem lidar com isso; no entanto, pouco pode ser feito em sua ausência.

Em algum momento da discussão, Tso mencionou que o Google tem seu próprio mecanismo de tratamento de erros de E / S. O kernel foi instruído a relatar erros de E / S através do soquete netlink; O processo dedicado recebe essas notificações e responde de acordo. No entanto, esse mecanismo nunca fez isso na entrada. Freind apontou que esse mecanismo seria "ideal" para o PostgreSQL, podendo aparecer no domínio público em um futuro próximo.

Enquanto isso, Jeff Leighton estava pensando em outra idéia: definir um sinalizador no superbloco do sistema de arquivos quando ocorrer um erro de E / S. Uma chamada para syncfs() limpará esse sinalizador e retornará um erro se ele tiver sido definido. O syncfs() verificação do PostgreSQL pode chamar periodicamente syncfs() para pesquisar erros no sistema de arquivos que contém o banco de dados. Freund concordou que essa poderia ser uma solução viável para o problema.

Obviamente, qualquer mecanismo desse tipo aparecerá apenas em novos kernels; Enquanto isso, as instalações do PostgreSQL geralmente são executadas em kernels antigos suportados por distribuições corporativas. Nesses kernels, parece que não há essas melhorias incluídas na versão 4.13. Para esses sistemas, pouco pode ser feito para ajudar o PostgreSQL a detectar erros de E / S. Pode ser o suficiente para iniciar um daemon que varre o log do sistema e procura por mensagens de erro de E / S lá. Não é a solução mais elegante, e é complicada pelo fato de que diferentes drivers de bloco e sistemas de arquivos relatam erros de maneiras diferentes, mas essa pode ser a melhor opção disponível.

O próximo passo provavelmente será uma discussão no evento LSFMM 2018 em 23 de abril. Se você tiver sorte, haverá algum tipo de solução que funcionará para as partes interessadas. No entanto, uma coisa que não muda é o simples fato de que a manipulação de erros é difícil de fazer corretamente.

Source: https://habr.com/ru/post/pt472684/


All Articles