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.