PostgreSQL e configurações de consistência de registros para cada conexão específica

A tradução do artigo foi preparada especialmente para os alunos do curso "Banco de Dados" . É interessante desenvolver nessa direção? Convidamos você para o Open Doors Day , onde falamos em detalhes sobre o programa, recursos do formato on-line, competências e perspectivas de carreira que aguardam os formados após o treinamento.



PostgreSQL e configurações de consistência de registros para cada conexão específica
No Compose, precisamos lidar com muitos bancos de dados, o que nos dá a oportunidade de conhecer melhor nossas funcionalidades e fraquezas. À medida que aprendemos a amar os recursos funcionais dos novos bancos de dados, às vezes começamos a pensar em como seria bom se funções semelhantes estivessem presentes em ferramentas mais maduras com as quais trabalhamos há muito tempo. Um dos novos recursos que o PostgreSQL queria ver era a consistência de gravação personalizada em todo o cluster. E, como se viu, já o temos e hoje queremos compartilhar com você informações sobre como usá-lo.


Por que eu preciso disso?


Como um cluster deve se comportar depende do seu aplicativo. Tome, por exemplo, um aplicativo para pagamento de contas. Você precisará de 100% de consistência no cluster, portanto precisará ativar confirmações síncronas para que seu banco de dados aguarde todas as alterações. No entanto, se o seu aplicativo for uma rede social em rápido crescimento, provavelmente você preferirá 100% de consistência com uma resposta rápida. Para conseguir isso, você pode usar confirmações assíncronas no seu cluster.


Conheça o compromisso


Você precisa comprometer a consistência e o desempenho dos dados. O PostgreSQL parte da consistência, porque a configuração padrão neste caso é previsível e sem surpresas inesperadas. E agora vamos nos familiarizar com compromissos.


Compromisso 1: Desempenho


Se o cluster do PostgreSQL não exigir consistência, ele poderá funcionar de forma assíncrona. A gravação é feita no líder do cluster e as atualizações serão enviadas para suas réplicas após alguns milissegundos. Quando a consistência é necessária para um cluster do PostgreSQL, ele deve funcionar de forma síncrona. O registro será feito no líder do cluster, que enviará atualizações para as réplicas e aguardará a confirmação de que todos fizeram um registro antes de enviar a confirmação ao cliente que iniciou o registro de que foi bem-sucedido. 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.


Compromisso 2: Consistência


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


No modo síncrono, isso não acontece. Se o líder falhar, todas as réplicas serão atualizadas, pois qualquer registro confirmado no líder deve ser confirmado nas réplicas. Aqui está - coerência.


Faz sentido usar o comportamento síncrono em um aplicativo para pagar contas, onde a consistência tem uma clara vantagem em encontrar um compromisso entre consistência e desempenho. O mais importante para esse aplicativo são dados válidos. Agora lembre-se da rede social, na qual a principal tarefa é manter a atenção do usuário, respondendo às solicitações o mais rápido possível. Nesse caso, o desempenho com menos saltos de rede e menos confirmações de espera será uma prioridade. No entanto, a troca entre desempenho e consistência não é a única a se pensar.


Compromisso 3: Falhas


É muito importante entender como o cluster se comporta durante uma falha. Considere uma situação em que uma ou mais réplicas falham. Quando as confirmações são processadas de forma assíncrona, o líder continuará funcionando, ou seja, receberá e processará registros sem aguardar a falta de réplicas. 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 da confirmação até que a réplica retorne ao cluster e possa aceitar e confirmar o registro.


Uma conexão por transação?


Cada aplicativo precisa de um tipo especial de combinação de consistência e desempenho. A menos, é claro, que seja nosso aplicativo de cobrança, que achamos completamente consistente, ou nosso aplicativo de rede social quase efêmero. Em todos os outros casos, haverá momentos em que algumas operações devem ser síncronas e outras assíncronas. Você pode não querer que o sistema aguarde o fechamento da mensagem enviada ao bate-papo, mas se o pagamento for feito no mesmo aplicativo, você terá que aguardar.


Todas essas decisões, é claro, são tomadas pelo desenvolvedor do aplicativo. As decisões corretas sobre quando aplicar essa ou aquela abordagem ajudarão a tirar o máximo proveito do cluster. É importante que o desenvolvedor possa alternar entre eles no nível SQL para conexões e transações.


Fornecendo 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á remote_write , mas tem três outras opções: local , remote_write ou off .


Quando o parâmetro está off , todas as confirmações síncronas são interrompidas, mesmo no sistema local. O parâmetro em local determina o modo síncrono para o sistema local, mas as gravações nas réplicas são assíncronas. 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 recebeu o registro, mas não o gravou no disco.


Considerando o intervalo de opções disponíveis, escolhemos o comportamento e, lembrando que existem registros síncronos, selecionamos local para confirmações assíncronas na rede, enquanto deixamos as confirmações locais síncronas.


Agora, mostraremos como configurar isso em um instante, mas imagine que definimos synchronous_commit como local para o servidor. Nós nos perguntamos se o parâmetro synchronous_commit pode ser alterado em tempo real, e acabou não sendo possível, existem duas maneiras de fazer isso. O primeiro é configurar sua sessão de conexão da seguinte maneira:


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

Todos os registros subsequentes na sessão confirmarão as operações de gravação para as réplicas antes de retornar um resultado positivo ao cliente conectado. A menos, é claro, que você altere a configuração synchronous_commit novamente. Você pode omitir a parte SESSION do comando, pois ela estará no valor padrão.


A segunda maneira é boa quando você só deseja garantir a replicação síncrona para uma única transação. Em muitos bancos de dados NoSQL, o conceito de transações não existe, mas existe no PostgreSQL. Nesse caso, você inicia a transação e, em seguida, defina o synchronous_commit antes de gravar na transação. COMMIT a transação usando qualquer valor do parâmetro synchronous_commit que foi definido naquele momento, embora seja melhor definir a variável antecipadamente para garantir que outros desenvolvedores entendam que os registros não são assíncronos.


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

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


Configuração do PostgreSQL


Antes disso, imaginávamos um sistema PostgreSQL com o synchronous_commit definido como local . Para que isso seja real no lado do servidor, você precisará definir dois parâmetros de configuração do servidor. Outro parâmetro synchronous_standby_names assumirá o controle quando o synchronous_commit estiver synchronous_commit . Ele determina quais réplicas são elegíveis para confirmações síncronas e a definiremos como * , o que significa que todas as réplicas estão ativadas. Esses valores geralmente são configurados no arquivo de configuração adicionando:


 synchronous_commit = local synchronous_standby_names='*' 

Ao definir o parâmetro synchronous_commit como local , criamos um sistema no qual as unidades locais permanecem síncronas, mas as confirmações de réplica de rede são assíncronas por padrão. A menos, é claro, que decidamos fazer esses commits síncronos, como mostrado acima.


Se você acompanhou o desenvolvimento do projeto Governor , pode ter notado algumas alterações recentes ( 1 , 2 ), que permitiram aos usuários do Governor testar esses parâmetros e controlar sua consistência.


Mais algumas palavras ...


Há apenas uma semana, eu diria a você que não é possível ajustar o PostgreSQL com tanta precisão. Foi então que Kurt, um membro da equipe da plataforma Compose, insistiu que havia essa oportunidade. Ele pacificou minhas objeções e encontrou o seguinte na documentação do PostgreSQL:



Este parâmetro pode ser alterado a qualquer momento. O comportamento de qualquer transação é determinado pela configuração em vigor ao confirmar. Portanto, é possível e útil que as confirmações sejam confirmadas de forma síncrona para algumas transações e assíncrona para outras. Por exemplo, para forçar uma única transação de multistatement a confirmar de forma assíncrona quando o valor padrão é o oposto, defina SET LOCAL synchronous_commit TO OFF na transação.


Com essa pequena modificação no arquivo de configuração, demos aos usuários a capacidade de controlar sua consistência e desempenho.

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


All Articles