备份恢复失败,sidekiq 无法停止然后失控

我今天早上进行了重建,然后尝试将备份恢复到容器中。我使用的是 2.6.0.beta5 (75a893fd61),所有组件都在容器内。

备份恢复通常可以正常工作(之前也成功过),但今天却失败了,错误如下:

Starting restore: app-2020-11-06-033740-v20201009190955.tar.gz
[STARTED]
'system' has started the restore!
Marking restore as running...
Making sure /var/www/discourse/tmp/restores/default/2020-11-06-084354 exists...
Copying archive to tmp directory...
Unzipping archive, this may take a while...
Extracting dump file...
Validating metadata...
  Current version: 20201103103401
  Restored version: 20201009190955
Enabling readonly mode...
Pausing sidekiq...
Waiting up to 60 seconds for Sidekiq to finish running jobs...
Waiting for sidekiq to finish running jobs... #2
Waiting for sidekiq to finish running jobs... #3
Waiting for sidekiq to finish running jobs... #4
Waiting for sidekiq to finish running jobs... #5
Waiting for sidekiq to finish running jobs... #6
Waiting for sidekiq to finish running jobs... #7
Waiting for sidekiq to finish running jobs... #8
Waiting for sidekiq to finish running jobs... #9
Waiting for sidekiq to finish running jobs... #10
EXCEPTION: Sidekiq did not finish running all the jobs in the allowed time!
/var/www/discourse/lib/backup_restore/system_interface.rb:89:in `block in wait_for_sidekiq'
/var/www/discourse/lib/backup_restore/system_interface.rb:84:in `loop'
/var/www/discourse/lib/backup_restore/system_interface.rb:84:in `wait_for_sidekiq'
/var/www/discourse/lib/backup_restore/restorer.rb:47:in `run'
script/discourse:143:in `restore'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-1.0.1/lib/thor/base.rb:485:in `start'
script/discourse:284:in `<top (required)>'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `load'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `kernel_load'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:28:in `run'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:476:in `exec'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:30:in `dispatch'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:24:in `start'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/friendly_errors.rb:123:in `with_friendly_errors'
/usr/local/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Trying to rollback...
There was no need to rollback
Cleaning stuff up...
Removing tmp '/var/www/discourse/tmp/restores/default/2020-11-06-084354' directory...
Unpausing sidekiq...
Disabling readonly mode...
Marking restore as finished...
Notifying 'system' of the end of the restore...
Finished!
[FAILED]
Restore done.

之后,有一个 Ruby 进程持续占用 100% CPU 数小时。该进程信息如下:

# ps aux | grep sidekiq
discour+    141  100  5.0 9302596 401484 ?      SNl  06:34 127:46 sidekiq 6.1.2 discourse [5 of 5 busy]

如果我停止并重新启动容器,这个 Sidekiq 进程仍然会回到 100% CPU 占用。sidekiq.log 为空,production.log 也没有显示太多信息。

我该如何查明这个 Sidekiq 进程正在做什么?是否有人在使用此版本时遇到过备份恢复失败的问题?

一位友好的绅士提醒我查看 Sidekiq 控制台,看起来 Sidekiq 正忙于缩略图生成:

我使用的备份不包含缩略图,因此这 可能 是预期行为。不过,在上一次测试备份恢复后,我已经运行了 rake posts:rebake,随后又运行了 rake posts:rebake_uncooked_posts,本以为这些操作应该已经完成了所有缩略图生成(rebake 处理大约 10 万篇帖子耗时约 1 小时,而 rebake_uncooked 没有做任何事情,我猜是因为完整的 rebake 已经处理了所有内容)。

假设这个工作负载是导致备份失败的原因,那么恢复备份时难道不应该先清除任务队列吗?

另外,既然表面上没有什么需要处理的,为什么 Sidekiq 还在生成缩略图?还是说 rebake 命令只是将工作加入队列?

# rake posts:rebake_uncooked_posts
正在默认环境下重新烘焙未烘焙的帖子

0 篇帖子完成!

没错。重新烘焙(rebake)会先将一堆任务加入队列,而不是立即全部执行。

可能吧。但通常的假设是,如果你懂得如何恢复备份,也就懂得先清理 Sidekiq 队列;通常你会将备份恢复到一个空站点上。

我相信情况确实如此。

谢谢,这开始变得清晰多了。

那么正确的顺序是否应该是:先销毁容器,然后(重新)构建容器,接着进入容器并恢复备份?

如果是这样,那很好。不过,Discourse 或许可以在向非空容器开始恢复时提供相应的提示或警告。

那就是“核选项”(我想你其实只需要删除 Redis 数据,然后重新构建即可)。通常情况下,不会有成千上万个任务在运行,所以这根本不成问题。但既然你显然连续进行了两次恢复操作,而第一次还没完全结束你就开始了第二次,那你就是个特殊情况。

另一个办法是进入 /sidekiq 页面,删除所有排队的任务。只需要点击几下就行。

那么,这对灾难恢复来说是个很好的测试 :smiley:

你说得对,这确实可能属于一种特殊情况。我一直在尝试缩短重新烘焙的时间,因此我在不同情况下测试了备份恢复并计时(默认情况下,如果不恢复缩略图,重新烘焙需要 2 到 3 天才能完成!)。这一切都是为网站迁移做铺垫。

我想我现在理解得更多了,谢谢。但对于像备份这样关键的任务,我认为 Discourse 应该确保其尽可能可靠(例如,在启动前清除 Sidekiq 队列),或者在检测到可能影响恢复的问题时发出明确的警告,提示需要执行其他步骤。

只有你知道该怎么做。

建议在迁移到不同服务器时创建包含缩略图的备份(通过 include_thumbnails_in_backups 站点设置)。

谢谢!这也是我尝试过的选项,但备份虽然只增加了约 6GB 的大小,创建时间却多了大约一小时。看起来是 tar 步骤耗时——可能是我的旧硬件在处理大量小文件时访问速度较慢。Gzip 压缩级别已设为 1,因此我认为瓶颈在于 I/O 而非 CPU。新主机完成同样的备份只需 30 到 40 分钟。

也许我只是有点缺乏耐心,应该接受备份时间较长的情况。不过,由于主站点在此过程中处于只读模式,我希望能尽量缩短这段时间。