迁移vBulletin 5数据库 - 导入脚本错误

好的,快速回顾一下。

我正在从一个目前使用 vbulletin3 的论坛迁移。
在一个暂存环境中,从数据库转储开始(20GB,你没看错)。

运行升级到 vBulletin 5。花费了 5-6 小时,但成功了。版本是 vBulletin 5.4。
对用户名进行了一些清理,以便 Discourse 可以接受。

现在,安装了 docker discourse,并大致遵循了 此指南 进行准备。大致意思是,其中大部分是多余的或过时的,但它有助于了解该怎么做。

我现在处于一个我完全看不懂的步骤,因为我几乎没有 Ruby 编码经验。
所以,相关部分是,在完成安装后,我使用 ./launcher enter app 进入容器,然后:

  • 添加了 freetds-devlibmariadb-dev
  • 编辑了 Gemfile 以添加 php_serialize gem。
  • 从 shell 运行 export IMPORT=1 来设置导入的环境
  • discourse 用户身份运行 bundle install --no-deployment --without test --without development --path vendor/bundle

出现了错误:

You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.

If this is a development machine, remove the /var/www/discourse/Gemfile freeze
by running `bundle config unset deployment`.

The list of sources changed
The dependencies in your gemfile changed

You have added to the Gemfile:
* mysql2
* redcarpet
* php_serialize
* sqlite3 (>= 1.3, ~> 1.3.13)
* ruby-bbcode-to-md
* reverse_markdown
* tiny_tds
* csv
* parallel

所以,继续执行:

  • bundle config unset deployment 并再次运行之前的命令
  • 检查了 mysql2php_serialize 是否都存在(它们存在)
  • 添加了旧论坛的头像(没有附件需要导入),并将目录所有权分配给 discourse 用户在其自己的 /home/discourse
  • 编辑了 script/import_scripts/vbulletin5.rb 以更改连接到数据库的引用
  • 以用户 discourse 身份运行 bundle exec ruby script/import_scripts/vbulletin5.rb

这给了我一个关于 tzinfo Integer values not supported 的错误,我在 这里 的 discourse 上找到了提及。

Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...

importing groups...
       41 / 41 (100.0%)  [2294 items/min]  ]
importing users
Traceback (most recent call last):
        15: from script/import_scripts/vbulletin5.rb:726:in `<main>'
        14: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        13: from script/import_scripts/vbulletin5.rb:46:in `execute'
        12: from script/import_scripts/vbulletin5.rb:79:in `import_users'
        11: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
        10: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
         9: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
         8: from script/import_scripts/vbulletin5.rb:98:in `block in import_users'
         7: from /var/www/discourse/script/import_scripts/base.rb:264:in `create_users'
         6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
         5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
         4: from /var/www/discourse/script/import_scripts/base.rb:265:in `block in create_users'
         3: from script/import_scripts/vbulletin5.rb:110:in `block (2 levels) in import_users'
         2: from script/import_scripts/vbulletin5.rb:718:in `parse_timestamp'
         1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone.rb:575:in `utc_to_local'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp.rb:138:in `for': Integer values are not supported (ArgumentError)

@Haddoq 的建议是将一行代码从 Time.zone.at(@tz.utc_to_local(timestamp)) 更改为 Time.zone.at(timestamp)

它还建议添加 lastvisit 到用户查询中,因为否则会导致另一个错误,我也这样做了。

然而,现在当我用 bundle exec ruby script/import_scripts/vbulletin5.rb 启动迁移时,我得到以下结果:

Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...

importing groups...
       41 / 41 (100.0%)  [120217 items/min]
importing users
Traceback (most recent call last):
        13: from script/import_scripts/vbulletin5.rb:727:in `<main>'
        12: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        11: from script/import_scripts/vbulletin5.rb:46:in `execute'
        10: from script/import_scripts/vbulletin5.rb:79:in `import_users'
         9: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
         8: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
         7: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
         6: from script/import_scripts/vbulletin5.rb:80:in `block in import_users'
         5: from script/import_scripts/vbulletin5.rb:723:in `mysql_query'
         4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:22:in `query'
         3: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:147:in `query'
         2: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:147:in `handle_interrupt'
         1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `block in query'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query': You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASE WHEN u.scheme='blowfish:10' THEN token (Mysql2::Error)
                 WHEN u.scheme='lega' at line 2

这时我有点迷茫了。有人能帮忙吗?

paging @Canapin as he’s been in “Migration Vietnam” and might know more :heart:

连续工作 8 小时以上是坏的。

SELECT u.userid, u.username, u.homepage, u.usertitle, u.usergroupid, u.joindate, u.email, 的末尾添加 u.lastvisit 时,我忘记在后面添加逗号 ,

抱歉打扰 Canapin :frowning:

1 个赞

好的,又一个后续问题。我之前遵循的指南提到,如果注册过程变慢,可以重新启动它。

但是重新启动后,我收到了关于用户已存在于 postgres 数据库中的错误。

我太傻了,我删除了数据库中所有 id > 1 的用户(基本上只留下 discobot、system 和 admin),然后重新启动。这使得导入继续进行,但所有先前创建的用户电子邮件都被标记为“已使用”。

我该如何清理它,并且这个过程不应该在用户名匹配时跳过插入吗?

编辑:好的,我发现我需要清理 usersemail_tokensuser_emails

1 个赞

不幸的是,我没有跟踪我在之前的导入中调整过的内容,所以我知之甚少。我现在有一个个人 Discourse 实例,我可以在其中编写这类东西……我应该早点这样做的!
当我实际处理导入时,我对导入内容更在行。

至于删除用户,你可能想通过 rails 控制台使用 UserDestroyer

2 个赞

很棒,我会在“真正”迁移时记住这一点。现在我只是在编写运行手册时对整个过程进行试运行 :slight_smile:

1 个赞

你为什么这么做?除非你更改了脚本中导入这些用户的不同方式,否则你应该直接重新启动,让它导入那些尚未导入的用户。

如果你确实需要从头开始,恢复备份或删除并创建一个新数据库要容易得多。

它应该能在 UserCustomFields 表中找到导入 ID。我不太确定你是如何遇到那个错误的。

更改是我列出的那些。我很惊讶,但脚本无法继续,只会出错并停止。

导入是否有办法加速?

我的社区有超过 90,000 名用户,但导入速度不知何故会随着时间的推移而下降,我无法想象原因。

它运行了一整夜,仅用户我们就达到了 25123 / 95635 ( 26.3%) [42 items/min]

帖子的数量是用户数量的好几个数量级。我应该期望迁移需要多长时间?几天?几周?

内存多少?这很可能是问题所在。你可以停止并重启。

我曾遇到过需要几周时间的情况。这就是为什么需要批量导入程序。

它只有 2GB 内存。这是一台测试机器。我可以在本地运行它,而不是在虚拟机中运行(16GB 内存会好很多吗?),然后打包所有东西并最终上传,我想。

你能详细介绍一下批量导入器吗?我第一次听说它,在我用谷歌搜索“将 vBulletin 迁移到 Discourse”时,它肯定应该弹出:“愤怒”

Frustrated Jason Segel GIF by NETFLIX

即使另一个导入器已经处理了一些用户,我也可以运行这个,还是应该清理一下?

我已经尝试过了,最坏的情况是它不起作用。我不断收到垃圾邮件:

ERROR: no implicit conversion of nil into String
/var/www/discourse/script/bulk_import/base.rb:861:in `encode'
/var/www/discourse/script/bulk_import/base.rb:861:in `normalize_charset'
/var/www/discourse/script/bulk_import/base.rb:856:in `normalize_text'
script/bulk_import/vbulletin5.rb:123:in `block in import_users'
/var/www/discourse/script/bulk_import/base.rb:725:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:340:in `create_users'
script/bulk_import/vbulletin5.rb:120:in `import_users'
script/bulk_import/vbulletin5.rb:63:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

我猜我应该清理一下用户和组,这是其他导入器创建/开始创建的唯一内容。

在我再次弄乱数据库之前,有没有什么 Ruby 命令可以干净地处理这个问题?

这次我将继续销毁并重新创建 Discourse 安装。感谢 Docker。

不,是干净的安装,脚本仍然会因这个通用错误而失败

ERROR: no implicit conversion of nil into String
/var/www/discourse/script/bulk_import/base.rb:861:in `encode'
/var/www/discourse/script/bulk_import/base.rb:861:in `normalize_charset'
/var/www/discourse/script/bulk_import/base.rb:856:in `normalize_text'
script/bulk_import/vbulletin5.rb:123:in `block in import_users'
/var/www/discourse/script/bulk_import/base.rb:725:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:340:in `create_users'
script/bulk_import/vbulletin5.rb:120:in `import_users'
script/bulk_import/vbulletin5.rb:63:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

有什么办法可以调试这个问题,至少让我知道哪个值是 nil 而不是预期的值吗?

好的,错误似乎与编码有关。
bulk_import/vbulletin5.rb 中,我可以指定编码(在我们的例子中是 UTF8mb4,但在 base.rb 文件中,它似乎没有映射到字符集映射中的任何内容

您好!

一些通用建议:

  1. 如果您对脚本进行了更改,通常建议从头开始,或者至少从一个已知的良好点开始。您可以按照 @pfaffman 所说,恢复迁移运行之前的备份,这是最简单的方法。
  2. 批量导入程序通常会花费更少的时间,但这个特定的程序可能会消耗大量的内存,因为它会在内存中缓存数据。我曾经从一个 2GB 未压缩的 SQL 文件迁移 vBulletin,该过程需要 22GB RAM(已仔细检查,不是笔误)。
  3. 如果您对脚本进行了更改,我建议您为输入创建一个测试版本,例如每个表包含 100 或 1000 条记录(但要注意引用完整性 - 即不要截断被其他表引用的表)。使用超过 8 小时的进程测试更改会很快让您精神崩溃。

关于堆栈跟踪的更具体建议:查找提及您运行的特定文件的行。在这种情况下,是的,这是一个编码问题,但更相关的是它与用户名有关:

您说您必须清理用户名,所以我建议您仔细检查您是否按照脚本的预期对其进行了编码。

2 个赞

您可以直接删除、创建、迁移数据库,而不是重新创建 Discourse。不过,这有点棘手,因为您必须

  sv stop unicorn

然后

  rake db:drop db:create db:migrate

它会抱怨并告诉您设置一个 ENV 变量,您需要将其放在 rake 任务的前一行。

您也可以恢复备份,这可能更方便。

供您参考,我不认为我曾经使用过批量迁移脚本。

1 个赞

这更奇怪了,因为用户名都经过清理,以遵循 Discourse 的准则,基本上它们都被更改为仅包含字母、数字或下划线,没有其他字符。

无论如何,将字符集从 utf8mb4 更改为 utf8(这是默认设置)后,它就可以通过了,但现在我收到无效电子邮件的错误。

ERROR: can't modify frozen String: "24ef401b30f5161e5a0bb27ec49ed921@email.invalid"
/var/www/discourse/script/bulk_import/base.rb:457:in `downcase!'
/var/www/discourse/script/bulk_import/base.rb:457:in `process_user_email'
/var/www/discourse/script/bulk_import/base.rb:726:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:351:in `create_user_emails'
script/bulk_import/vbulletin5.rb:151:in `import_user_emails'
script/bulk_import/vbulletin5.rb:66:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

我现在要去弄清楚这是怎么回事,因为“非批量”导入检测到了一些格式错误的电子邮件,但会自动替换它们。

完成之后,只需备份您空置的、全新的 Discourse 安装。
您可以随时快速恢复它并重新开始。

2 个赞

此外,如果您在导入帖子等方面遇到问题,也可以在用户导入成功完成后退出脚本,并创建另一个备份。然后,您可以重新启动脚本,并从已导入用户的时刻继续。

1 个赞