Ottimizzazione della velocità di migrazione da PHPBB a Discourse

Ehi, sono con phpBB dal 2004, quindi sto trasferendo un forum di dimensioni considerevoli. Al momento sono a due giorni di lavoro: 303139/2167314 (14%), 446 al minuto. Come posso accelerare il processo? Sono su DigitalOcean e uso solo il 4% della CPU. Redis continua a scadere il timeout. Ho disattivato gli allegati.

Alcuni dettagli utili aiuterebbero a restringere il campo:

  • Dimensione del Droplet: RAM, numero di vCPU, tipo/dimensione del disco
  • Il comando di importazione esatto che stai eseguendo
  • Le impostazioni relative alle risorse del tuo app.yml, con i segreti rimossi, in particolare:
    • UNICORN_WORKERS
    • db_shared_buffers
    • db_work_mem
  • Se l’importazione viene eseguita all’interno del container Docker standard di Discourse
  • Eventuali messaggi di timeout di Redis o estratti dei log
  • Se il database è locale nello stesso container o esterno

Una cosa da notare: UNICORN_WORKERS probabilmente non accelererà molto l’importazione, poiché l’importatore phpBB non è servito principalmente tramite i worker web. Aumentarlo potrebbe semplicemente consumare più RAM. Le impostazioni di memoria di PostgreSQL e l’I/O del disco sono più probabili fattori determinanti.

Poiché l’utilizzo della CPU è solo intorno al 4%, il problema potrebbe essere legato all’I/O, al database o all’attesa di Redis, piuttosto che a una carenza di CPU. Vale la pena indagare separatamente eventuali timeout di Redis.

image

Il mio log aggiornato
script/import_scripts/phpbb3.rb:15:in ‘’
302570 / 2167314 ( 14.0%) [448 elementi/min] Eccezione durante la creazione del post 304683. Salto.
Attesa di 1,0 secondi
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:214:in ‘block in RedisClient::RubyConnection::BufferedIO#fill_buffer’
internal:kernel:168:in ‘Kernel#loop’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:197:in ‘RedisClient::RubyConnection::BufferedIO#fill_buffer’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:187:in ‘RedisClient::RubyConnection::BufferedIO#ensure_remaining’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:152:in ‘RedisClient::RubyConnection::BufferedIO#getbyte’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/resp3.rb:113:in ‘RedisClient::RESP3.parse’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/resp3.rb:50:in ‘RedisClient::RESP3.load’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection.rb:97:in ‘RedisClient::RubyConnection#read’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/connection_mixin.rb:37:in ‘RedisClient::ConnectionMixin#call’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:374:in ‘block (2 levels) in RedisClient#call_v’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/middlewares.rb:16:in ‘RedisClient::BasicMiddleware#call’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:373:in ‘block in RedisClient#call_v’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:781:in ‘RedisClient#ensure_connected’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:372:in ‘RedisClient#call_v’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis/client.rb:90:in ‘Redis::Client#call_v’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/mini_profiler/profiling_methods.rb:90:in ‘block in Redis::Client#profile_method’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:152:in ‘block in Redis#send_command’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:151:in ‘Monitor#synchronize’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:151:in ‘Redis#send_command’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis/commands/scripting.rb:110:in ‘Redis::Commands::Scripting#_eval’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis/commands/scripting.rb:97:in ‘Redis::Commands::Scripting#evalsha’
/var/www/discourse/lib/discourse_redis.rb:38:in ‘Kernel#public_send’
/var/www/discourse/lib/discourse_redis.rb:38:in ‘block in DiscourseRedis#method_missing’
/var/www/discourse/lib/discourse_redis.rb:29:in ‘DiscourseRedis.ignore_readonly’
/var/www/discourse/lib/discourse_redis.rb:38:in ‘DiscourseRedis#method_missing’
/var/www/discourse/lib/discourse_redis.rb:270:in ‘DiscourseRedis::EvalHelper#eval’
/var/www/discourse/lib/distributed_mutex.rb:82:in ‘DistributedMutex#get_lock’
/var/www/discourse/lib/distributed_mutex.rb:50:in ‘block in DistributedMutex#synchronize’
/var/www/discourse/lib/distributed_mutex.rb:49:in ‘Thread::Mutex#synchronize’
/var/www/discourse/lib/distributed_mutex.rb:49:in ‘DistributedMutex#synchronize’
/var/www/discourse/lib/distributed_mutex.rb:34:in ‘DistributedMutex.synchronize’
/var/www/discourse/lib/post_creator.rb:410:in ‘PostCreator#transaction’
/var/www/discourse/lib/post_creator.rb:200:in ‘PostCreator#create’
/var/www/discourse/script/import_scripts/base.rb:611:in ‘ImportScripts::Base#create_post’
/var/www/discourse/script/import_scripts/base.rb:555:in ‘block in ImportScripts::Base#create_posts’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/mysql2/alias_method.rb:8:in ‘Mysql2::Result#each’
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/mysql2/alias_method.rb:8:in ‘Mysql2::Result#each’
/var/www/discourse/script/import_scripts/base.rb:542:in ‘ImportScripts::Base#create_posts’
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:212:in ‘block in ImportScripts::PhpBB3::Importer#import_posts’
/var/www/discourse/script/import_scripts/base.rb:943:in ‘block in ImportScripts::Base#batches’
internal:kernel:168:in ‘Kernel#loop’
/var/www/discourse/script/import_scripts/base.rb:942:in ‘ImportScripts::Base#batches’
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:293:in ‘ImportScripts::PhpBB3::Importer#batches’
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:208:in ‘ImportScripts::PhpBB3::Importer#import_posts’
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:38:in ‘ImportScripts::PhpBB3::Importer#execute’
/var/www/discourse/script/import_scripts/base.rb:47:in ‘ImportScripts::Base#perform’
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:22:in ‘ImportScripts::PhpBB3::Importer#perform’
script/import_scripts/phpbb3.rb:35:in ‘module:PhpBB3
script/import_scripts/phpbb3.rb:16:in ‘module:ImportScripts
script/import_scripts/phpbb3.rb:15:in ‘’
333919 / 2167314 ( 15.4%) [441 elementi/min]

Sembra funzionare, per ora non ci sono lamentele.

Ho fermato Unicorn.

Ho disabilitato gli allegati e gli avatar.

Quella dimensione del droplet sembra ragionevolmente adeguata per questo tipo di importazione, quindi non mi aspetterei che UNICORN_WORKERS sia il principale collo di bottiglia in questo caso.

Alcune osservazioni:

  • Fermare Unicorn è probabilmente accettabile per un contenitore dedicato solo all’importazione o di staging, ma è improbabile che acceleri in modo significativo l’importatore stesso.
  • Disabilitare gli allegati e gli avatar dovrebbe rimuovere due delle operazioni più lente; quindi, se si ottengono comunque solo circa 440 post/min, il collo di bottiglia potrebbe essere l’I/O del database, il lato query MySQL della fonte phpBB o i tempi di attesa di Redis/PostgreSQL.
  • Vale la pena monitorare attentamente questa riga di log:

Eccezione durante la creazione del post 304683. Salto.

Anche se l’importazione prosegue, ciò significa che almeno quel post è stato saltato. Se ciò si verifica ripetutamente, la migrazione finale potrebbe risultare priva di alcuni post.

La parte relativa a Redis sembra indicare un timeout del client Redis di 1 secondo durante il blocco mutex distribuito di Discourse mentre PostCreator sta creando un post. Verificherei se Redis è effettivamente sovraccarico o se il timeout è semplicemente troppo aggressivo durante un’importazione lunga.

I prossimi controlli utili sarebbero:

free -h
df -h
iostat -xz 1
vmstat 1
redis-cli INFO memory
redis-cli INFO stats
redis-cli SLOWLOG GET 20

Inoltre, il database MySQL di phpBB è locale sullo stesso droplet o viene letto tramite rete? Dato che lo stack trace sta iterando attraverso mysql2, un database sorgente lento o un disco lento possono mantenere l’utilizzo della CPU basso mentre l’importatore attende.

All’attuale velocità, da 333919 / 2167314 a circa 441 elementi/min, mancano ancora circa 69 ore, quindi potrebbe terminare, ma sarei principalmente preoccupato se quelle eccezioni di timeout di Redis stiano causando il salto di post.

Non suggerirei di aumentare UNICORN_WORKERS. In un’esecuzione dedicata solo all’importazione, Unicorn è per lo più irrilevante. L’aspetto importante è che l’importazione prosegue ma salta dei post, ed è proprio questo il punto su cui vorrei attirare l’attenzione.

Gli importatori di massa sono ordini di grandezza più veloci, ma più difficili da configurare e far funzionare.

Nella maggior parte dei casi, è proprio così. Sono riuscito a velocizzare l’importazione aggiungendo indici, creando viste e ottimizzando le impostazioni del database. Ti consiglio di dedicare un po’ di tempo a questo aspetto, perché se in seguito dovessi riscontrare un errore nei tuoi dati e dovessi rieseguire l’importazione… sarebbe un vero mal di testa :grimacing:

A proposito, stiamo lavorando a nuovi strumenti che renderanno le migrazioni molto, molto più veloci!

Stiamo comunque procedendo!

var/www/discourse/script/import_scripts/phpbb3/importer.rb:38:in 'ImportScripts::PhpBB3::Importer#execute'
/var/www/discourse/script/import_scripts/base.rb:47:in 'ImportScripts::Base#perform'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:22:in 'ImportScripts::PhpBB3::Importer#perform'
script/import_scripts/phpbb3.rb:35:in '<module:PhpBB3>'
script/import_scripts/phpbb3.rb:16:in '<module:ImportScripts>'
script/import_scripts/phpbb3.rb:15:in ''
606484 / 2167314 ( 28.0%)  \[415 elementi/min\]  Eccezione durante la creazione del post 608597. Salto.
In attesa di 1,0 secondi
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:214:in 'block in RedisClient::RubyConnection::BufferedIO#fill_buffer'
<internal:kernel>:168:in 'Kernel#loop'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:197:in 'RedisClient::RubyConnection::BufferedIO#fill_buffer'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:187:in 'RedisClient::RubyConnection::BufferedIO#ensure_remaining'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/buffered_io.rb:152:in 'RedisClient::RubyConnection::BufferedIO#getbyte'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/resp3.rb:113:in 'RedisClient::RESP3.parse'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection/resp3.rb:50:in 'RedisClient::RESP3.load'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/ruby_connection.rb:97:in 'RedisClient::RubyConnection#read'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/connection_mixin.rb:37:in 'RedisClient::ConnectionMixin#call'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:374:in 'block (2 levels) in RedisClient#call_v'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client/middlewares.rb:16:in 'RedisClient::BasicMiddleware#call'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:373:in 'block in RedisClient#call_v'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:781:in 'RedisClient#ensure_connected'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-client-0.28.0/lib/redis_client.rb:372:in 'RedisClient#call_v'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis/client.rb:90:in 'Redis::Client#call_v'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/mini_profiler/profiling_methods.rb:90:in 'block in Redis::Client#profile_method'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:152:in 'block in Redis#send_command'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:151:in 'Monitor#synchronize'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis.rb:151:in 'Redis#send_command'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/redis-5.4.0/lib/redis/commands/server.rb:178:in 'Redis::Commands::Server#time'
/var/www/discourse/lib/discourse_redis.rb:38:in 'Kernel#public_send'
/var/www/discourse/lib/discourse_redis.rb:38:in 'block in DiscourseRedis#method_missing'
/var/www/discourse/lib/discourse_redis.rb:29:in 'DiscourseRedis.ignore_readonly'
/var/www/discourse/lib/discourse_redis.rb:38:in 'DiscourseRedis#method_missing'
/var/www/discourse/lib/distributed_mutex.rb:55:in 'block in DistributedMutex#synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in 'Thread::Mutex#synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in 'DistributedMutex#synchronize'
/var/www/discourse/lib/distributed_mutex.rb:34:in 'DistributedMutex.synchronize'
/var/www/discourse/lib/post_creator.rb:410:in 'PostCreator#transaction'
/var/www/discourse/lib/post_creator.rb:200:in 'PostCreator#create'
/var/www/discourse/script/import_scripts/base.rb:611:in 'ImportScripts::Base#create_post'
/var/www/discourse/script/import_scripts/base.rb:555:in 'block in ImportScripts::Base#create_posts'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/mysql2/alias_method.rb:8:in 'Mysql2::Result#each'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/mysql2/alias_method.rb:8:in 'Mysql2::Result#each'
/var/www/discourse/script/import_scripts/base.rb:542:in 'ImportScripts::Base#create_posts'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:212:in 'block in ImportScripts::PhpBB3::Importer#import_posts'
/var/www/discourse/script/import_scripts/base.rb:943:in 'block in ImportScripts::Base#batches'
<internal:kernel>:168:in 'Kernel#loop'
/var/www/discourse/script/import_scripts/base.rb:942:in 'ImportScripts::Base#batches'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:293:in 'ImportScripts::PhpBB3::Importer#batches'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:208:in 'ImportScripts::PhpBB3::Importer#import_posts'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:38:in 'ImportScripts::PhpBB3::Importer#execute'
/var/www/discourse/script/import_scripts/base.rb:47:in 'ImportScripts::Base#perform'
/var/www/discourse/script/import_scripts/phpbb3/importer.rb:22:in 'ImportScripts::PhpBB3::Importer#perform'
script/import_scripts/phpbb3.rb:35:in '<module:PhpBB3>'
script/import_scripts/phpbb3.rb:16:in '<module:ImportScripts>'
script/import_scripts/phpbb3.rb:15:in ''
615718 / 2167314 ( 28.4%)  \[415 elementi/min\]
\[phpbbimpo0:docker\*

1746813 / 2167314 (80,6%) [353 elementi/min]

È finito, ma ho dimenticato di importare le password, quindi devo ricominciare da capo :frowning: Questa volta però intendo eliminare alcuni post. Probabilmente ho mezzo milione di post su Jello e sui countdown lol. Grazie per il consiglio

Non importiamo le password e ti suggeriamo di non farlo nemmeno tu, per motivi di sicurezza.

Dopo una migrazione, gli utenti vengono invitati a reimpostare le proprie password tramite il pulsante “Ho dimenticato la password”. È un passaggio in più per loro, ma se spieghi in anticipo perché è necessario e come procedere, non dovrebbero esserci problemi.

Se sono ospitati in proprio, possono utilizzare il plugin Supporto per hash delle password migrati. Non importa le password, ma gli hash delle password, quindi è sicuro quanto lo erano le password sul vecchio sistema.

Con tutto il rispetto, ma non vedo fondamento per questa affermazione. Il nostro plugin migratepassword esiste da oltre un decennio e non sono mai stati riscontrati problemi di sicurezza.

Finché manterrai disabilitata l’impostazione migratepassword_allow_insecure_passwords, applicherà le stesse restrizioni sulla sicurezza delle password previste dal core di Discourse.