Очень медленная проблема Sidekiq с большой очередью из-за огромного количества непрочитанных уведомлений пользователей

Спасибо, @Falco.

Я в основном просто не понимаю, как производительность может колебаться от выполнения ~11 млн до ~300 тыс. задач в день в течение примерно одной недели при той же конфигурации. Разница в скорости составляет примерно в 35 раз по количеству задач в секунду.

Что касается использования процессора, оно снова упало до ~15–20%, что является обычным показателем. Обработка задач происходит с той же скоростью (медленно).

Только для уточнения/подтверждения: я имел в виду назначение (а не добавление) некоторых воркеров Sidekiq исключительно для обработки очереди с низким приоритетом, так как казалось, что задачи с низким приоритетом могут выполняться гораздо быстрее и, возможно, не сталкиваются с теми же узкими местами. Я предполагал, что это может объяснить, почему количество задач в секунду может так сильно варьироваться (т. е. задачи с низким приоритетом «простые» задачи застревают позади очереди задач по умолчанию).

Уточню: как вы думаете, что вызывает медленное завершение задач — производительность PostgreSQL или просто событие высокой загрузки процессора, которое я заметил вчера (которое сейчас вернулось в норму)?

Всё это на SSD, верно?

Да, верно, @Stephen — NVMe SSD в RAID 1.

Обновление: Я несколько раз пытался удалить очередь с низким приоритетом и очередь по умолчанию, но это не повлияло на скорость, так как очередь по умолчанию сразу же снова заполнялась. Затем я попробовал удалить очередь по умолчанию и включить режим только для чтения. Это привело к резкому скачку количества обработанных заданий в секунду, и очередь с низким приоритетом была обработана с невероятной скоростью (примерно в 100 раз быстрее).

Редакция: Похоже, что даже при наличии только большой очереди с низким приоритетом скорость обработки всё ещё низкая. Если я переведу Discourse в режим только для чтения, а затем очищу обе очереди (с низким приоритетом и по умолчанию), то последующая обработка заданий остаётся чрезвычайно быстрой: планировщик задач и очереди опустошаются до тех пор, пока я не отключу режим только для чтения. :yuno:

Мой следующий шаг — точно определить, какой процесс вызывает проблему. Для этого нужно зайти в приложение Discourse и запустить htop или top, чтобы увидеть процессы с самым высоким потреблением CPU.

Похоже, что PostgreSQL является узким местом. Вы можете настроить Prometheus для отслеживания его производительности и проверить, получает ли он достаточно оперативной памяти.

Спасибо за ваш комментарий @pfaffman :slight_smile: Я полагаю, что db_shared_buffers и db_work_mem в файле app.yml — это единственные параметры, контролирующие использование оперативной памяти PostgreSQL, верно?

Я немного экспериментировал, увеличивая и уменьшая значения. Текущие настройки в app.yml:
db_shared_buffers: “32768MB”
db_work_mem: “128MB”

Общий объем оперативной памяти системы — 128 ГБ.

Также я пробовал изменять параметр max_connections в файле /var/discourse/shared/standalone/postgres_data/postgresql.conf, а затем пересобирать Discourse. Испытывал значения выше стандартного (100): от 200 до 500. В настоящее время установлено значение 300. Не уверен, что изменение этого параметра в указанном месте действительно влияет на максимальное количество подключений.

В файле /var/discourse/templates/postgres.template.yml я вижу следующие настройки:

db_synchronous_commit: “off”
db_shared_buffers: “256MB”
db_work_mem: “10MB”
db_default_text_search_config: “pg_catalog.english”
db_name: discourse
db_user: discourse
db_wal_level: minimal
db_max_wal_senders: 0
db_checkpoint_segments: 6
db_logging_collector: off
db_log_min_duration_statement: 100

Спасибо @bartv, следуя вашему совету, я наблюдал за процессами внутри приложения Discourse через утилиту top. Я вижу множество процессов postmaster, запущенных от имени пользователя postgres — потребление CPU варьируется. Скриншоты показывают продолжительные периоды с похожей статистикой использования.

Использование ~95% из 32 ядер:

Использование ~20%, более низкое потребление CPU процессом postmaster.

Использование ~6% CPU, пока был активен режим только для чтения.

Какого размера ваша база данных? Сколько у вас пользователей? Сколько новых постов в день?

Первое, что нужно сделать, — это выполнить команду VACUUM ANALYZE; из консоли PostgreSQL.

Это может занять некоторое время; возможно, стоит временно остановить Sidekiq, чтобы снизить нагрузку во время выполнения.

Если это не поможет, следует включить расширение pg_stat_statements, а затем проверить, какие запросы потребляют значительное количество ресурсов CPU.

@pfaffman

  • Папка /var/discourse/shared/standalone/postgres_data занимает 170 ГБ
  • 61,7 тыс. активных пользователей за последние 30 дней (точное общее количество неизвестно)
  • ~50–80 тыс. новых постов в день

Ох. Это нетривиально.

Вам стоит изучить настройки оптимизации PostgreSQL. Такой уровень производительности немного выходит за рамки типичного самостоятельного хостинга, который здесь встречается.

Я бы попробовал выделить PostgreSQL около 3/4 оперативной памяти. Конечно, стоит разделить контейнеры для данных и веб-сервера. Но, возможно, вам потребуется более сложная настройка PostgreSQL, чтобы обеспечить необходимую производительность.

РЕДАКТИРОВАНИЕ: Однако у меня нет опыта работы с гораздо более крупными базами данных, так что смотрите ниже! :wink:

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

Информация из pg_stat_statements, скорее всего, подскажет, в чём проблема.

Огромное спасибо за помощь, ребята.

Итак, я попробовал запустить VACUUM ANALYZE; — к сожалению, безрезультатно. Ниже приведены использованные команды для справки:

cd /var/discourse/
./launcher enter app
sudo -u postgres psql
\c discourse
VACUUM ANALYZE;

Я попытался включить pg_stat_statements, шаги выполнены ниже:

Добавил/изменил следующие строки здесь: /var/discourse/shared/standalone/postgres_data/postgresql.conf

shared_preload_libraries = ‘pg_stat_statements’ # (требуется перезапуск)
pg_stat_statements.max = 10000
pg_stat_statements.track = all
pg_stat_statements.track_utility = on
pg_stat_statements.save = off

Затем я пересобрал Discourse и выполнил:

./launcher enter app
sudo -u postgres psql
\c discourse
CREATE EXTENSION pg_stat_statements;

Я попытался выполнить запросы, но получил следующую ошибку:

ERROR: pg_stat_statements must be loaded via shared_preload_libraries

Мое предположение: мои правки в файле postgresql.conf (/var/discourse/shared/standalone/postgres_data/postgresql.conf) не применяются (я пересобирал Discourse после редактирования). Возможно ли внести эти изменения через файл app.yml? Или вы видите, где я ошибся?

Пересборка Discourse удалит эти изменения. Скорее всего, поможет перезапуск контейнера (также может сработать команда вроде sv restart postgres внутри контейнера).

Спасибо, я попробовал перезапустить контейнер:

./launcher stop app
./launcher start app

При попытке выполнить запрос всё та же ошибка:

ERROR: pg_stat_statements must be loaded via shared_preload_libraries

Изменения, которые я ранее внёс, всё ещё сохраняются в этом файле даже после пересборки:

/var/discourse/shared/standalone/postgres_data/postgresql.conf

Подозреваю, что редактировать нужно не этот файл :face_with_monocle:

Возможно, это связано с тем, что я использую только app.yml (и mail-receiver.yml) в папке containers и не реализовал использование data.yml.

Не заглядывая внутрь, можно сказать, что это, скорее всего, /etc/postgres внутри контейнера. Возможно, вам также потребуется установить любую библиотеку, которую он требует.

Спасибо, это очень помогло, по крайней мере сначала. :man_cartwheeling:. Проблема, казалось, была решена, и очередь задач работала очень быстро просто благодаря увеличению максимального числа соединений в postgresql.conf. К сожалению, примерно через день скорость снова упала.

Ниже приведены шаги, на случай если они будут полезны другим, желающим увеличить максимальное число соединений в PostgreSQL.

docker ps

Получите ID контейнера, например aaabbbccc123, и подставьте его в команды ниже:

Скопируйте файл postgresql.conf изнутри контейнера Docker в локальную файловую систему:

docker cp aaabbbccc123:/etc/postgresql/10/main/postgresql.conf /srv

Отредактируйте конфигурацию:

nano /srv/postgresql.conf

Скопируйте его обратно в контейнер Docker:

docker cp /srv/postgresql.conf aaabbbccc123:/etc/postgresql/10/main/postgresql.conf

cd /var/discourse
./launcher stop app
./launcher start app

Удалите оставшийся файл (необязательно):

rm /srv/postgresql.conf

@supermathie I believe I’ve successfully enabled pg_stat_statements :grinning:

I tried using this query:

SELECT
(total_time / 1000 / 60) as total,
(total_time/calls) as avg,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;

From this guide: The most useful Postgres extension: pg_stat_statements - Citus Data

I can’t really read the result though, I think I’ve done something wrong.

total | avg | query
1671.1110420745 | 374.736186677194 | SELECT COUNT(*) FROM ( +
| | SELECT $1 FROM +
| | notifications n +
| | LEFT JOIN topics t ON t.id = n.topic_id +
| | WHERE t.deleted_at IS NULL AND +
| | n.notification_type <> $2 AND +
| | n.user_id = $3 AND +
| | n.id > $4 AND

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

Кроме того, вы можете просто выполнить ./launcher enter app и отредактировать файлы напрямую. Однако имейте в виду, что при пересборке эти изменения не сохранятся в новом контейнере.