حاليًا يمكن جدولة إدخال/إخراج الأقراص البعيدة وCPU باستخدام الطريقة الموضحة. وللاطلاع على حدود الذاكرة المرنة، راجع الالتزام الزائد بالذاكرة
تهيئة القرص
storage_configuration الخاصة بالخادم:
لتمكين جدولة IO لقرص معيّن، يجب تحديد read_resource و/أو write_resource في إعدادات التخزين. يحدّد ذلك لـ ClickHouse المورد الذي يجب استخدامه لكل طلب قراءة وكتابة على القرص المحدد. ويمكن أن يشير مورد القراءة ومورد الكتابة إلى اسم المورد نفسه، وهو ما يفيد مع أقراص Local SSD أو HDD. كما يمكن أن تشير عدة أقراص مختلفة إلى المورد نفسه، وهو ما يفيد مع الأقراص البعيدة إذا كنت تريد إتاحة تقسيم عادل لعرض نطاق الشبكة بين أعباء العمل مثلًا “الإنتاج” و”التطوير”.
مثال:
وسم عبء العمل
workload لتمييز أعباء العمل المختلفة. وإذا لم يتم تعيين workload، فستُستخدم القيمة “default”. لاحظ أنه يمكنك أيضًا تحديد قيمة أخرى باستخدام ملفات تعريف الإعدادات. ويمكن استخدام قيود الإعداد لجعل workload ثابتًا إذا كنت تريد وسم جميع استعلامات المستخدم بقيمة ثابتة لإعداد workload.
يمكن تعيين الإعداد workload لعمليات الخلفية. وتستخدم عمليات الدمج والطفرات إعدادَي الخادم merge_workload وmutation_workload على الترتيب. ويمكن أيضًا تجاوز هذه القيم لجداول محددة باستخدام إعدادَي MergeTree merge_workload وmutation_workload
لننظر في مثال لنظام يحتوي على عبئي عمل مختلفين: “production” و”development”.
التسلسل الهرمي لجدولة الموارد
inflight_limit(constraint) - يحظر التنفيذ إذا تجاوز عدد الطلبات المتزامنة قيد التنفيذmax_requests، أو إذا تجاوزت تكلفتها الإجماليةmax_cost؛ ويجب أن يكون له child واحد.bandwidth_limit(constraint) - يحظر التنفيذ إذا تجاوز عرض النطاق الحاليmax_speed(0 تعني غير محدود) أو إذا تجاوزت الدفقةmax_burst(وتساويmax_speedافتراضيًا)؛ ويجب أن يكون له child واحد.fair(policy) - يختار الطلب التالي الذي ستتم خدمته من إحدى عُقده الأبناء وفقًا لعدالة max-min؛ ويمكن للعُقد الأبناء تحديدweight(القيمة الافتراضية هي 1).priority(policy) - يختار الطلب التالي الذي ستتم خدمته من إحدى عُقده الأبناء وفقًا للأولويات الثابتة (القيمة الأقل تعني أولوية أعلى)؛ ويمكن للعُقد الأبناء تحديدpriority(القيمة الافتراضية هي 0).fifo(queue) - عقدة طرفية في التسلسل الهرمي يمكنها الاحتفاظ بالطلبات التي تتجاوز سعة المورد.
inflight_limit. لاحظ أن العدد المنخفض لـ max_requests أو max_cost قد يؤدي إلى عدم الاستفادة الكاملة من المورد، بينما قد تؤدي القيم المرتفعة جدًا إلى وجود طوابير فارغة داخل المُجدول، ما يؤدي بدوره إلى تجاهل السياسات (مثل غياب العدالة أو تجاهل الأولويات) في الشجرة الفرعية. من ناحية أخرى، إذا كنت تريد حماية الموارد من الاستغلال المفرط، فينبغي استخدام bandwidth_limit. فهو يحدّ المعدل عندما تتجاوز كمية المورد المستهلكة خلال duration ثانية مقدار max_burst + max_speed * duration بايت. ويمكن استخدام عقدتي bandwidth_limit على المورد نفسه للحد من ذروة عرض النطاق خلال الفترات القصيرة ومتوسط عرض النطاق خلال الفترات الأطول.
يوضح المثال التالي كيفية تعريف البنى الهرمية لجدولة IO الظاهرة في الصورة:
مُصنِّفات أعباء العمل
workload المحددة بواسطة query إلى قوائم الانتظار النهائية التي ينبغي استخدامها لموارد معيّنة. في الوقت الحالي، يكون تصنيف أعباء العمل بسيطًا: لا يتوفر سوى التعيين الثابت.
مثال:
التسلسل الهرمي لأحمال العمل
CREATE RESOURCE في البنية نفسها لهذا التسلسل الهرمي، لكنها قد تختلف في بعض الجوانب. ويتضمن كل عبء عمل أُنشئ باستخدام CREATE WORKLOAD عددًا قليلًا من عُقد الجدولة التي تُنشأ تلقائيًا لكل مورد. ويمكن إنشاء عبء عمل فرعي داخل عبء عمل رئيسي آخر. في ما يلي مثال يعرّف التسلسل الهرمي نفسه تمامًا كما في تهيئة XML أعلاه:
SETTINGS workload = 'name'.
لتخصيص عبء العمل، يمكن استخدام الإعدادات التالية:
priority- تتم خدمة أعباء العمل الشقيقة وفقًا لقيم أولوية ثابتة (القيمة الأقل تعني أولوية أعلى).weight- تتشارك أعباء العمل الشقيقة ذات الأولوية الثابتة نفسها الموارد وفقًا للأوزان.max_io_requests- الحد الأقصى لعدد طلبات IO المتزامنة في عبء العمل هذا.max_bytes_inflight- الحد الأقصى لإجمالي البايتات قيد التنفيذ للطلبات المتزامنة في عبء العمل هذا.max_bytes_per_second- الحد الأقصى لمعدل قراءة أو كتابة البايتات في عبء العمل هذا.max_burst_bytes- الحد الأقصى لعدد البايتات التي يمكن أن يعالجها عبء العمل من دون تقييد المعدل (لكل مورد على حدة).max_concurrent_threads- الحد الأقصى لعدد خيوط التنفيذ الخاصة بالاستعلامات في عبء العمل هذا.max_concurrent_threads_ratio_to_cores- مثلmax_concurrent_threads، ولكن محسوب نسبةً إلى عدد أنوية CPU المتاحة.max_cpus- الحد الأقصى لعدد أنوية CPU المستخدمة لخدمة الاستعلامات في عبء العمل هذا.max_cpu_share- مثلmax_cpus، ولكن محسوب نسبةً إلى عدد أنوية CPU المتاحة.max_burst_cpu_seconds- الحد الأقصى لعدد ثواني CPU التي يمكن أن يستهلكها عبء العمل من دون تقييد المعدل بسببmax_cpus.
max_bytes_per_second = 10485760 ستكون له سعة نطاق قدرها 10 MB/s لكل مورد قراءة ومورد كتابة على حدة. إذا كان مطلوبًا حدٌّ مشترك للقراءة والكتابة، ففكّر في استخدام المورد نفسه لوصول READ وWRITE.
لا توجد طريقة لتحديد هياكل هرمية مختلفة لأعباء العمل لموارد مختلفة. ولكن توجد طريقة لتحديد قيمة مختلفة لإعداد عبء العمل لمورد معيّن:
CREATE OR REPLACE WORKLOAD.
تُترجم إعدادات عبء العمل إلى مجموعة مناسبة من عُقَد الجدولة. ولمزيد من التفاصيل ذات المستوى الأدنى، راجع وصف أنواع عُقَد الجدولة وخياراتها.
جدولة CPU
- الخيط الرئيسي — أول خيط يبدأ العمل على استعلام أو نشاط في الخلفية مثل عملية دمج أو عملية mutation.
- خيط العامل — الخيوط الإضافية التي يمكن للخيط الرئيسي إنشاؤها للعمل على المهام كثيفة الاستهلاك للمعالج.
max_threads. وعندئذٍ ينبغي أن تُحجب الاستعلامات الواردة وتنتظر توفّر فتحة CPU حتى يتمكن خيطها الرئيسي من بدء التنفيذ. ولتجنّب ذلك، يمكن استخدام الإعداد التالي:
cpu_slot_preemption. وإذا كان مفعّلًا، يجدّد كل خيط تنفيذ فتحة CPU الخاصة به دوريًا (وفقًا لإعداد الخادم cpu_slot_quantum_ns). وقد يؤدي هذا التجديد إلى حظر التنفيذ إذا كان CPU مثقلاً. وعندما يُحظر التنفيذ لفترة طويلة (راجع إعداد الخادم cpu_slot_preemption_timeout_ms)، يُقلَّص الاستعلام وينخفض عدد خيوط التنفيذ المتزامنة العاملة ديناميكيًا. لاحظ أن عدالة وقت CPU مضمونة بين أعباء العمل، لكنها قد لا تتحقق بين الاستعلامات داخل عبء العمل نفسه في بعض الحالات الطرفية.
يؤدي تعريف مورد CPU إلى إبطال مفعول الإعدادين
concurrent_threads_soft_limit_num وconcurrent_threads_soft_limit_ratio_to_cores. وبدلاً من ذلك، يُستخدم إعداد عبء العمل max_concurrent_threads لتقييد عدد وحدات CPU المخصّصة لعبء عمل معيّن. وللحصول على السلوك السابق، أنشئ فقط مورد WORKER THREAD، واضبط max_concurrent_threads لعبء العمل all على القيمة نفسها لـ concurrent_threads_soft_limit_num، واستخدم إعداد الاستعلام workload = "all". ويتوافق هذا الضبط مع تعيين الإعداد concurrent_threads_scheduler إلى القيمة “fair_round_robin”.الخيوط مقابل وحدات CPU
- حد عدد الخيوط:
max_concurrent_threadsوmax_concurrent_threads_ratio_to_cores - خنق CPU:
max_cpusوmax_cpu_shareوmax_burst_cpu_seconds
max_threads. أما الطريقة الثانية فتقوم بخنق استهلاك CPU لعبء العمل باستخدام خوارزمية token bucket. وهي لا تؤثر مباشرةً في عدد الخيوط، لكنها تحدّ من إجمالي استهلاك CPU لجميع الخيوط في عبء العمل.
يعني خنق token bucket باستخدام max_cpus و max_burst_cpu_seconds ما يلي: خلال أي interval مقداره delta ثانية، لا يُسمح بأن يزيد إجمالي استهلاك CPU لجميع الاستعلامات في عبء العمل على max_cpus * delta + max_burst_cpu_seconds ثانية CPU. وهو يقيّد متوسط الاستهلاك عند max_cpus على المدى الطويل، لكن قد يتم تجاوز هذا الحد على المدى القصير. على سبيل المثال، إذا كانت max_burst_cpu_seconds = 60 و max_cpus=0.001، فيُسمح بتشغيل خيط واحد لمدة 60 ثانية، أو خيطين لمدة 30 ثانية، أو 60 خيطًا لمدة ثانية واحدة، من دون خنق. القيمة الافتراضية لـ max_burst_cpu_seconds هي ثانية واحدة. وقد تؤدي القيم الأقل إلى عدم الاستفادة الكاملة من الأنوية المسموح بها في max_cpus عند وجود عدد كبير من الخيوط المتزامنة.
أثناء احتفاظ خيط بفتحة CPU، يمكن أن يكون في واحدة من هذه الحالات الرئيسية الثلاث:
- Running: يستهلك مورد CPU فعليًا. ويُحتسب الوقت المقضي في هذه الحالة ضمن خنق CPU.
- Ready: ينتظر حتى تصبح وحدة CPU متاحة. لا يُحتسب ضمن خنق CPU.
- Blocked: ينفّذ عمليات IO أو استدعاءات نظام حاجبة أخرى (مثل انتظار mutex). لا يُحتسب ضمن خنق CPU.
default ذي القيمة 0)، ويحصل أولًا على أي حصة CPU عند الحاجة. وعندما لا يُشغّل Admin أي استعلامات، تُوزَّع موارد CPU بين أعباء عمل الإنتاج والتطوير. وتعتمد الحصص المضمونة من وقت CPU على الأوزان (4 إلى 1): يذهب ما لا يقل عن 80% إلى الإنتاج (عند الحاجة)، ويذهب ما لا يقل عن 20% إلى التطوير (عند الحاجة). وبينما توفّر الأوزان هذه الضمانات، يفرض تقييد CPU حدودًا: فالإنتاج غير مقيَّد ويمكنه استهلاك 100%، بينما للتطوير حدّ قدره 30%، ويُطبَّق هذا الحد حتى إذا لم تكن هناك استعلامات من أعباء عمل أخرى. وعبء عمل الإنتاج ليس عقدة طرفية، لذا تُقسَّم موارده بين التحليلات والاستيعاب وفقًا للأوزان (3 إلى 1). وهذا يعني أن التحليلات لها حصة مضمونة لا تقل عن 0.8 * 0.75 = 60%، وبالاستناد إلى max_cpu_share، فلها حد أقصى يبلغ 70% من إجمالي موارد CPU. أما الاستيعاب، فرغم أن حصته المضمونة لا تقل عن 0.8 * 0.25 = 20%، فلا يوجد له حد أعلى.
إذا كنت تريد زيادة استخدام CPU إلى أقصى حد على ClickHouse server، فتجنّب استخدام
max_cpus وmax_cpu_share لعبء العمل الجذر all. وبدلًا من ذلك، اضبط قيمة أعلى لـ max_concurrent_threads. على سبيل المثال، في نظام يحتوي على 8 وحدات CPU، اضبط max_concurrent_threads = 16. يتيح ذلك تشغيل 8 خيوط لمهام CPU، بينما يمكن لـ 8 خيوط أخرى التعامل مع عمليات I/O. وستُحدِث الخيوط الإضافية ضغطًا على CPU، ما يضمن تطبيق قواعد الجدولة. وعلى النقيض من ذلك، فإن ضبط max_cpus = 8 لن يُحدِث أبدًا ضغطًا على CPU لأن الخادم لا يمكنه تجاوز وحدات CPU الثماني المتاحة.جدولة حصص الاستعلام
max_concurrent_queries من عدد الاستعلامات المتزامنة التي يمكن تشغيلها في الوقت نفسه لعبء عمل معيّن. وهو مماثل لإعداد الاستعلام max_concurrent_queries_for_all_users وإعداد الخادم max_concurrent_queries. ولا تُحتسب استعلامات async insert وبعض الاستعلامات المحددة، مثل KILL، ضمن هذا الحد.
يحدّ إعدادا عبء العمل max_queries_per_second وmax_burst_queries عدد الاستعلامات لعبء العمل باستخدام مُقيِّد من نوع token bucket. ويضمن ذلك أنه خلال أي فترة زمنية T لن يبدأ تنفيذ أكثر من max_queries_per_second * T + max_burst_queries من الاستعلامات الجديدة.
يحدّ إعداد عبء العمل max_waiting_queries من عدد الاستعلامات المنتظرة لعبء العمل. وعند بلوغ هذا الحد، يعيد الخادم الخطأ SERVER_OVERLOADED.
ستنتظر الاستعلامات المحجوبة إلى أجل غير مسمّى، ولن تظهر في
SHOW PROCESSLIST حتى تُستوفى جميع القيود.تخزين أحمال العمل والموارد
CREATE WORKLOAD وCREATE RESOURCE، تخزينًا دائمًا إما على القرص في workload_path أو في ZooKeeper عند workload_zookeeper_path. ويُوصى باستخدام التخزين في ZooKeeper لتحقيق الاتساق بين العُقد. وبدلًا من ذلك، يمكن استخدام البند ON CLUSTER إلى جانب التخزين على القرص.
أحمال العمل والموارد المستندة إلى التهيئة
تنسيق التهيئة
CREATE WORKLOAD وCREATE RESOURCE. يجب أن تكون جميع الاستعلامات صحيحة.
توصيات الاستخدام
- حدِّد عبء العمل الجذري وموارد IO للشبكة في التهيئة لوضع حدود البنية التحتية
- اضبط
throw_on_unknown_workloadلفرض هذه الحدود - أنشئ
CREATE WORKLOAD default IN allلتطبيق الحدود تلقائيًا على جميع الاستعلامات (لأن القيمة الافتراضية لإعداد الاستعلامworkloadهي ‘default’) - اسمح للمستخدمين بإنشاء أعباء عمل إضافية ضمن التسلسل الهرمي المُعدّ
الوصول المقيّد إلى الموارد
throw_on_unknown_workload. إذا ضُبط على true، فسيُطلب من كل استعلام استخدام إعداد workload صالح، وإلا فسيُرفع الاستثناء RESOURCE_ACCESS_DENIED. وإذا ضُبط على false، فلن يستخدم هذا الاستعلام مجدول الموارد، أي سيحصل على وصول غير محدود إلى أي RESOURCE. يتيح إعداد الاستعلام ‘use_concurrency_control = 0’ للاستعلام تجاوز مجدول CPU والحصول على وصول غير محدود إلى CPU. ولفرض جدولة CPU، أنشئ قيدًا على الإعداد للإبقاء على ‘use_concurrency_control’ كقيمة ثابتة للقراءة فقط.
لا تضبط
throw_on_unknown_workload على true ما لم يكن CREATE WORKLOAD default قد نُفِّذ. فقد يؤدي ذلك إلى مشكلات في بدء تشغيل الخادم إذا نُفِّذ أثناء بدء التشغيل استعلام بدون إعداد workload صريح.راجع أيضًا
- system.scheduler
- system.workloads
- system.resources
- merge_workload إعداد MergeTree
- merge_workload إعداد عام على مستوى الخادم
- mutation_workload إعداد MergeTree
- mutation_workload إعداد عام على مستوى الخادم
- workload_path إعداد عام على مستوى الخادم
- workload_zookeeper_path إعداد عام على مستوى الخادم
- cpu_slot_preemption إعداد عام على مستوى الخادم
- cpu_slot_quantum_ns إعداد عام على مستوى الخادم
- cpu_slot_preemption_timeout_ms إعداد عام على مستوى الخادم