Ripristino in fallimento: possibile problema con Data Explorer

Ho un forum funzionante e vorrei vedere alcuni elementi che si sono rovinati qualche giorno fa. Sono su AWS, quindi creo un’immagine AMI del forum funzionante, avvio una nuova istanza e provo a ripristinare un backup di qualche giorno fa. L’operazione fallisce con i messaggi riportati di seguito.

Non può trattarsi di un’incompatibilità di versione o schema, dato che il server è stato creato partendo da un’immagine fresca del forum funzionante.

Ho provato a ricostruire.

Ho provato a ripristinare da un backup diverso di un giorno fa: stesso risultato.

L’unica cosa strana che ho fatto è aver eliminato i file PDF dalla directory di caricamento (…/uploads/original/1X/*.pdf) per liberare spazio. Riproverò senza quel passaggio, ma sembra improbabile che sia la causa del problema.

> [2019-11-30 01:17:44] 'admin' ha iniziato il ripristino!
> [2019-11-30 01:17:44] Impostazione dello stato del ripristino in esecuzione...
> [2019-11-30 01:17:44] Verifica dell'esistenza di /var/www/discourse/tmp/restores/default/2019-11-30-011744...
> [2019-11-30 01:17:44] Download dell'archivio nella directory tmp...
> [2019-11-30 01:23:24] Decompressione dell'archivio, ciò potrebbe richiedere del tempo...
> [2019-11-30 01:27:52] Nessun file di metadati da estrarre.
> [2019-11-30 01:27:52] Validazione dei metadati...
> [2019-11-30 01:27:52]   Versione corrente: 20191129144706
> [2019-11-30 01:27:52]   Versione da ripristinare: 20191120015344
> [2019-11-30 01:27:52] Estrazione del file dump...
> [2019-11-30 01:50:57] comando non valido \N
> [2019-11-30 01:50:57] comando non valido \N
> 
> 
> < ripetuto circa 100 volte >
> 
> [2019-11-30 01:51:07] comando non valido \N
> [2019-11-30 01:54:13] comando non valido \N
> [2019-11-30 01:54:13] ECCEZIONE: psql fallito
> [2019-11-30 01:54:14] /var/www/discourse/lib/backup_restore/restorer.rb:331:in `restore_dump'
> /var/www/discourse/lib/backup_restore/restorer.rb:75:in `run'
> /var/www/discourse/lib/backup_restore.rb:166:in `block in start!'
> /var/www/discourse/lib/backup_restore.rb:163:in `fork'
> /var/www/discourse/lib/backup_restore.rb:163:in `start!'
> /var/www/discourse/lib/backup_restore.rb:22:in `restore!'
> /var/www/discourse/app/controllers/admin/backups_controller.rb:119:in `restore'
> etc...

Tuttavia, l’errore invalid command \N è tipico di una discrepanza di versione di Postgres…

root@example:/var/www/discourse# psql --version
psql (PostgreSQL) 10.10 (Debian 10.10-1.pgdg100+1)

È la stessa versione del nuovo server e del forum funzionante.

Volevo associare quegli errori alla corrispondenza della versione di PostgreSQL, ma ho visto quegli errori \N l’altro giorno su un sistema che aveva esaurito lo spazio su disco (stavo ripristinando sullo stesso sistema che aveva creato il backup). Non ho completato la diagnosi del problema (era un altro problema bizzarro che stavo affrontando e il ripristino di un backup su un altro server ha risolto il problema; mi sono chiesto se ripristinarlo sullo stesso server avrebbe risolto il problema).

Hai menzionato di avere poco spazio. Sospetto che sia questo il problema. Il ripristino utilizza molto spazio mentre scompatta il backup e quindi ha due copie complete dello stesso, più lo spazio necessario per il ripristino e per poter tornare indietro in caso di fallimento.

Quindi ci vogliono 23 minuti prima che fallisca?

Peggiora, ma forse ci si avvicina al vero problema… Sull’ipotesi che avessi bisogno di più spazio su disco, ho creato una nuova istanza dalla mia immagine, questa volta con 100 GB, rispetto ai 50 GB precedenti. (I backup sono da 5 GB ciascuno e vengono archiviati su S3.) Questa volta ho ricevuto un errore esplicito: “No space left on device”. Eppure df mostra un sacco di spazio.

> [2019-11-29 22:42:58] Assicurazione che /var/www/discourse/tmp/restores/default/2019-11-29-224258 esista...
> [2019-11-29 22:42:58] Download dell'archivio nella directory tmp...
> [2019-11-29 22:45:46] Decompressione dell'archivio, potrebbe richiedere del tempo...
> [2019-11-29 22:51:46] Nessun file di metadati da estrarre.
> [2019-11-29 22:51:46] Validazione dei metadati...
> [2019-11-29 22:51:46]   Versione corrente: 20191129144706
> [2019-11-29 22:51:46]   Versione ripristinata: 20191108000414
> [2019-11-29 22:51:46] Estrazione del file dump...
> [2019-11-29 22:53:47] ECCEZIONE: No space left on device @ io_write - /shared/tmp/restores/default/2019-11-29-224258/dump.sql

> [ec2-user@ip-172-31-47-237 discourse]$ df / -h
> Filesystem      Size  Used Avail Use% Mounted on
> /dev/xvda1       99G   28G   71G  28% /

È interessante notare che non c’è nulla nella directory di riferimento:

> /var/www/discourse# ls /shared/tmp/*
> /shared/tmp/backups:
> < vuoto >
> /shared/tmp/restores:
> < vuoto >

Potrebbe essere un problema legato al file di swap? L’istanza EC2 è una t2.small con 2 GB di memoria, quindi molto tempo fa ho creato un file di swap sul forum funzionante. Presumo che il file di swap venga replicato anche sulla nuova istanza. Non sono un esperto, ma credo che il file di swap esista, perché non mi ha permesso di crearne uno nuovo e perché:

> /var/www/discourse# swapon -s
> Filename                                Type            Size    Used    Priority
> /swapfile                               file            2097148 1024    -2

Potrebbe essere un problema di inode. Cosa ti dice df -i?

df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
devtmpfs 252562 437 252125 1% /dev
tmpfs 255203 1 255202 1% /dev/shm
/dev/xvda1 6553600 737194 5816406 12% /

Sto uscendo dalla mia zona di competenza, ma immagino che non sia un problema?

No, va bene.

‘L’archiviazione è piena’ non si verifica solo quando il dispositivo esaurisce i gigabyte, ma anche quando il filesystem esaurisce gli inodi. Tuttavia, è chiaro che non si tratta di questo problema. (In tal caso, iUse% sarebbe al 100%).

Ancora nessun risultato. Pensavo di provare a ripristinare su una nuova istanza Lightsail, invece di lanciare un’AMI della mia istanza EC2 funzionante. Fallisce ancora, ma i messaggi sono leggermente diversi.

Sia l’istanza vecchia che quella nuova sono aggiornate, entrambe sono installazioni Docker standard e entrambe eseguono la stessa versione di PostgreSQL:

psql --version
psql (PostgreSQL) 10.10 (Debian 10.10-1.pgdg100+1)

È normale questo:

Creazione delle funzioni mancanti nello schema discourse_functions
Impossibile ripristinare in uno schema diverso, ripristino in loco

Potrebbe essere correlato ai plugin? Ho diversi plugin, sia supportati che personalizzati, installati sul sito “sorgente”. Alcuni utilizzano campi utente personalizzati. Ho provato a ripristinare su siti “destinazione” puliti, sia con che senza plugin.

Qualche indicazione su come iniziare a confrontare gli schemi?

> [2019-12-07 04:51:36] 'admin' ha avviato il ripristino!
> [2019-12-07 04:51:36] Impostazione dello stato del ripristino su in corso...
> [2019-12-07 04:51:36] Verifica dell'esistenza di /var/www/discourse/tmp/restores/default/2019-12-07-045136...
> [2019-12-07 04:51:36] Download dell'archivio nella directory tmp...
> [2019-12-07 04:53:49] Decompressione dell'archivio, potrebbe richiedere del tempo...
> [2019-12-07 04:57:12] Nessun file di metadati da estrarre.
> [2019-12-07 04:57:12] Validazione dei metadati...
> [2019-12-07 04:57:12]   Versione corrente: 20191129144706
> [2019-12-07 04:57:12]   Versione ripristinata: 20191120015344
> [2019-12-07 04:57:12] Estrazione del file dump...
> [2019-12-07 04:59:10] Creazione delle funzioni mancanti nello schema discourse_functions
> [2019-12-07 04:59:11] Impossibile ripristinare in uno schema diverso, ripristino in loco
> [2019-12-07 05:05:02] ERRORE: la transazione corrente è abortita, i comandi verranno ignorati fino alla fine del blocco di transazione
> [2019-12-07 05:05:03] ERRORE: la transazione corrente è abortita, i comandi verranno ignorati fino alla fine del blocco di transazione
> < si ripete circa 100 volte >
> [2019-12-07 05:05:03] ERRORE: la transazione corrente è abortita, i comandi verranno ignorati fino alla fine del blocco di transazione
> [2019-12-07 05:05:03] ECCEZIONE: psql non riuscito
> [2019-12-07 05:05:03] /var/www/discourse/lib/backup_restore/restorer.rb:331:in `restore_dump'
> /var/www/discourse/lib/backup_restore/restorer.rb:75:in `run'
> /var/www/discourse/lib/backup_restore.rb:166:in `block in start!'
> /var/www/discourse/lib/backup_restore.rb:163:in `fork'
> /var/www/discourse/lib/backup_restore.rb:163:in `start!'
> /var/www/discourse/lib/backup_restore.rb:22:in `restore!'
> /var/www/discourse/app/controllers/admin/backups_controller.rb:119:in `restore'
> < resto dello stack trace >

Sì, è normale.

Chiaramente c’è qualcosa che non va all’interno di PostgreSQL. Hai controllato i suoi log?

Scommessa azzardata: potrebbe essere legato alla memoria? Puoi provare a monitorare l’output di free -m durante il ripristino e verificare se la memoria (virtuale) si esaurisce.

So che è una domanda difficile, dato che non sappiamo qual è il problema, ma in generale dovrei installare i plugin sul sito di destinazione prima di provare a ripristinare? Oppure il ripristino scarica e configura automaticamente i plugin?

Sì, dovresti: il ripristino non lo farà per te.

D’altra parte, non credo che questo sia il tuo problema, dato che il ripristino si occuperà della corretta struttura del database (inclusi gli elementi specifici dei plugin).

Ho creato una nuova istanza Lightsail da 20 $ con 4 GB di memoria. Ho osservato ‘free -m’ durante il ripristino. C’era sempre molta memoria libera e disponibile.

Gli errori specifici variano a seconda che i plugin siano installati o meno, ma probabilmente sono dovuti alla stessa causa radice. In questo caso non ho installato i plugin prima del backup. Ci sono due categorie di errori:

  1. Nei log di postgres, ricevo molti di questi errori, a volte al carattere 34 e a volte al carattere 41.

discourse@discourse ERROR: la relazione “user_auth_tokens” non esiste al carattere 34

Questi non hanno un output corrispondente nella pagina admin > backup > log, e il ripristino continua per diversi minuti nonostante questi errori.

  1. Il secondo errore dipende dal fatto che i plugin siano installati. In questo caso non li ho installati, quindi ricevo un errore relativo a Data Explorer, ed è lì che tutto va storto.

In admin > backup > log:

[2019-12-07 07:38:34] CREATE INDEX
[2019-12-07 07:38:34] CREATE INDEX
[2019-12-07 07:38:34] ERROR: impossibile creare l’indice univoco “index_plugin_store_rows_on_plugin_name_and_key”
[2019-12-07 07:38:34] DETAIL: Chiave (plugin_name, key)=(discourse-data-explorer, q:-6) duplicata.
[2019-12-07 07:38:34] ERROR: la transazione corrente è abortita, i comandi vengono ignorati fino alla fine del blocco di transazione
[2019-12-07 07:38:34] ERROR: la transazione corrente è abortita, i comandi vengono ignorati fino alla fine del blocco di transazione
< si ripete 1000 volte e termina >

E l’output corrispondente nel log di postgres:

2019-12-07 07:38:34.718 UTC [8991] discourse@discourse LOG: durata: 165.427 ms statement: CREATE INDEX index_notifications_on_user_
id_and_topic_id_and_post_number ON public.notifications USING btree (user_id, topic_id, post_number);
2019-12-07 07:38:34.767 UTC [8991] discourse@discourse ERROR: impossibile creare l’indice univoco “index_plugin_store_rows_on_plugin_name_an
d_key”
2019-12-07 07:38:34.767 UTC [8991] discourse@discourse DETAIL: Chiave (plugin_name, key)=(discourse-data-explorer, q:-6) duplicata.
2019-12-07 07:38:34.767 UTC [8991] discourse@discourse STATEMENT: CREATE UNIQUE INDEX index_plugin_store_rows_on_plugin_name_and_key O
N public.plugin_store_rows USING btree (plugin_name, key);
2019-12-07 07:38:34.984 UTC [8991] discourse@discourse ERROR: la transazione corrente è abortita, i comandi vengono ignorati fino alla fine del blocco di transazione
2019-12-07 07:38:34.984 UTC [8991] discourse@discourse STATEMENT: CREATE INDEX index_policy_users_on_post_policy_id_and_user_id ON pub
lic.policy_users USING btree (post_policy_id, user_id);

Penso che il problema #1 non sia critico e sia solo un effetto collaterale del ripristino in-place.

Potresti valutare di (esportare e) eliminare tutte le query dell’esploratore di dati e rimuovere il plugin dell’esploratore di dati prima di creare il backup.

In alternativa, puoi pubblicare il contenuto rilevante della tabella plugin_store_rows?

Infatti ci sono query duplicate con coppie duplicate (plugin_name, key), ad esempio q:-11 e q:-2, ma con ID univoci. Non vedo alcun pattern tra i duplicati, come se non fossero le mie query preferite o altro.

Quindi il mio prossimo passo sarà rimuovere i duplicati, creare un backup e provare a ripristinare da quello.

SELECT id, plugin_name, key from plugin_store_rows
WHERE plugin_name = ‘discourse-data-explorer’
ORDER BY key

id plugin_name key
1138 discourse-data-explorer q:-1
1136 discourse-data-explorer q:-10
813 discourse-data-explorer q:10
1142 discourse-data-explorer q:-11
1397 discourse-data-explorer q:-11
825 discourse-data-explorer q:11
889 discourse-data-explorer q:13
1004 discourse-data-explorer q:14
1005 discourse-data-explorer q:15
1043 discourse-data-explorer q:17
1044 discourse-data-explorer q:18
514 discourse-data-explorer q:-2
1249 discourse-data-explorer q:-2
764 discourse-data-explorer q:2
1053 discourse-data-explorer q:21
1066 discourse-data-explorer q:22
1082 discourse-data-explorer q:23
1097 discourse-data-explorer q:24
1131 discourse-data-explorer q:26
1132 discourse-data-explorer q:27
1134 discourse-data-explorer q:28
1135 discourse-data-explorer q:29
775 discourse-data-explorer q:3
1137 discourse-data-explorer q:30
1140 discourse-data-explorer q:31
1141 discourse-data-explorer q:32
1143 discourse-data-explorer q:33
1149 discourse-data-explorer q:34
1155 discourse-data-explorer q:35
1156 discourse-data-explorer q:36
1157 discourse-data-explorer q:37
1158 discourse-data-explorer q:38
1161 discourse-data-explorer q:39
513 discourse-data-explorer q:-4
777 discourse-data-explorer q:4
1211 discourse-data-explorer q:40
1215 discourse-data-explorer q:41
1223 discourse-data-explorer q:42
1224 discourse-data-explorer q:43
1225 discourse-data-explorer q:44
1226 discourse-data-explorer q:45
1269 discourse-data-explorer q:46
1272 discourse-data-explorer q:47
1273 discourse-data-explorer q:48
1274 discourse-data-explorer q:49
1279 discourse-data-explorer q:50
1281 discourse-data-explorer q:51
1282 discourse-data-explorer q:52
1301 discourse-data-explorer q:53
1349 discourse-data-explorer q:54
1369 discourse-data-explorer q:55
1373 discourse-data-explorer q:56
1384 discourse-data-explorer q:57
1387 discourse-data-explorer q:58
1396 discourse-data-explorer q:59
1222 discourse-data-explorer q:-6
1348 discourse-data-explorer q:-6
781 discourse-data-explorer q:6
763 discourse-data-explorer q:-7
782 discourse-data-explorer q:7
515 discourse-data-explorer q:-8
791 discourse-data-explorer q:8
1139 discourse-data-explorer q:-9
798 discourse-data-explorer q:9
507 discourse-data-explorer q:_id

In realtà, come posso eliminare i duplicati? Tutti e tre sono di proprietà di “system”, quindi non posso modificarli o eliminarli.

Ho trovato il modello. Quando eseguo una query di proprietà del sistema, viene creato un duplicato, che evidentemente interrompe il ripristino.

Non riesco a riprodurlo su un sito di test pulito, ma si verifica costantemente sul mio sito di produzione. Ho installato tutti i plugin di produzione sul sito di test, ma non riesco comunque a riprodurlo.

  1. Come posso individuare cosa non va nel mio sito di produzione?

  2. Come posso eliminare le query duplicate, dato che sono gestite dal sistema? Devo usare sudo -u postgres psql discourse...? Sembra spaventoso.

Per rendere il backup ripristinabile, puoi probabilmente eliminare le righe duplicate dal file SQL di backup.

È possibile che il database di sviluppo non abbia quell’indice per qualche motivo?