Atualização do PostgreSQL 18 para self-hosters

:warning: AVISO! Se o seu banco de dados for muito grande, você precisará de muito espaço extra em disco (3x o tamanho do banco de dados) e deve ter muito cuidado com esta atualização!

Acabamos de implementar alterações para atualizar nossa imagem Docker para o PostgreSQL 18. Qualquer administrador de site que reconstruir o Discourse pela linha de comando será atualizado do PostgreSQL 15 anterior para o PostgreSQL 18. Observe que, se você evitou a atualização quando a atualização do PostgreSQL 15 aconteceu em 2025, você pode pular essa atualização e ir diretamente para o PostgreSQL 18.

Se você havia adiado a atualização anteriormente, altere o modelo do PostgreSQL em app.yml de templates/postgres.13.template.yml para templates/postgres.template.yml.

Como em qualquer atualização, é fortemente recomendado fazer um backup antes de fazer qualquer coisa.

Alterações de localidade

Anteriormente, vimos corrupção de índices ocorrer quando a glibc era atualizada, como durante atualizações do sistema operacional. Desde o PostgreSQL 17, há um novo provedor de localidade integrado que é desacoplado da glibc do sistema operacional e, portanto, estável entre versões. Como parte desta atualização, estamos migrando para este provedor integrado usando a localidade C.UTF-8. Esta localidade usa ordenação por ponto de código e a recomendamos pelos motivos de estabilidade mencionados acima.

Para realizar a alteração de localidade, precisamos primeiro criar o novo cluster de banco de dados usando o provedor de localidade integrado e, em seguida, fazer o dump e restaurar o banco de dados neste cluster. Por esse motivo, os requisitos de espaço em disco são maiores do que nas atualizações anteriores, onde realizávamos atualizações no local.

Atualizando

Guia Oficial de Instalação (contêiner único)

Na sua próxima reconstrução, você verá esta mensagem no final:

-------------------------------------------------------------------------------------
ATUALIZAÇÃO DO POSTGRES CONCLUÍDA

O banco de dados antigo 15 está armazenado em /shared/postgres_data_old

Para concluir a atualização, reconstrua novamente usando:

./launcher rebuild app
-------------------------------------------------------------------------------------

Isso significa que tudo correu bem na atualização! Você só precisa emitir uma nova reconstrução para colocar seu site de volta no ar.

Instalação com Contêiner de Dados

Se você estiver executando uma configuração com um contêiner de dados dedicado baseado no modelo fornecido em nosso repositório discourse_docker, certifique-se de desligar o PostgreSQL de forma segura e limpa.

Hoje em dia, temos jobs em segundo plano executando consultas que duram vários minutos, então desligar o contêiner web ajudará a desligar o contêiner de dados com segurança.

./launcher stop web_only
./launcher stop data
./launcher rebuild data
./launcher rebuild data
./launcher rebuild web_only

Antes de emitir a primeira reconstrução para o contêiner de dados, você pode acompanhar o log do PostgreSQL para ver se foi desligado corretamente.

Executar um tail -f shared/standalone/log/var-log/postgres/current deve fornecer o seguinte log se foi limpo:

2025-01-24 09:19:06.437 UTC [37] LOG:  received smart shutdown request
2025-01-24 09:19:06.444 UTC [37] LOG:  background worker "logical replication launcher" (PID 54) exited with exit code 1
2025-01-24 09:19:06.446 UTC [49] LOG:  shutting down
2025-01-24 09:19:06.468 UTC [37] LOG:  database system is shut down

Adiando a atualização

Se você precisar adiar a atualização durante sua próxima reconstrução, você pode trocar o modelo do PostgreSQL no seu arquivo app.yml alterando "templates/postgres.template.yml" para "templates/postgres.15.template.yml".

Isso não é recomendado, pois alguns administradores de site esquecerão de reverter a alteração posteriormente.

Tarefas opcionais pós-atualização

Otimizando estatísticas do PostgreSQL

Após a atualização, o novo PostgreSQL não terá estatísticas de tabela à mão. Você pode gerar essas estatísticas usando:

docker exec -u postgres app \
	/usr/lib/postgresql/18/bin/vacuumdb -d discourse --analyze-in-stages

Limpando dados antigos

Para uma instalação padrão, você pode excluir os dados antigos no formato PG15 com o seguinte comando:

cd /var/discourse
./launcher cleanup

Se você tiver um contêiner de dados separado, precisará remover a cópia de backup assim:

rm -fr /var/discourse/shared/data/postgres_data_old/

FAQ

O cluster de origem não foi desligado de forma limpa

Se você receber uma falha na atualização com a mensagem acima, pode tentar uma abordagem mais simples para colocá-lo em um estado melhor.

Reinicie o contêiner antigo com ./launcher start app. Aguarde alguns minutos até que ele esteja de volta.

Agora desligue-o novamente com ./launcher stop app. Após isso, acompanhe os logs para ver se foi um desligamento limpo:

tail -f shared/standalone/log/var-log/postgres/current
2025-01-24 09:19:06.437 UTC [37] LOG:  received smart shutdown request
2025-01-24 09:19:06.444 UTC [37] LOG:  background worker "logical replication launcher" (PID 54) exited with exit code 1
2025-01-24 09:19:06.446 UTC [49] LOG:  shutting down
2025-01-24 09:19:06.468 UTC [37] LOG:  database system is shut down

Se os logs não indicarem que o banco de dados foi desligado, você pode iniciar o contêiner antigo novamente, entrar com ./launcher enter app, executar estes comandos e acompanhar os logs novamente após a conclusão.

export SVWAIT=300
sv stop nginx
sv stop unicorn
sv stop postgres
exit

Se os logs parecerem com os acima, você pode tentar atualizar novamente usando ./launcher rebuild app.

Os valores de lc_collate para o banco de dados “postgres” não correspondem

Este erro ocorre se você estiver usando localidades não padrão para seu banco de dados. Foi relatado que você precisa de 3 variáveis para que ele tenha sucesso. Certifique-se de que a seção env: do seu arquivo app.yml tenha as 3 linhas:

  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8

Alterando en_US.UTF-8 para sua localidade.

Cada reconstrução faz a atualização novamente, ou seja, loop de atualização

Quando isso acontece, seus logs de atualização conterão

mv: cannot move '/shared/postgres_data' to '/shared/postgres_data_old/postgres_data': Directory not empty
mv: cannot move '/shared/postgres_data_new' to '/shared/postgres_data/postgres_data_new': Directory not empty

Isso significa que ainda há arquivos da última atualização por aí. Mova-os para outro lugar antes de continuar.

Eu pulei a atualização do PostgreSQL 15, o que fazer agora?

Você pode seguir as instruções padrão no topo deste guia e elas atualizarão de sua versão para a 18 sem problemas.

6 Curtiram

ótimo, obrigado Chris!

1 Curtiu

Que tipo de falha, esperançosamente elegante, ocorrerá se não houver espaço livre em disco suficiente? Alguém certamente vai percorrer esse caminho!

Para aqueles que não têm espaço livre em disco suficiente, funcionaria fazer um backup e, em seguida, restaurá-lo em uma instalação limpa, como uma migração?

(Nesse caso, também seria uma boa oportunidade para migrar para uma nova versão LTS do sistema operacional. O Ubuntu 26.04 é bastante recente; a versão 26.04.1 deve chegar muito em breve. Uma instalação limpa do sistema operacional pode ser menos problemática do que uma tentativa de atualização no local.)

2 Curtiram

Eu teria, se não tivesse recebido uma notificação por e-mail sobre esta postagem :raised_back_of_hand: :flushed_face:

Só para confirmar, isso já está ativo agora?

Se eu atualizar pela linha de comando mais tarde esta manhã, tudo isso acontecerá?

O script de atualização verificará o espaço livre e só prosseguirá se for seguro fazê-lo.

Há duas etapas no processo onde o espaço em disco pode se tornar crítico. Se você ignorasse a verificação de espaço livre, é aqui que poderia encontrar problemas:

  1. Ao executar o pg_dump para extrair os dados do banco de dados antigo (é necessário o dobro do armazenamento do BD neste ponto).
  2. Ao executar o pg_restore para inserir os dados de volta no novo banco de dados (é necessário o triplo do armazenamento do BD neste ponto).

Para se recuperar desse estado, você precisaria remover /shared/postgres_dump e /shared/postgres_data_new.

Observe que, ao final da atualização, removemos os arquivos temporários do pg_dump, mas mantemos seus dados do banco de dados pré-atualização em /shared/postgres_data_old apenas por precaução. Uma vez que você estiver satisfeito com o funcionamento de tudo, provavelmente desejará remover esse diretório para liberar espaço em disco.

Testei fazer um backup do Discourse em um site com PG15 e restaurá-lo em um site com PG18. Funcionou para mim, mas esteja ciente de que não é um método oficialmente suportado. Teste minuciosamente em algo que não seja produção primeiro e certifique-se de ter um caminho de retorno!

Recomendo estudar o processo usado pelo script de atualização. Se você tiver requisitos especiais de armazenamento, deverá ser capaz de adaptá-lo às suas necessidades. Novamente, teste primeiro:

Isso está agora no discourse_docker, sim. Se você executar pull na branch main ou rodar ./launcher rebuild app, você obterá isso.

Desativar o discourse_docker da branch main ajuda a prevenir atualizações acidentais se você quiser adiá-la.

Você pode dar mais detalhes sobre o que significa “muito grande”?

Entendi isso como a necessidade de ter um espaço de reserva no banco de dados três vezes maior, independentemente do tamanho?

1 Curtiu

Desculpas, aquele aviso foi mal formulado e incorreto.

Além do banco de dados existente no disco, você precisará de espaço livre suficiente para a saída do dump e para a nova cópia do banco de dados conforme ele é restaurado. A saída do pg_dump geralmente é menor que o diretório de dados do banco de dados, então 2x o banco de dados atual em espaço livre deve ser suficiente. Vou corrigir isso no script de atualização.