Enorme quantità di transazioni di archiviazione

Ciao,

di tanto in tanto affrontiamo carichi di transazioni enormi sul nostro archivio. Non siamo riusciti a individuare alcun programma o pattern temporale per questo evento, ma si verifica almeno una volta al giorno. Anche la durata varia da 10 minuti a diverse ore.
Durante questi picchi di carico, l’intera installazione si comporta in modo leggermente anomalo; ad esempio, la lettura dei topic non viene rilevata, quindi continuano a essere visualizzati in “Nuovi” e/o “Non letti”.

Sembra che Discourse stia spostando grandi quantità di file. In particolare, le operazioni di READ sono in aumento. Abbiamo già verificato se anche il traffico esterno fosse in aumento, ma non è così. Solo il traffico tra Discourse e l’archivio è interessato.
Abbiamo notato questo comportamento per la prima volta dopo l’aggiornamento da Discourse 2.4.0.beta9 a 2.4.0.beta10, ma non siamo sicuri che non fosse già presente in precedenza. Attualmente stiamo utilizzando la versione 2.5.0.beta4.

La nostra installazione di Discourse è eseguita in un ambiente Azure con un archivio Premium collegato tramite SMBv3, che normalmente funziona molto bene.

Qualcuno può spiegare cosa sta succedendo? Inizialmente abbiamo sospettato il job di sidekiq MigrateUploadScheme, ma se questo job fosse responsabile di queste transazioni, dovremmo osservare carichi così elevati molto più frequentemente di quanto non accada. Inoltre, non abbiamo trovato alcun altro job che possa essere responsabile.


A causa degli “IOPS burst”, si può notare questo picco a circa 800k transazioni/30 minuti. Dopo l’esaurimento di questi crediti, il sistema viene limitato a circa 250k transazioni/30 minuti. Quindi, vi preghiamo di non considerare questo picco, in quanto si tratta semplicemente di un bonus limitato/credito del livello di archiviazione Azure.
Normalmente, abbiamo tra 5k e 40k transazioni ogni 30 minuti.

A questo punto non sappiamo dove cercare e apprezziamo qualsiasi idea o suggerimento.

Cordiali saluti,
Sascha

Hai attivato i backup automatici? Controlla le impostazioni del sito “backup automatici attivati” e “frequenza dei backup”.

Ciao.
No, i backup sono completamente disabilitati. Stiamo utilizzando la funzionalità di retention dei backup della stessa istanza PSQL e (non automatizzati) snapshot di archiviazione.

Puoi abilitare le statistiche in Postgres per individuare query in esecuzione da molto tempo o query ripetute?

È necessario abilitare pg_stat_statements e analizzare le statistiche che genera.

Abilitiamo le statistiche da un po’ di tempo per risolvere alcuni colli di bottiglia. Da lì è nato il mio precedente post Raccomandazioni sulle prestazioni del database (da Azure PSQL).

Ecco le 10 query più lunghe eseguite nella settimana passata:

Se hai bisogno delle query complete, fammelo sapere. Sarebbe interessante capire perché questo influisce sull’utilizzo dello spazio di archiviazione.

Probabilmente la prima query completa, quella è grande con una durata di 1:00 e 14 esecuzioni.

Ciao. La prima query verrà attivata/eseguita tramite DirectoryItem.refresh_period (immagino).

Ecco quindi la query effettiva:

Riepilogo
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 fornire un po’ di contesto per permetterti di valutarla meglio:
Abbiamo circa 430k utenti, 1,6 milioni di argomenti (esclusi quelli cancellati) con 8,4 milioni di post (esclusi quelli cancellati) distribuiti in 241 categorie e 12 milioni di user_actions.

Tuttavia, non riesco ancora a capire perché query lente dovrebbero causare un così elevato numero di operazioni di LETTURA sull’archiviazione (/uploads). Mi sto perdendo qualcosa?

Questo non sembra corretto. Sono confuso: se sei su Azure, come archivi i file? Si tratta di una configurazione con un singolo contenitore? Come sono configurati gli upload?

L’aggiornamento della directory è molto lento. Se non puoi permetterti il costo dell’aggiornamento, potresti disabilitare la directory https://meta.discourse.org/u; abbiamo alcuni piani concreti per aggiungere la ricerca utenti alla ricerca su tutta la pagina, così potrai fare a meno della directory.

Scusate per la confusione. Cercherò di spiegare come abbiamo configurato Discourse.

Innanzitutto, non si tratta di un setup con un singolo container. Abbiamo suddiviso l’architettura per utilizzare i servizi nativi di Azure per Redis, PostgreSQL e l’archiviazione.

Ci sono 3 VM che eseguono Discourse + nginx. Una Azure File Share separata è montata tramite SMBv3 su queste 3 VM e questo punto di mount è collegato ai container di Discourse come volume.
È lì che verranno memorizzati /public/uploads, /tmp/javascript-cache e /tmp/stylesheet-cache.

Inoltre, facciamo uso di Azure Cache for Redis e Azure Database for PostgreSQL.

I dischi delle VM, l’archiviazione e il database sono separati tra loro. Di conseguenza, il carico sul DB non dovrebbe influenzare le prestazioni dell’archiviazione o delle VM e possiamo sfruttare i vantaggi di questi servizi (come le statistiche del database sull’istanza PostgreSQL menzionata sopra e i suggerimenti per le prestazioni).

Questo setup ci permette anche di monitorare ogni servizio o componente singolarmente e abbiamo notato che la nostra Azure File Share, dove risiedono gli uploads, riceve un numero molto elevato di transazioni (come potete vedere nel mio primo messaggio). Queste transazioni sono per lo più operazioni di READ.
Quindi, dato che questa archiviazione (File Share) è utilizzata solo da Discourse, abbiamo cercato di capire quale processo o job sia responsabile di questi eventi, che si verificano 1-2 volte al giorno per diversi minuti fino a diverse ore.

Oltre a questi enormi conteggi di transazioni, questo setup funziona piuttosto bene, tranne per alcune query lente che influenzano le prestazioni solo in pochi casi (ad esempio, una piccola quantità di pagine di riepilogo dell’attività degli utenti può richiedere fino a 15 secondi per il caricamento).

Spero di aver chiarito perché mi chiedevo come le prestazioni del DB possano avere un effetto sui conteggi delle transazioni dei file statici.

Cordiali saluti e grazie per gli sforzi finora
Sascha

P.S.
Stiamo utilizzando un’immagine Docker personalizzata nel nostro setup e comprendo perfettamente che non potete/offrirete supporto per soluzioni personalizzate.
L’unica cosa che vorremmo sapere è quale processo/job/impostazione potrebbe causare questi conteggi di transazioni di archiviazione che in parte rallentano l’intero setup e cosa possiamo fare per evitarlo.

Credo che la soluzione migliore per le prestazioni sia passare a un archiviazione su S3 o a un motore di archiviazione compatibile con S3 + CDN. L’uso di una condivisione SMB per i caricamenti non è stato mai testato da noi; ipotizzo che stiamo verificando le dimensioni dei caricamenti ogni giorno, operazione che è velocissima in locale ma molto lenta su SMB.

Grazie per le chiarificazioni e i consigli. Effettivamente, SMB può essere molto lento quando si tratta di accedere a molti file. Nella maggior parte dei casi non fa differenza, poiché i file più frequentemente accessibili vengono memorizzati nella cache da nginx (appliciamo regolarmente le modifiche apportate alla configurazione di esempio di nginx per Discourse).
Tuttavia, quando si tratta di queste letture, le prestazioni diminuiscono.

Stiamo cercando altre soluzioni di archiviazione da qualche tempo. Utilizzare un archivio esterno S3 (compatibile) potrebbe compromettere parti del nostro concetto di sicurezza. Ogni istanza/servizio coinvolto (database, VM, archiviazione, …) è vincolato a una rete privata e non accessibile da Internet pubblico. Tutto il traffico pubblico è gestito da un Azure Application Gateway.
Purtroppo, Azure Blob Storage non è compatibile con S3, ma dovremmo forse investire del tempo per utilizzarlo.
Le soluzioni possibili attualmente sono il plugin di archiviazione Blob di Discourse o l’uso diretto di blobfuse all’interno del contenitore.

Comunque, grazie per il tuo tempo e il tuo aiuto. C’è un motivo per cui la dimensione dei caricamenti viene verificata quotidianamente e c’è un modo per disattivarlo?

Cordiali saluti

Questo probabilmente deriva da qui:

Immagino tu possa disabilitare il recupero delle immagini collegate esternamente o creare una patch monkey in un plugin che disattivi questa funzionalità:

In alternativa, puoi semplicemente aliasare du nel tuo container per renderlo un’operazione vuota modificando la configurazione del container.

Grazie mille, questo ci aiuterà molto. du risulterebbe molto costoso utilizzando una condivisione SMB, considerando che ospitiamo circa 800.000 file (38 GB) su questa condivisione di file.

Abbiamo già disabilitato pulling_hotlinked_images a causa di potenziali problemi legali o di copyright.

Credo che aliasare du sia un po’ troppo invasivo, anche se è un’ottima idea correggerlo tramite un plugin. Possiamo semplicemente applicare un git-patch durante la costruzione dell’immagine con qualcosa del genere:

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

Dato che du potrebbe essere più affidabile e accurato, penso che df possa soddisfare le nostre esigenze senza compromettere altre funzionalità.