كمية هائلة من معاملات التخزين

مرحبًا،

نواجه أحمال معاملات ضخمة على تخزيننا من وقت لآخر. لم نتمكن من العثور على أي جدول زمني أو نمط زمني لهذا الحدث، لكنه يحدث مرة واحدة على الأقل يوميًا. حتى أن المدة تتراوح بين 10 دقائق وعدة ساعات.
أثناء هذه الأحمال، يتصرف نظامنا بالكامل بشكل غريب قليلاً، على سبيل المثال، لا يتم التعرف على قراءة المواضيع، لذا لا تزال تظهر في “جديدة” و/أو “غير مقروءة”.

يبدو أن Discourse ينقل كميات هائلة من الملفات. خاصة عمليات READ تزداد بشكل ملحوظ. لقد تحققنا بالفعل مما إذا كان هناك زيادة في حركة المرور الخارجية أيضًا، لكن لا. فقط حركة المرور بين Discourse والتخزين هي المتأثرة.
لاحظنا هذا السلوك لأول مرة بعد الترقية من Discourse 2.4.0.beta9 إلى 2.4.0.beta10، لكننا لسنا متأكدين مما إذا كان قد حدث من قبل. نحن الآن نعمل بالإصدار 2.5.0.beta4.

يعمل تثبيت Discourse لدينا في بيئة Azure مع تخزين Premium متصل عبر SMBv3، والذي يعمل بشكل جيد عادةً.

هل يمكن لأحد شرح ما يحدث؟ في البداية اشتبهنا في مهمة sidekiq المسماة MigrateUploadScheme، لكن إذا كانت هذه المهمة مسؤولة عن هذه المعاملات، فيجب أن نرى هذه الأحمال العالية بشكل متكرر أكثر مما نراه. بالإضافة إلى ذلك، لم نجد أي مهمة أخرى يمكن أن تكون مسؤولة.


بسبب “انفجار IOPS”، يمكنك رؤية هذه الذروة عند حوالي 800 ألف معاملة/30 دقيقة. بعد استنفاد هذه الرصيد، يتم تقليلها إلى حوالي 250 ألف معاملة/30 دقيقة. لذا، يرجى عدم الانتباه إلى هذه الذروة لأنها مجرد مكافأة محدودة/مرخصة من طبقة تخزين Azure.
عادةً ما يكون لدينا 5 آلاف - 40 ألف معاملة كل 30 دقيقة.

في هذه المرحلة، لا نعرف أين ننظر، وأي فكرة أو تلميح مُقدَّر.

مع أطيب التحيات،
ساسشا

هل تم تمكين النسخ الاحتياطي التلقائي؟ تحقق من إعدادات الموقع تمكين النسخ الاحتياطي التلقائي و تكرار النسخ الاحتياطي

مرحبًا.
لا، النسخ الاحتياطي معطل تمامًا. نحن نستخدم خاصية الاحتفاظ بالنسخ الاحتياطي الخاصة بـ PSQL-Instance نفسها ولقطات التخزين (غير المؤتمتة).

هل يمكنك تمكين الإحصائيات في Postgres للبحث عن استعلامات طويلة المدة أو استعلامات متكررة؟

يجب عليك تمكين pg_stat_statements والتعمق في الإحصائيات التي ينشئها

قمنا بتفعيل الإحصائيات منذ فترة لمعالجة بعض الاختناقات. ومن هنا جاءت مشاركتي السابقة توصيات أداء قاعدة البيانات (من Azure PSQL).

إليك أعلى 10 استعلامات طويلة الأمد خلال الأسبوع الماضي:

إذا كنت بحاجة إلى الاستعلامات الكاملة، يرجى إعلامي، وسنكون مهتمين بمعرفة سبب تأثير ذلك على استخدام التخزين.

ربما تكون هذه أول استعلام كامل على الإطلاق، فهي كبيرة جدًا حيث تبلغ مدتها دقيقة واحدة وتم تنفيذها 14 مرة.

مرحبًا. سيتم تشغيل/تنفيذ الاستعلام الأول عبر DirectoryItem.refresh_period (أظن ذلك).

إذًا، هذا هو الاستعلام الفعلي:

ملخص
WITH x AS (SELECT
			u.id user_id,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 2 THEN 1 ELSE 0 END) likes_received,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 1 THEN 1 ELSE 0 END) likes_given,
			COALESCE((SELECT COUNT(topic_id) FROM topic_views AS v WHERE v.user_id = u.id AND v.viewed_at > '2019-10-28 23:52:24.911261'), 0) topics_entered,
			COALESCE((SELECT COUNT(id) FROM user_visits AS uv WHERE uv.user_id = u.id AND uv.visited_at > '2019-10-28 23:52:24.911261'), 0) days_visited,
			COALESCE((SELECT SUM(posts_read) FROM user_visits AS uv2 WHERE uv2.user_id = u.id AND uv2.visited_at > '2019-10-28 23:52:24.911261'), 0) posts_read,
			SUM(CASE WHEN t2.id IS NOT NULL AND ua.action_type = 4 THEN 1 ELSE 0 END) topic_count,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 5 THEN 1 ELSE 0 END) post_count
			FROM users AS u
			LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id AND COALESCE(ua.created_at, '2019-10-28 23:52:24.911261') > '2019-10-28 23:52:24.911261'
			LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id AND p.deleted_at IS NULL AND p.post_type = 1 AND NOT p.hidden
			LEFT OUTER JOIN topics AS t ON p.topic_id = t.id AND t.archetype = 'regular' AND t.deleted_at IS NULL AND t.visible
			LEFT OUTER JOIN topics AS t2 ON t2.id = ua.target_topic_id AND t2.archetype = 'regular' AND t2.deleted_at IS NULL AND t2.visible
			LEFT OUTER JOIN categories AS c ON t.category_id = c.id
			WHERE u.active
			AND u.silenced_till IS NULL
			AND u.id > 0
			GROUP BY u.id)
	UPDATE directory_items di SET
		 likes_received = x.likes_received,
		 likes_given = x.likes_given,
		 topics_entered = x.topics_entered,
		 days_visited = x.days_visited,
		 posts_read = x.posts_read,
		 topic_count = x.topic_count,
		 post_count = x.post_count
	FROM x
	WHERE
	x.user_id = di.user_id AND
	di.period_type = 5 AND (
	di.likes_received <> x.likes_received OR
	di.likes_given <> x.likes_given OR
	di.topics_entered <> x.topics_entered OR
	di.days_visited <> x.days_visited OR
	di.posts_read <> x.posts_read OR
	di.topic_count <> x.topic_count OR
	di.post_count <> x.post_count )

هل يمكنني تقديم بعض السياق لتتمكن من تقييمه بشكل أفضل:
لدينا حوالي 430 ألف مستخدم، و1.6 مليون موضوع (بدون المحذوف منها) مع 8.4 مليون منشور (بدون المحذوف منها) في 241 فئة و12 مليون user_actions.

لكنني لا أفهم بعد لماذا يجب أن تتسبب الاستعلامات البطيئة في هذا العدد الكبير من عمليات القراءة على وحدة التخزين (/uploads). هل يمكن أن أكون قد فاتني شيء ما؟

هذا لا يبدو صحيحًا. أنا مشوش، إذا كنت تستخدم Azure، فكيف تقوم بتخزين الملفات؟ هل هذه إعدادة حاوية واحدة؟ وكيف تم إعداد عمليات الرفع؟

تحديث الدليل بطيء جدًا. إذا لم تتمكن من تحمل تكلفة تحديثه، فيمكنك تعطيل الدليل https://meta.discourse.org/u. لدينا بعض الخطط المحددة لإضافة بحث المستخدمين إلى بحث الصفحة الكاملة، حتى تتمكن من الاستغناء عن الدليل.

نعتذر عن أي لبس. سأحاول شرح كيفية إعدادنا لـ Discourse.

أولاً، ليس لدينا إعداد حاوية واحدة. لقد قمنا بتقسيمه لاستخدام خدمات Azure الخاصة بـ Redis و PostgreSQL والتخزين.

هناك 3 آلات افتراضية (VMs) تشغل Discourse + Nginx. تم تركيب Azure File Share منفصل عبر SMBv3 على هذه الآلات الافتراضية الثلاث، وتم ربط نقطة التثبيت هذه بحاويات Discourse كحجم تخزين (volume).
هنا سيتم تخزين /public/uploads و /tmp/javascript-cache و /tmp/stylesheet-cache.

بالإضافة إلى ذلك، نستخدم Azure Cache for Redis و Azure Database for PostgreSQL.

أقراص الآلات الافتراضية والتخزين وقاعدة البيانات مفصولة عن بعضها البعض. لذلك، لن يؤثر حمل قاعدة البيانات (أو لا ينبغي أن يؤثر) على التخزين أو أداء الآلات الافتراضية، ويمكننا الاستفادة من مزايا هذه الخدمات (مثل إحصائيات قاعدة البيانات على مثيل PostgreSQL الذي ذكرته سابقًا وتوصيات الأداء).

يسمح لنا هذا الإعداد أيضًا بمراقبة كل خدمة/جزء على حدة، وقد لاحظنا أن Azure File Share، حيث يتم تخزين uploads، يستقبل عددًا كبيرًا جدًا من المعاملات (كما يمكنك رؤية ذلك في منشوري الأول). تتكون هذه المعاملات في الغالب من عمليات قراءة.

وبما أن هذا التخزين (Azure File Share) يُستخدم فقط بواسطة Discourse نفسه، فقد حاولنا معرفة العملية/العمل المسؤول عن هذه الأحداث التي تحدث 1-2 مرة يوميًا وتستمر من بضع دقائق إلى عدة ساعات.

إلى جانب هذه الأعداد الهائلة من المعاملات، يعمل هذا الإعداد بشكل جيد جدًا باستثناء بعض الاستعلامات البطيئة التي تؤثر على الأداء فقط في حالات قليلة (على سبيل المثال، قد تستغرق صفحات ملخص نشاط عدد قليل من المستخدمين ما يصل إلى 15 ثانية للتحميل).

آمل أن أكون قد شرحت سبب دهشتي من كيف يمكن لأداء قاعدة البيانات أن يؤثر على عدد معاملات الملفات الثابتة.

مع أطيب التحيات وشكرًا لجهودكم حتى الآن
ساسا

ملاحظة:
نحن نستخدم صورة Docker مخصصة في إعدادنا، وأنا أفهم تمامًا أنك لا تستطيع/لا ترغب في تقديم دعم للحلول المخصصة.
الشيء الوحيد الذي نود معرفته هو العملية/العمل/الإعداد الذي قد يتسبب في هذه الأعداد من معاملات التخزين والتي تبطئ جزئيًا الإعداد بأكمله، وما يمكننا فعله لتجنب ذلك.

أعتقد أن أفضل خيار لك من حيث الأداء هو التبديل إلى تخزين S3 أو محرك تخزين متوافق مع S3 بالإضافة إلى CDN. استخدام مشاركة SMB للuploads ليس شيئًا اختبرناه من قبل. أظن أننا نتحقق من حجم الuploads يوميًا، وهو أمر سريع جدًا على النظام المحلي، ولكنه بطيء جدًا على SMB.

شكرًا للتوضيح ونصيحتك. في الواقع، يمكن أن يكون بروتوكول SMB بطيئًا جدًا عند الوصول إلى عدد كبير من الملفات. في معظم الأحيان، لا يحدث فرق لأن الملفات التي يتم الوصول إليها بشكل متكرر يتم تخزينها مؤقتًا بواسطة nginx (نطبق بشكل متكرر التغييرات المطبقة على ملف إعداد nginx النموذجي الخاص بـ Discourse). لكن عند التعامل مع عمليات الفحص هذه، ينخفض الأداء.

نحن نبحث عن حلول تخزين أخرى منذ فترة. قد يؤدي استخدام تخزين خارجي متوافق مع S3 إلى كسر أجزاء من مفهوم الأمان الخاص بنا. كل مثيل/خدمة مشاركة (قاعدة البيانات، الآلة الافتراضية، التخزين، إلخ) مرتبط بشبكة خاصة وغير قابل للوصول من الإنترنت العام. يتم إدارة جميع حركة المرور العامة بواسطة Azure Application Gateway.

لسوء الحظ، ليس تخزين Azure Blob متوافقًا مع S3، لكن قد ينبغي علينا استثمار بعض الوقت للاستفادة منه. الحلول الممكنة الحالية هي إضافة تخزين Blob الخاصة بـ Discourse أو استخدام blobfuse مباشرة داخل الحاوية.

على أي حال، شكرًا لوقتك ومساعدتك. هل هناك سبب لفحص حجم التحميل يوميًا، وهل هناك طريقة لإيقاف ذلك؟

مع أطيب التحيات

يبدو أن هذا الأمر يأتي من هنا:

أعتقد أنه يمكنك تعطيل سحب الصور المرتبطة حرارياً، أو إنشاء “تصحيح قرد” (monkey patch) في إضافة تقوم بتعطيل ذلك:

أو ببساطة قم بإنشاء اسم مستعار (alias) للأمر du في الحاوية الخاصة بك ليكون غير فعال (no-op) من خلال تعديل إعدادات الحاوية الخاصة بك.

شكرًا جزيلاً لك، هذا سيساعد كثيرًا. ستكون أداة du مكلفة جدًا عند استخدامها مع مشاركة SMB، خاصة أننا نستضيف حوالي 800 ألف ملف (38 جيجابايت) على هذه المشاركة.

لقد قمنا بتعطيل pulling_hotlinked_images بالفعل بسبب المخاوف القانونية/حقوق النشر المحتملة.

أعتقد أن إنشاء اختصار (alias) لـ du قد يكون تدخلاً كبيرًا بعض الشيء، بينما يُعد إصلاحه باستخدام إضافة فكرة جيدة. هل يمكننا ببساطة تطبيق git-patch أثناء بناء الصورة باستخدام شيء مثل:

def self.used(path)
    output = Discourse::Utils.execute_command('df', '-Pk', path)
    size_line = output.split("\n")[1]
    size_line.split(/\s+/)[2].to_i * 1024
end

وبما أن du قد تكون أكثر موثوقية/دقة، أعتقد أن df ستناسب احتياجاتنا ولن تكسر أي وظيفة أخرى.