Temos um aplicativo SaaS multilocatário. Estávamos usando um banco de dados compartilhado para todos os nossos locatários com TenantId como chave estrangeira em todas as tabelas. Tudo estava funcionando bem, até que nosso negócio exigia arquitetura de banco de dados (ou esquema) por locatário.
Atualizamos nosso back-end (ASP.NET Core 8) para lidar com essa arquitetura e migramos ambiciosamente todos os nossos locatários para um banco de dados separado em um cluster. Temos cerca de 1.000 bancos de dados no cluster e desde então nossa vida de migração tem sido muito difícil. Onde, com a mesma quantidade de dados e carga, até mesmo r7g.xl
instâncias de 32 GB e 4 CPUs pareciam superprovisionadas, agora até r7g.4xl
instâncias AWS de 16 CPUs e 128 GB às vezes parecem subprovisionadas.
Dos 1.000 bancos de dados, mais da metade não terá mais de 100 MB de dados. Poucos podem ter dados em poucos GB.
Como estávamos usando AWS DMS (sem servidor), a replicação também estava inativa há algum tempo. Então vieram os avisos no vácuo depois de algum tempo:
WARNING: oldest xmin is far in the past
Quando verificamos todos os motivos possíveis, descobrimos que os slots de replicação estão retendo o xmin. Aqui está o que a seguinte consulta retorna:
SELECT c.relnamespace::regnamespace as schema_name, c.relname as table_name,
greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age,
2^31-1000000-greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as remaining
FROM pg_class c LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm') ORDER BY 4;
Resultado:
O valor está aumentando, tentamos excluir os slots de replicação duas vezes, e cada vez isso causou um tempo de inatividade e o cluster não conseguiu se recuperar e tivemos que recorrer à criação de um novo cluster a partir do backup. Então, no momento em que excluímos os slots de replicação inativos, isso acontece:
As consultas de inserção/atualização que, de outra forma, funcionam bem, de repente, logo após a exclusão dos slots de replicação, começam a mostrar bloqueios LW.
Esta é a aparência agora (slots não excluídos):
Passamos a acreditar que é um erro ter mais de 300 bancos de dados por cluster. Portanto, usaremos vários clusters com cerca de 300 bancos de dados por cluster.
Mas o que devemos fazer agora e por que a exclusão dos slots de replicação aciona esses bloqueios?
Os slots de replicação obsoletos impediram que o autovacuum realizasse seu trabalho de manutenção. Como suas tabelas agora contêm linhas descongeladas mais antigas que
autovacuum_freeze_max_age
as transações, o autovacuum está lançando execuções de autovacuum anti-wraparound que parecem consumir recursos suficientes para afetar seu aplicativo.Você pode tentar o seguinte: Defina
autovacuum_freeze_max_age
como 1500000000 evacuum_freeze_table_age
evacuum_freeze_min_age
como 500000000. Em seguida, exclua os slots de replicação obsoletos. As configurações alteradas evitarão que o vácuo automático inicie atividades intensas. Essencialmente, você está ganhando algum tempo. Use esse tempo para manualmenteVACUUM (FREEZE)
todas as tabelas queage(pg_class.relfrozenxid)
excedem 100 milhões. Certifique-se de terminar isso antes de atingir os limites aumentados. Se tiver sucesso,age(pg_database.datfrozenxid)
ficará abaixo de 200 milhões. Quando terminar, redefina os parâmetros para seus valores padrão.Se você não tomar nenhuma atitude, em algum momento seu banco de dados recusará novas transações e você terá que passar um longo período de inatividade nas
VACUUM
tabelas afetadas.