Otimização da velocidade de migração do PHPBB para o Discourse

Ei, estou com o phpBB desde 2004, então estou transferindo um fórum de tamanho considerável. Atualmente, estou no segundo dia: 303.139/2.167.314 (14%), com 446 por minuto. Como posso acelerar isso? Estou na Digital Ocean e estou usando apenas 4% da CPU. O Redis continua dando timeout para mim. Desativei os anexos.

Alguns detalhes úteis ajudariam a estreitar essa investigação:

  • Tamanho do Droplet: RAM, quantidade de vCPU, tipo/tamanho do disco
  • O comando de importação exato que você está executando
  • As configurações relacionadas a recursos do seu app.yml, com segredos removidos, especialmente:
    • UNICORN_WORKERS
    • db_shared_buffers
    • db_work_mem
  • Se a importação está sendo executada dentro do contêiner Docker padrão do Discourse
  • Quaisquer mensagens de timeout do Redis ou trechos de log
  • Se o banco de dados está local, no mesmo contêiner, ou externo

Um ponto a observar: UNICORN_WORKERS provavelmente não acelerará muito a importação, pois o importador do phpBB não é atendido principalmente pelos workers da web. Aumentá-lo pode apenas consumir mais RAM. As configurações de memória do PostgreSQL e a E/S do disco são mais prováveis de fazer diferença.

Como o uso da CPU é de apenas cerca de 4%, isso pode ser limitado por E/S, limitado pelo banco de dados ou por espera no Redis, e não por falta de CPU. O timeout do Redis merece investigação separada.

image

Meu log atualizado
script/import_scripts/phpbb3.rb:15:in ‘’
302570 / 2167314 ( 14.0%) [448 itens/min] Exceção ao criar a postagem 304683. Pulando.
Aguardado 1,0 segundo
/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 itens/min]

Parece que está funcionando, sem reclamações.

Até agora

Unicorn parado

Anexos e avatares desativados

O tamanho da droplet parece razoavelmente adequado para esse tipo de importação, então eu não esperaria que UNICORN_WORKERS fosse o principal limitador aqui.

Algumas observações:

  • Parar o Unicorn provavelmente é aceitável para um container de importação ou staging, mas dificilmente acelerará significativamente o próprio importador.
  • Com os anexos e avatares desabilitados, duas das etapas mais lentas devem ser removidas. Se você ainda estiver obtendo apenas ~440 posts/min, o gargalo pode estar na E/S do banco de dados, na consulta MySQL do phpBB de origem ou em esperas no Redis/PostgreSQL.
  • Vale a pena observar com atenção a linha do log:

Exception while creating post 304683. Skipping.

Embora a importação continue, isso significa que pelo menos aquele post foi pulado. Se isso acontecer repetidamente, a migração final pode estar faltando posts.

A parte do Redis parece ser um timeout de 1 segundo no cliente Redis durante o bloqueio de mutex distribuído do Discourse enquanto o PostCreator está criando um post. Verifique se o Redis está realmente sobrecarregado ou se o timeout está apenas muito agressivo durante uma importação longa.

Próximas verificações úteis seriam:

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

Além disso, o banco de dados MySQL do phpBB está local na mesma droplet ou sendo lido pela rede? Como o rastreamento de pilha está iterando pelo mysql2, um banco de dados de origem lento ou um disco lento podem manter o uso da CPU baixo enquanto o importador aguarda.

Na taxa atual, de 333919 / 2167314 a cerca de 441 itens/min, você ainda tem aproximadamente 69 horas restantes, então a importação pode terminar, mas minha principal preocupação é se essas exceções de timeout do Redis estão causando a omissão de posts.

Eu não sugeriria aumentar UNICORN_WORKERS. Em uma execução de importação exclusiva, o Unicorn é em grande parte irrelevante. O importante é que a importação está continuando, mas pulando posts, e é isso que eu destacaria.