Многопоточность Ruby на нескольких процессорах

Привет! Как я уже упоминал в предыдущих постах, я провожу тестовые запуски миграции с Drupal на Discourse, чтобы подготовить все необходимые решения перед окончательным отключением старого сайта и переносом продакшн-данных, содержащих около 2 млн постов. Из того, что я узнал, процесс импорта на довольно быстром VPS с 3 ядрами CPU занимает очень много времени — примерно 48 часов. Затем, скорее всего, придётся выполнить дополнительную очистку с помощью задач rake и/или rails c, а для любых операций, требующих выполнения rake posts:rebake, потребуется ещё около 20 часов.

Я не очень хорошо разбираюсь в основах инструментария Ruby. Но если я добавлю больше ядер CPU, существенно ли это сократит время выполнения каждого из этих процессов? Например, смогут ли команды bundle или rake распределить свою работу между доступными процессорами, или дополнительные ядра полезны в основном для запуска нескольких параллельных процессов, когда на сайт одновременно обращаются несколько пользователей?

Я немного отклоняюсь от темы, но когда я работал над миграцией форума с таким же количеством постов, я модифицировал скрипт импорта, чтобы импортировать только 1/100 или 1/1000 тем и постов.

Это более быстрый способ проверить надёжность вашего импорта и понять, нужны ли корректировки или отладка.

@Canapin На самом деле, большое спасибо, что упомянули об этом. Мне очень интересно узнать, как вы это сделали. Я давно хотел сделать то же самое, но отказался от этой идеи, предполагая, что при частичном импорте возникнут проблемы с согласованностью базы данных. Поэтому в итоге я создал тестовый форум на Drupal в виде скелета для экспериментов. Но я бы предпочел тестировать копию рабочей базы данных.

Меня в основном беспокоит окончательная миграция на продакшн: мне придется отключить старый форум или хотя бы перевести его в режим только для чтения, и похоже, что минимальное время простоя составит 48 часов, если только удвоение количества ядер процессора не сократит это время вдвое?

Задачи, на восстановление которых уходит много времени, действительно выполняются в многопоточном режиме. Однако следует учитывать, что удвоение количества процессоров почти никогда не приводит к двукратному росту производительности.

Ещё один важный момент: обычно задачи, связанные с выполнением команды rake posts:rebake, а также основная работа самого форума по восстановлению и оптимизации контента, могут выполняться при работающем форуме. Это может сократить время, в течение которого форум должен быть недоступен или работать только в режиме чтения, позволяя при этом предоставлять пользователям несколько урезанный функционал.

Моя рекомендация: сначала проведите тестирование. Выполните миграцию, оцените, сколько времени это займёт, и посмотрите, как выглядит форум без всех пересобраных версий контента. Если время миграции приемлемо, запланируйте её на период с наименьшей нагрузкой на форум. Таким образом вы выиграете от 4 до 10 часов на миграцию, не вызывая большого количества жалоб со стороны пользователей.

Отлично, спасибо за подтверждение. Я тоже интересовался этой возможностью.

К сожалению, я это не записал и забыл… Но если вы умеете программировать, это не должно быть очень сложно.
Возможно, я изменял значения BATCH_SIZE и offset среди прочего, чтобы модифицировать цикл и заставить его пропускать партии постов или что-то в этом роде…

Сейчас я не могу повторить попытку, потому что у меня нет форума для импорта, но в следующий раз я составлю краткое руководство, так как считаю это довольно полезным.

Хочу отметить два момента.

  • Да, процессоры важны, поэтому просто возьмите более мощный VPS и запустите несколько экземпляров Sidekiq для повторной обработки и обработки изображений — это ускорит процесс.
  • Когда импорт полностью завершён, всегда полезно сделать резервную копию и восстановить базу данных — это улучшит производительность базы данных.

Совместно это выглядит так: для импорта используйте мощный VPS, а после завершения перенесите его на более компактный продакшн-сервер (через резервное копирование и восстановление).

Как правило, после импорта не требуется повторная обработка постов.

Большое спасибо за ответ, Ричард. Так какие именно из них?

  • UNICORN_WORKERS
  • UNICORN_SIDEKIQS
  • DISCOURSE_SIDEKIQ_WORKERS

Интересно, я раньше не встречал этой рекомендации. Это уменьшает фрагментацию или что-то в этом роде?

Да, изначально я планировал исправить проблемы с [QUOTE] и конвертацию из Textile в Markdown с помощью regexp_replace() в консоли Postgres, а затем повторно обработать все посты, потому что команды rake posts:remap работали слишком медленно. Но затем я обнаружил, что вариант регулярных выражений, используемый Postgres, не совместим с PCRE, и существует слишком много непредсказуемых аномалий, чтобы полагаться на него. Поэтому я попробую пропустить посты через Pandoc в процессе импорта — это позволит мне привести импортированный сайт в рабочее и презентабельное состояние, а затем исправить мелкие детали, такие как ключевые слова для эмодзи, с помощью rake posts:remap.

  • UNICORN_SIDEKIQS — количество процессов (по умолчанию 1)
  • DISCOURSE_SIDEKIQ_WORKERS — количество потоков внутри процесса (по умолчанию 5)

Это уменьшает фрагментацию и исправляет ситуацию, когда статистика Postgres может быть искажена из-за импорта.

:+1:

Я тоже раньше не встречал этого совета. Если это «всегда полезно», возможно, стоит добавить эту рекомендацию в Pre-launch checklist after migrating from another platform?

Думаю, это Сэм или Джефф дали мне этот совет много лет назад. Я больше не могу его найти. Может, стоит проверить, всё ещё ли это хорошая идея и/или стоит ли затраченных усилий :wink:

Случайно не мог бы кто-нибудь поделиться советами о самом быстром способе повторного запуска скрипта импорта и повторного импорта данных? Я пытаюсь настроить подстановку текста в скрипте импортера, и когда у меня не получается, мне приходится удалять базу данных Discourse и запускать ./launcher rebuild import, что занимает довольно много времени. Я хотел бы вносить изменения в свой скрипт импортера и запускать его заново с самого начала (сейчас я использую небольшую тестовую базу данных-каркас моего сайта, поэтому запуск импортера происходит очень быстро).

Хм. Я тестирую ещё один импорт данных моего продакшн-форума, на этот раз на довольно мощном VPS с 8 виртуальными ядрами и 16 ГБ ОЗУ. Я установил:
UNICORN_SIDEKIQS=4
DISCOURSE_SIDEKIQ_WORKERS=20
UNICORN_WORKERS=16

При этом, похоже, во время этапа import_topics не используются все ядра:

Хотя интересно, что на этапе user_import график процессора уперся в отметку свыше 600% (то есть использовалось около 6 из 8 ядер на 100%).

Также я обратил внимание на переменную окружения: RUBY_GLOBAL_METHOD_CACHE_SIZE=131072. Не слишком ли она мала?

Я считаю, что на этапе создания пользователя Sidekiq асинхронно обрабатывает больше действий.
К сожалению, значительная часть импорта не выиграет от параллелизации, поэтому стоит оптимизировать производительность для однопоточного процессора.

Теоретически можно запускать разные части импорта тем параллельно, но это потребует значительной рефакторинг импортера и обеспечения последовательной обработки всех данных. Для разовой задачи с несколькими итерациями это того не стоит.

Я использовал комбинацию этих двух руководств[1][2] для импорта, имея доступ к другому контейнеру Docker с копией базы данных исходного форума в MySQL. Но мне пришло в голову, что вместо создания отдельного контейнера import я могу просто использовать один контейнер app и добавить в него mysql-dep.template:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"
  - "templates/import/mysql-dep.template.yml"

Это позволяет мне иметь работающий экземпляр Discourse, пока выполняется скрипт импорта. Есть ли какие-либо недостатки в том, чтобы открыть форум для публики сразу после импорта всех пользователей и категорий, просто уведомив пользователей баннером о том, что полное заполнение займёт несколько дней? Я думаю, что как минимум я могу открыть его после импорта всех тем и сообщений, но до импорта личных сообщений, так как только личные сообщения займут около 24 часов.