مشكلة بطء شديد في Sidekiq مع طابور كبير بسبب أعداد هائلة من إشعارات المستخدم غير المقروءة

شكرًا لك @Falco

أنا في حيرة أساسًا من كيفية أن يتقلب الأداء بين إكمال حوالي 11 مليون وظيفة وحوالي 300 ألف وظيفة في اليوم خلال أسبوع واحد تقريبًا مع نفس التكوين. فرق سرعة يبلغ حوالي 35 ضعفًا من حيث عدد الوظائف في الثانية.

أما بالنسبة لاستخدام وحدة المعالجة المركزية، فقد عاد إلى حوالي 15-20% وهو المعدل المعتاد. معالجة الوظائف بنفس السرعة (البطيئة).

فقط للتوضيح/التأكيد، كنت أعني تخصيص (وليس إضافة) بعض عمال Sidekiq لمعالجة طابور الأولوية المنخفضة حصريًا، حيث بدا أن مهام الأولوية المنخفضة يمكن معالجتها بمعدل أسرع بكثير وقد لا تعاني من نفس الاختناقات. كنت أتخيل أن هذا قد يفسر كيف يمكن أن يتفاوت عدد الوظائف في الثانية بهذه الطريقة الكبيرة (أي مهام الأولوية المنخفضة “السهلة” عالقة خلف طابور الانتظار الافتراضي).

للتوضيح - هل تعتقد أن أداء PostgreSQL هو ما يسبب إكمال الوظائف البطيء أم مجرد حدث استخدام وحدة المعالجة المركزية المرتفع الذي لاحظته أمس (والذي عاد الآن إلى طبيعته)؟

كل هذا على قرص SSD، أليس كذلك؟

نعم، صحيح @Stephen - أقراص NVMe SSD في تكوين RAID 1.

تحديث: لقد حاولت حذف طابور الأولوية المنخفضة والطابور الافتراضي عدة مرات دون أي تأثير على السرعة، حيث ينمو الطابور الافتراضي مرة أخرى فورًا. ثم جربت حذف الطابور الافتراضي وتفعيل وضع القراءة فقط. أدى ذلك إلى ارتفاع حاد في عدد الوظائف في الثانية، مما سمح بالمرور السريع عبر طابور الأولوية المنخفضة (سرعة تزيد عن 100 مرة في عدد الوظائف في الثانية).

تعديل: يبدو أنه حتى مع وجود طابور أولوية منخفضة كبير فقط، تظل سرعة المعالجة بطيئة. إذا قمت بتعيين Discourse على وضع القراءة فقط، ثم أفراغ طابوري الأولوية المنخفضة والافتراضي، يبدو أن معالجة الوظائف بعد ذلك تظل سريعة جدًا في إفراغ المهام المجدولة والطوابير حتى أقوم بتعطيل وضع القراءة فقط. :yuno:

خطوتي التالية ستكون تحديد العملية التي تسبب المشكلة بدقة من خلال الدخول إلى تطبيق Discourse وتشغيل htop أو top لعرض أعلى استهلاك للوحدة المركزية للمعالجة.

يبدو أن قاعدة بيانات PostgreSQL هي عنق الزجاجة. يمكنك إعداد Prometheus لتتبع أدائها والتحقق من أنها تحصل على ذاكرة وصول عشوائي (RAM) كافية.

شكرًا لمساهمتك @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، مع تباين في استخدام وحدة المعالجة المركزية. تمثل لقطات الشاشة فترات زمنية ممتدة بإحصائيات استخدام مماثلة.

استخدام حوالي 95% من 32 نواة:

استخدام حوالي 20%، مع انخفاض استخدام وحدة المعالجة المركزية لـ postmaster.

استخدام حوالي 6% من وحدة المعالجة المركزية، بينما كان وضع القراءة فقط نشطًا.

ما حجم قاعدة بياناتك؟ كم عدد المستخدمين لديك؟ كم عدد المنشورات الجديدة يوميًا؟

أول ما يجب عليك فعله هو تشغيل الأمر VACUUM ANALYZE; من وحدة تحكم PostgreSQL.

قد يستغرق هذا الأمر بعض الوقت للتنفيذ؛ لذا قد ترغب في إيقاف Sidekiq مؤقتًا لتخفيف الحمل أثناء تشغيله.

إذا لم يُسهم ذلك في حل المشكلة، فيجب علينا تمكين pg_stat_statements ثم التحقق من الاستعلامات التي تستهلك قدرًا هائلاً من وحدة المعالجة المركزية (CPU).

@pfaffman

  • مجلد /var/discourse/shared/standalone/postgres_data بحجم 170 جيجابايت
  • 61.7 ألف مستخدم نشط خلال آخر 30 يومًا (غير متأكد من الإجمالي المطلق)
  • ما بين 50 ألفًا و80 ألف منشور جديد يوميًا

أوه، هذا ليس بالأمر البسيط.

يجب أن تقرأ عن ضبط أداء PostgreSQL. مستوى الأداء هذا يتجاوز إلى حد ما الاستضافة الذاتية النموذجية التي تُرى هنا.

أنصحك بتخصيص حوالي ثلاثة أرباع ذاكرة الوصول العشوائي (RAM) لـ PostgreSQL. وسأقوم بالتأكيد بفصل الحاويات إلى حاوية للبيانات وأخرى للويب. لكن قد تحتاج إلى إعداد أكثر تعقيدًا لـ 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) في مجلد الحاويات، ولم أقوم بتطبيق استخدام data.yml.

بدون النظر فعليًا، من المرجح أن يكون المسار /etc/postgres داخل الحاوية. قد تحتاج أيضًا إلى تثبيت أي مكتبة يطلبها.

شكرًا لك، ساعدني هذا كثيرًا في البداية. :man_cartwheeling:. بدا أن المشكلة قد حُلّت، وازدادت سرعة طابور الوظائف بشكل ملحوظ بمجرد زيادة الحد الأقصى للاتصالات في ملف postgresql.conf. للأسف، تباطأ الأمر مجددًا بعد يوم تقريبًا.

أضع الخطوات أدناه، في حال كانت مفيدة للآخرين الراغبين في زيادة الحد الأقصى للاتصالات (max_connections) في PostgreSQL.

docker ps

احصل على معرف الحاوية (Container 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

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

الآن بعد أن عرفت ما تريد فعله، يمكنك إجراء هذه التغييرات باستخدام عبارة استبدال في ملف app.yml.

كما يمكنك أيضًا تشغيل الأمر ./launcher enter app وتعديل الملفات مباشرة. ولكن لاحظ أنه عند إعادة البناء، لن تكون هذه التغييرات موجودة في الحاوية الجديدة.