Grande volume de transações de armazenamento

Olá,

Estamos enfrentando cargas enormes de transações em nosso armazenamento de vez em quando. Não conseguimos encontrar nenhum cronograma ou padrão de tempo para esse evento, mas ele ocorre pelo menos uma vez por dia. Até mesmo a duração varia de 10 minutos a várias horas.
Durante essas cargas, toda a nossa instalação se comporta de forma um pouco estranha; por exemplo, a leitura de tópicos não é reconhecida, então eles continuam aparecendo em “Novos” e/ou “Não lidos”.

Parece que o Discourse está movendo grandes quantidades de arquivos. Especialmente as operações de LEITURA estão aumentando. Já verificamos se o tráfego externo também está aumentando, mas não está. Apenas o tráfego entre o Discourse e o armazenamento é afetado.
Detectamos esse comportamento pela primeira vez após a atualização da versão 2.4.0.beta9 para a 2.4.0.beta10 do Discourse, mas não temos certeza se já ocorreu antes. Atualmente, estamos executando a versão 2.5.0.beta4.

Nossa instalação do Discourse está rodando em um ambiente Azure com um armazenamento Premium anexado via SMBv3, que normalmente funciona muito bem.

Alguém pode explicar o que está acontecendo? Inicialmente, suspeitamos do job do Sidekiq MigrateUploadScheme, mas se esse job fosse responsável por essas transações, deveríamos ver essas cargas altas com muito mais frequência do que vemos. Além disso, não encontramos nenhum outro job que pudesse ser responsável.


Devido aos “IOPS de pico” (burst IOPS), você pode ver esse pico de aproximadamente 800 mil transações/30min. Após o uso desses créditos, a taxa é reduzida para cerca de 250 mil transações/30min. Portanto, por favor, não se preocupe com esse pico, pois é apenas um bônus limitado/crédito do nível de armazenamento do Azure.
Normalmente, temos entre 5 mil e 40 mil transações a cada 30 minutos.

Neste momento, não sabemos onde procurar e qualquer ideia ou dica é bem-vinda.

Atenciosamente,
Sascha

Você tem backups automáticos ativados? Verifique as configurações do site backups automáticos ativados e frequência de backup.

Olá.
Não, os backups estão completamente desativados. Estamos utilizando a retenção de backups da própria instância do PSQL e instantâneos de armazenamento (não automatizados).

Você pode habilitar estatísticas no PostgreSQL, procurando por consultas de longa execução ou consultas repetidas?

Você precisa habilitar o pg_stat_statements e analisar as estatísticas que ele gera.

Habilitamos as estatísticas há algum tempo para resolver alguns gargalos. Foi de lá que surgiu meu post anterior Recomendações de desempenho do banco de dados (por Azure PSQL).

Aqui estão as 10 principais consultas de longa duração da semana passada:

Se precisar das consultas completas, por favor, me avise. Também seria interessante entender por que isso afeta o uso de armazenamento.

Provavelmente a primeira consulta completa com certeza, essa é grande com duração de 1:00 e 14 execuções.

Olá. A primeira consulta será acionada/executada via DirectoryItem.refresh_period (acho eu).

Então, aqui está a consulta real:

Resumo
WITH x AS (SELECT
			u.id user_id,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 2 THEN 1 ELSE 0 END) likes_received,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 1 THEN 1 ELSE 0 END) likes_given,
			COALESCE((SELECT COUNT(topic_id) FROM topic_views AS v WHERE v.user_id = u.id AND v.viewed_at > '2019-10-28 23:52:24.911261'), 0) topics_entered,
			COALESCE((SELECT COUNT(id) FROM user_visits AS uv WHERE uv.user_id = u.id AND uv.visited_at > '2019-10-28 23:52:24.911261'), 0) days_visited,
			COALESCE((SELECT SUM(posts_read) FROM user_visits AS uv2 WHERE uv2.user_id = u.id AND uv2.visited_at > '2019-10-28 23:52:24.911261'), 0) posts_read,
			SUM(CASE WHEN t2.id IS NOT NULL AND ua.action_type = 4 THEN 1 ELSE 0 END) topic_count,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 5 THEN 1 ELSE 0 END) post_count
			FROM users AS u
			LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id AND COALESCE(ua.created_at, '2019-10-28 23:52:24.911261') > '2019-10-28 23:52:24.911261'
			LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id AND p.deleted_at IS NULL AND p.post_type = 1 AND NOT p.hidden
			LEFT OUTER JOIN topics AS t ON p.topic_id = t.id AND t.archetype = 'regular' AND t.deleted_at IS NULL AND t.visible
			LEFT OUTER JOIN topics AS t2 ON t2.id = ua.target_topic_id AND t2.archetype = 'regular' AND t2.deleted_at IS NULL AND t2.visible
			LEFT OUTER JOIN categories AS c ON t.category_id = c.id
			WHERE u.active
			AND u.silenced_till IS NULL
			AND u.id > 0
			GROUP BY u.id)
	UPDATE directory_items di SET
		 likes_received = x.likes_received,
		 likes_given = x.likes_given,
		 topics_entered = x.topics_entered,
		 days_visited = x.days_visited,
		 posts_read = x.posts_read,
		 topic_count = x.topic_count,
		 post_count = x.post_count
	FROM x
	WHERE
	x.user_id = di.user_id AND
	di.period_type = 5 AND (
	di.likes_received <> x.likes_received OR
	di.likes_given <> x.likes_given OR
	di.topics_entered <> x.topics_entered OR
	di.days_visited <> x.days_visited OR
	di.posts_read <> x.posts_read OR
	di.topic_count <> x.topic_count OR
	di.post_count <> x.post_count )

Posso fornecer algum contexto para que você possa avaliá-lo melhor:
Temos ~430k usuários, 1,6mi de tópicos (sem os excluídos) com 8,4mi de posts (sem os excluídos) em 241 categorias e 12mi de user_actions.

Mas ainda não entendo por que consultas lentas deveriam causar essa alta quantidade de operações de LEITURA no armazenamento (/uploads). Será que estou esquecendo algo?

Isso não parece correto. Estou confuso: se você está no Azure, como está armazenando os arquivos? É uma configuração de único container? Como os uploads estão configurados?

A atualização do diretório está muito lenta. Se você não pode arcar com o custo de atualizá-lo, pode desabilitar o diretório https://meta.discourse.org/u. Temos planos concretos para adicionar a busca de usuários à busca em página inteira, para que você possa funcionar sem o diretório.

Desculpe pela confusão. Vou tentar explicar como configuramos o Discourse.

Primeiramente, não se trata de uma configuração com um único contêiner. Dividimos a infraestrutura para utilizar os próprios serviços do Azure para Redis, PostgreSQL e armazenamento.

Existem 3 VMs executando o Discourse + Nginx. Um Azure File Share separado é montado via SMBv3 nessas 3 VMs, e esse ponto de montagem é anexado aos contêineres do Discourse como um volume.
É ali que /public/uploads, /tmp/javascript-cache e /tmp/stylesheet-cache serão armazenados.

Além disso, utilizamos o Azure Cache for Redis e o Azure Database for PostgreSQL.

Os discos das VMs, o armazenamento e o banco de dados estão separados uns dos outros. Portanto, a carga do banco de dados não deve (e não deve) afetar o desempenho do armazenamento ou das VMs, e podemos aproveitar os benefícios desses serviços (como estatísticas do banco de dados na instância do PostgreSQL mencionada acima e recomendações de desempenho).

Essa configuração também nos permite monitorar cada serviço/parte individualmente, e observamos que nosso Azure File Share, onde os uploads estão localizados, recebe uma quantidade muito alta de transações (como você pode ver em meu primeiro post). Essas transações são principalmente operações de LEITURA.
Como esse armazenamento (File Share) é usado apenas pelo próprio Discourse, tentamos descobrir qual processo/tarefa é responsável por esses eventos, que ocorrem 1 a 2 vezes ao dia por vários minutos até várias horas.

Além desses altos números de transações, essa configuração funciona muito bem, exceto por algumas consultas lentas que afetam o desempenho apenas em alguns casos (por exemplo, uma pequena quantidade de páginas de resumo de atividade de usuários pode levar até 15 segundos para carregar).

Espero ter conseguido explicar por que fiquei em dúvida sobre como o desempenho do banco de dados poderia afetar as contagens de transações de arquivos estáticos.

Atenciosamente e obrigado pelos seus esforços até agora,
Sascha

P.S.
Estamos usando uma imagem Docker personalizada em nossa configuração e entendo perfeitamente que você não pode/não oferecerá suporte para soluções personalizadas.
A única coisa que gostaríamos de saber é qual processo/tarefa/configuração poderia causar essas contagens de transações de armazenamento que, em parte, desaceleram toda a configuração e o que podemos fazer para evitá-las.

Acho que sua melhor opção em termos de desempenho é migrar o armazenamento de uploads para o S3 ou um motor de armazenamento compatível com S3 + CDN. Usar uma compartilhamento SMB para uploads não é algo que já testamos. Minha suposição é que estamos verificando o tamanho dos uploads diariamente, o que é extremamente rápido no ambiente local e muito lento no SMB.

Obrigado pela esclarecimento e pelo seu conselho. De fato, o SMB pode ser muito lento ao acessar muitos arquivos. Na maioria das vezes, não faz diferença, pois os arquivos frequentemente acessados são armazenados em cache pelo nginx (aplicamos frequentemente as alterações feitas na configuração de exemplo do nginx do Discourse).
Mas, quando se trata desses acessos esporádicos, o desempenho cai.

Estamos buscando outras soluções de armazenamento há algum tempo. Usar um armazenamento externo compatível com o S3 poderia pode quebrar partes do nosso conceito de segurança. Cada instância/serviço envolvido (banco de dados, VM, armazenamento, …) está vinculado a uma rede privada e inacessível pela internet pública. Todo o tráfego público é gerenciado por um Azure Application Gateway.
Infelizmente, o Azure Blob Storage não é compatível com o S3, mas talvez devêssemos investir algum tempo para utilizá-lo.
As soluções possíveis atualmente são o plugin de armazenamento em blob do Discourse ou usar o blobfuse diretamente dentro do contêiner.

De qualquer forma. Obrigado pelo seu tempo e ajuda. Há algum motivo para que o tamanho do upload seja verificado diariamente e há alguma maneira de desativar isso?

Cordiais saudações

Isso provavelmente vem daqui:

Acho que você pode desativar a busca de imagens com hotlink ou criar um monkey patch em um plugin que desative isso:

Ou basta fazer um alias para du no seu container para que ele seja um no-op, modificando a configuração do seu container.

Muito obrigado, isso vai ajudar bastante. O du será muito caro usando uma share SMB, já que estamos hospedando cerca de 800 mil arquivos (38 GB) nessa share de arquivos.

Já desativamos o pulling_hotlinked_images devido a possíveis questões legais/de direitos autorais.

Acho que fazer um alias do du é um pouco invasivo, embora seja uma boa ideia corrigir isso usando um plugin. Podemos simplesmente aplicar um git-patch ao construir a imagem, com algo como:

def self.used(path)
    output = Discourse::Utils.execute_command('df', '-Pk', path)
    size_line = output.split("\n")[1]
    size_line.split(/\s+/)[2].to_i * 1024
end

Como o du pode ser mais confiável/preciso, acho que o df deve atender às nossas necessidades e não deve quebrar nenhuma outra funcionalidade.