PostgreSQL e configurações de consistência de gravação específicas da conexão

A tradução do artigo foi elaborada especificamente para os alunos do curso "Base de dados". Interessado em desenvolver nessa direção? Nós convidamos você a Dia Aberto, onde falamos detalhadamente sobre o programa, características do formato online, competências e perspectivas de carreira que aguardam os formandos após a formação.

PostgreSQL e configurações de consistência de gravação específicas da conexão

PostgreSQL e configurações de consistência de gravação específicas da conexão
No Compose lidamos com diversos bancos de dados, o que nos dá a oportunidade de nos familiarizarmos mais com suas funcionalidades e deficiências. À medida que aprendemos a amar os recursos dos novos bancos de dados, às vezes começamos a pensar como seria bom se recursos semelhantes estivessem presentes nas ferramentas mais maduras com as quais trabalhamos há muito tempo. Um dos novos recursos que eu queria ver no PostgreSQL era a consistência de gravação configurável por conexão em todo o cluster. E acontece que já o temos e hoje queremos compartilhar com vocês informações sobre como você pode usá-lo.

Por que eu preciso disso?

O modo como o cluster deve se comportar depende do seu aplicativo. Veja, por exemplo, um aplicativo de pagamento de contas. Você precisará de XNUMX% de consistência em todo o cluster, então terá que habilitar commits síncronos para que seu banco de dados aguarde que todas as alterações sejam feitas. No entanto, se o seu aplicativo for uma rede social de rápido crescimento, você provavelmente preferirá uma resposta rápida a XNUMX% de consistência. Para conseguir isso, você pode usar commits assíncronos em seu cluster.

Alcance o compromisso

Você precisa fazer concessões entre consistência e desempenho dos dados. O PostgreSQL se afasta da consistência porque a configuração padrão é previsível e sem surpresas inesperadas. Agora vamos examinar os compromissos.

Compensação 1: Desempenho

Se o cluster PostgreSQL não exigir consistência, ele poderá ser executado de forma assíncrona. A gravação é feita no líder do cluster e as atualizações serão enviadas para suas réplicas alguns milissegundos depois. Quando um cluster PostgreSQL requer consistência, ele deve ser executado de forma síncrona. A gravação será feita para o líder do cluster, que enviará uma atualização para as réplicas e aguardará a confirmação de que cada uma gravou antes de enviar a confirmação ao cliente que iniciou a gravação de que ela foi bem-sucedida. A diferença prática entre essas abordagens é que o método assíncrono requer dois saltos de rede, enquanto o método síncrono requer quatro.

Compensação 2: Consistência

O resultado no caso de falha do líder nessas duas abordagens também será diferente. Se o trabalho for executado de forma assíncrona, se tal erro ocorrer, nem todos os registros serão confirmados pelas réplicas. Quanto será perdido? Depende do próprio aplicativo e da eficiência da replicação. A replicação do Compose impedirá que uma réplica se torne líder se a quantidade de informações nela contida for 1 MB menor que a do líder, ou seja, até 1 MB de registros poderá ser potencialmente perdido durante a operação assíncrona.

Isso não acontece no modo síncrono. Se o líder falhar, todas as réplicas serão atualizadas, pois qualquer gravação confirmada no líder deverá ser confirmada nas réplicas. Isso é consistência.

O comportamento síncrono faz sentido em um aplicativo de cobrança onde a consistência tem uma clara vantagem no equilíbrio entre consistência e desempenho. O mais importante para tal aplicação são os dados válidos. Agora pense em uma rede social em que a principal tarefa é manter a atenção do usuário respondendo às solicitações o mais rápido possível. Neste caso, o desempenho com menos saltos de rede e menos espera por commits será uma prioridade. No entanto, a compensação entre desempenho e consistência não é a única em que você deve pensar.

Compensação 3: Falhas

É muito importante entender como um cluster se comporta durante uma falha. Considere uma situação em que uma ou mais réplicas falham. Quando os commits são processados ​​de forma assíncrona, o líder continuará funcionando, ou seja, aceitando e processando gravações, sem esperar por réplicas perdidas. Quando as réplicas retornam ao cluster, elas alcançam o líder. Com a replicação síncrona, se as réplicas não responderem, o líder não terá escolha e continuará aguardando a confirmação do commit até que a réplica retorne ao cluster e possa aceitar e confirmar a gravação.

Uma conexão por transação?

Cada aplicativo precisa de um tipo diferente de combinação de consistência e desempenho. A menos, claro, que seja o nosso aplicativo de pagamento de contas, que imaginamos ser completamente consistente, ou o nosso aplicativo de rede social quase efêmero. Em todos os outros casos, haverá momentos em que algumas operações deverão ser síncronas e outras assíncronas. Você pode não querer que o sistema espere até que uma mensagem enviada para o chat seja confirmada, mas se um pagamento for processado no mesmo aplicativo, você terá que esperar.

Todas essas decisões, é claro, são tomadas pelo desenvolvedor do aplicativo. Tomar as decisões corretas sobre quando usar cada abordagem ajudará você a aproveitar ao máximo seu cluster. É importante que o desenvolvedor possa alternar entre eles no nível SQL para conexões e transações.

Garantindo o controle na prática

Por padrão, o PostgreSQL fornece consistência. Isso é controlado pelo parâmetro do servidor synchronous_commit. Por padrão está na posição on, mas tem três outras opções: local, remote_write ou off.

Ao definir o parâmetro para off todos os commits síncronos são interrompidos, mesmo no sistema local. O parâmetro local especifica o modo síncrono para o sistema local, mas as gravações nas réplicas são executadas de forma assíncrona. Remote_write vai ainda mais longe: as gravações nas réplicas são feitas de forma assíncrona, mas são retornadas quando a réplica aceita a gravação, mas não a grava no disco.

Ao considerar o leque de opções disponíveis, escolhemos um comportamento e, tendo em mente que on – são gravações síncronas, escolheremos local para commits assíncronos na rede, deixando os commits locais síncronos.

Agora, diremos a você como configurar isso em um momento, mas imagine que configuramos synchronous_commit в local para o servidor. Ficamos nos perguntando se era possível alterar o parâmetro synchronous_commit na hora, e descobriu-se que não só é possível, como há até duas maneiras de fazer isso. A primeira é definir a sessão da sua conexão da seguinte forma:

SET SESSION synchronous_commit TO ON;  
// Your writes go here

Todas as gravações subsequentes na sessão reconhecerão as gravações nas réplicas antes de retornar um resultado positivo ao cliente conectado. A menos, é claro, que você altere a configuração synchronous_commit de novo. Você pode omitir parte SESSION no comando porque estará no valor padrão.

O segundo método é bom quando você deseja apenas garantir a replicação síncrona para uma única transação. Em muitos bancos de dados de geração NoSQL o conceito de transações não existe, mas existe no PostgreSQL. Neste caso você inicia uma transação e então define synchronous_commit в on antes de executar a entrada da transação. COMMIT confirmará a transação usando qualquer valor de parâmetro synchronous_commit, que foi definido na época, embora seja melhor definir a variável antecipadamente para garantir que outros desenvolvedores entendam que as gravações não são assíncronas.

BEGIN;  
SET LOCAL synchronous_commit TO ON;  
// Your writes go here
COMMIT;  

Todas as confirmações de transação serão agora confirmadas como gravadas nas réplicas antes que o banco de dados retorne uma resposta positiva ao cliente conectado.

Configurando o PostgreSQL

Antes disso, imaginamos um sistema PostgreSQL com synchronous_commit, instalado em local. Para tornar isso realista no lado do servidor, você precisará definir duas opções de configuração do servidor. Mais um parâmetro synchronous_standby_names entrará em ação quando synchronous_commit estará em on. Ele determina quais réplicas são elegíveis para commits síncronos e iremos defini-lo como *, o que significará que todas as réplicas estão envolvidas. Esses valores geralmente são configurados em arquivo de configuração adicionando:

synchronous_commit = local  
synchronous_standby_names='*'

Ao definir o parâmetro synchronous_commit em significado local, criamos um sistema onde os discos locais permanecem síncronos, mas as confirmações de réplicas de rede são assíncronas por padrão. A menos, é claro, que decidamos tornar esses commits síncronos, conforme mostrado acima.

Se você tem acompanhado o desenvolvimento Projeto governador, você deve ter notado algumas mudanças recentes (1, 2), o que permitiu aos usuários do Governor testar esses parâmetros e monitorar sua consistência.

Mais algumas palavras...

Há apenas uma semana, eu teria dito que é impossível ajustar o PostgreSQL com tanta precisão. Foi então que Kurt, membro da equipe da plataforma Compose, insistiu que tal oportunidade existia. Ele acalmou minhas objeções e encontrou na documentação do PostgreSQL o seguinte:

PostgreSQL e configurações de consistência de gravação específicas da conexão

Esta configuração pode ser alterada a qualquer momento. O comportamento de qualquer transação é determinado pela configuração em vigor no momento do commit. Portanto, é possível e útil que algumas transações sejam confirmadas de forma síncrona e outras de forma assíncrona. Por exemplo, para forçar alguém multistatement transação para fazer commits de forma assíncrona quando o valor padrão do parâmetro for oposto, defina SET LOCAL synchronous_commit TO OFF em uma transação.

Com esta pequena modificação no arquivo de configuração, demos aos usuários controle sobre sua consistência e desempenho.

Fonte: habr.com

Adicionar um comentário