يمكن تطبيق الدرس الموضّح في هذا الدليل على تطبيقات تخزين الكائنات الأخرى التي تملك دوال جداول مخصّصة لها، مثل GCS وAzure Blob storage.
آليات insert (عقدة واحدة)
حجم كتلة الإدراج
INSERT INTO SELECT، يتلقى ClickHouse جزءًا من البيانات، ثم ① يُنشئ (على الأقل) كتلة إدراج واحدة داخل الذاكرة (لكل مفتاح تقسيم) من البيانات المستلمة. بعد ذلك، تُرتَّب بيانات الكتلة وتُطبَّق عليها تحسينات خاصة بمحرك الجدول. ثم تُضغط البيانات وتُكتب ② إلى مساحة تخزين قاعدة البيانات على شكل جزء بيانات جديد.
يؤثر حجم كتلة الإدراج في كلٍّ من استخدام I/O لملفات القرص واستخدام الذاكرة في ClickHouse server. تستهلك كتل الإدراج الأكبر ذاكرةً أكثر، لكنها تُنتج أجزاءً أولية أكبر وأقل عددًا. وكلما قلّ عدد الأجزاء التي يحتاج ClickHouse إلى إنشائها عند تحميل كمية كبيرة من البيانات، انخفض I/O لملفات القرص وقلت عمليات الدمج في الخلفية المطلوبة تلقائيًا.
عند استخدام استعلام INSERT INTO SELECT بالاقتران مع محرك جدول تكامل أو table function، يسحب ClickHouse server البيانات:
وحتى يكتمل تحميل البيانات، ينفّذ server حلقةً:
min_insert_block_size_rows(القيمة الافتراضية:1048545صفًا)min_insert_block_size_bytes(القيمة الافتراضية:256 MiB)
min_insert_block_size_bytes تشير إلى حجم الكتلة غير المضغوطة في الذاكرة (وليس حجم الـ جزء المضغوط على القرص). ولاحظ أيضًا أن الكتل والـ أجزاء المُنشأة نادرًا ما تحتوي بدقة على العدد المُعدّ من الصفوف أو البايتات، لأن ClickHouse يتعامل مع البيانات ويقوم بمعالجتها على أساس صفوف ضمن كتل. لذلك، تحدد هذه الإعدادات حدودًا دنيا.
انتبه إلى عمليات الدمج
MergeTree).
توازي الإدراج
max_insert_threads. تكون القيمة الافتراضية 1 في ClickHouse مفتوح المصدر و4 في ClickHouse Cloud.
عند وجود عدد كبير من الملفات، تعمل المعالجة المتوازية عبر عدة خيوط إدراج بكفاءة. ويمكنها الاستفادة بالكامل من كلٍّ من أنوية CPU المتاحة وعرض النطاق الترددي للشبكة (في تنزيلات الملفات المتوازية). وفي السيناريوهات التي يُحمَّل فيها عدد قليل فقط من الملفات الكبيرة إلى جدول، ينشئ ClickHouse تلقائيًا مستوىً عاليًا من التوازي في معالجة البيانات، ويُحسّن استخدام عرض النطاق الترددي للشبكة من خلال إنشاء خيوط قراءة إضافية لكل خيط إدراج لقراءة (تنزيل) المزيد من النطاقات المختلفة داخل الملفات الكبيرة بالتوازي.
بالنسبة إلى دالة s3 والجدول، يُحدَّد التنزيل المتوازي لملف واحد بواسطة القيم max_download_threads وmax_download_buffer_size. لن تُنزَّل الملفات بالتوازي إلا إذا كان حجمها أكبر من 2 * max_download_buffer_size. افتراضيًا، تُضبط القيمة الافتراضية لـ max_download_buffer_size على 10MiB. وفي بعض الحالات، يمكنك بأمان زيادة حجم هذا المخزن المؤقت إلى 50 MB (max_download_buffer_size=52428800) بهدف ضمان تنزيل كل ملف بواسطة خيط واحد. ويمكن أن يقلل ذلك الوقت الذي يقضيه كل خيط في إجراء استدعاءات S3، وبالتالي يُخفِّض أيضًا وقت انتظار S3. علاوة على ذلك، بالنسبة إلى الملفات الصغيرة جدًا بحيث لا تناسب القراءة المتوازية، يزيد ClickHouse معدل النقل تلقائيًا من خلال الجلب المسبق للبيانات عبر القراءة المسبقة غير المتزامنة لهذه الملفات.
قياس الأداء
تأثير حجم الموارد العتادية
- الحجم الأولي المدعوم للأجزاء
- مستوى توازي الإدراج الممكن
- إنتاجية عمليات دمج الأجزاء في الخلفية
الموقع الإقليمي
التنسيقات
s3 والمحرك S3. وعند قراءة الملفات الخام، تتميز بعض هذه التنسيقات بمزايا واضحة:
- تتطلب الاستعلامات على التنسيقات التي تتضمن أسماء أعمدة مُرمَّزة، مثل Native وParquet وCSVWithNames وTabSeparatedWithNames، تفاصيل أقل، لأن المستخدم لن يكون بحاجة إلى تحديد اسم العمود في الدالة
s3. إذ تتيح أسماء الأعمدة استنتاج هذه المعلومات تلقائيًا. - تختلف التنسيقات من حيث الأداء فيما يتعلق بمعدلات النقل في القراءة والكتابة. ويُعد Native وParquet الخيارين الأمثل لأداء القراءة، لأنهما عموديان بطبيعتهما وأكثر إحكامًا. ويستفيد تنسيق Native أيضًا من توافقه مع الطريقة التي يخزن بها ClickHouse البيانات في الذاكرة، مما يقلل العبء الإضافي للمعالجة أثناء تدفق البيانات إلى ClickHouse.
- كثيرًا ما يؤثر حجم الكتلة في زمن استجابة القراءة من الملفات الكبيرة. ويظهر ذلك بوضوح إذا كنت تكتفي بأخذ عينة من البيانات، مثلًا عند إرجاع أعلى N من الصفوف. وفي حالة التنسيقات مثل CSV وTSV، يجب تحليل الملفات أولًا لإرجاع مجموعة من الصفوف. أما التنسيقات مثل Native وParquet فتتيح أخذ العينات بسرعة أكبر نتيجة لذلك.
- لكل تنسيق ضغط مزاياه وعيوبه، وغالبًا ما يكون الأمر موازنةً بين مستوى الضغط والسرعة مع تفضيل أداء الضغط أو فك الضغط. وإذا كنت تضغط ملفات خام مثل CSV أو TSV، فإن lz4 يوفر أسرع أداء لفك الضغط، مقابل التضحية بمستوى الضغط. أما Gzip فعادةً ما يحقق ضغطًا أفضل على حساب سرعات قراءة أبطأ قليلًا. ويذهب Xz إلى أبعد من ذلك، إذ يقدم عادةً أفضل ضغط مع أبطأ أداء في الضغط وفك الضغط. وعند التصدير، يوفر كل من Gz وlz4 سرعات ضغط متقاربة. وازن ذلك مع سرعات الاتصال لديك. فأي مكاسب من ضغط أو فك ضغط أسرع قد تتلاشى بسهولة بسبب بطء الاتصال بحاويات التخزين S3 لديك.
- لا تبرر التنسيقات مثل Native أو Parquet عادةً الكلفة الإضافية للضغط. فمن المرجح أن يكون التوفير في حجم البيانات محدودًا، لأن هذه التنسيقات مدمجة بطبيعتها. ونادرًا ما يعوض الوقت المستغرق في الضغط وفك الضغط أزمنة نقل الشبكة، لا سيما أن S3 متاح عالميًا وبعرض نطاق شبكي أعلى.
مجموعة بيانات تجريبية
SELECT، حيث تُعاد كميات كبيرة من البيانات إلى العميل، فاستخدم إمّا تنسيق Null للاستعلامات أو وجّه النتائج إلى محرك Null. من شأن ذلك تجنّب إرهاق العميل بالبيانات وتشبّع الشبكة.
عند القراءة باستخدام الاستعلامات، قد يبدو الاستعلام الأوّلي أبطأ في كثير من الأحيان من تكرار الاستعلام نفسه. ويمكن أن يُعزى ذلك إلى كلٍّ من التخزين المؤقت في S3 وذاكرة التخزين المؤقت لاستنتاج المخطط في ClickHouse. إذ تخزّن هذه الذاكرة المخطط المستنتَج للملفات، ما يتيح تخطّي خطوة الاستنتاج في عمليات الوصول اللاحقة، وبالتالي تقليل وقت الاستعلام.
استخدام الخيوط لعمليات القراءة
- عادةً ما تكون القيمة الافتراضية لـ
max_threadsكافية، أي عدد الأنوية. وإذا كان مقدار الذاكرة المستخدمة للاستعلام كبيرًا وتحتاج إلى تقليله، أو كانLIMITعلى النتائج منخفضًا، فيمكن ضبط هذه القيمة إلى مستوى أقل. وقد يرغب المستخدمون الذين لديهم ذاكرة وفيرة في تجربة زيادة هذه القيمة للحصول على معدل نقل أعلى للقراءة من S3. وعادةً لا يكون ذلك مفيدًا إلا على الأجهزة ذات عدد الأنوية المنخفض، أي أقل من10. وغالبًا ما تتضاءل فائدة المزيد من التنفيذ المتوازي عندما تصبح موارد أخرى هي عنق الزجاجة، مثل الشبكة أو التنافس على CPU. - كانت إصدارات ClickHouse الأقدم من 22.3.1 لا تُجري القراءة على التوازي عبر ملفات متعددة إلا عند استخدام الدالة
s3أو محرك الجدولS3. وكان ذلك يتطلب من المستخدم التأكد من تقسيم الملفات إلى أجزاء على S3 وقراءتها باستخدام نمط glob لتحقيق أفضل أداء للقراءة. أما الإصدارات الأحدث فأصبحت تُنفّذ التنزيلات على التوازي داخل الملف الواحد. - في الحالات التي يكون فيها عدد الخيوط منخفضًا، قد تستفيد من ضبط
remote_filesystem_read_methodعلى “read” لفرض القراءة المتزامنة للملفات من S3. - بالنسبة إلى الدالة
s3والجدول، يتحدد التنزيل المتوازي للملف الواحد بحسب قيمmax_download_threadsوmax_download_buffer_size. وبينما يتحكمmax_download_threadsفي عدد الخيوط المستخدمة، فلن تُنزَّل الملفات على التوازي إلا إذا كان حجمها أكبر من 2 *max_download_buffer_size. افتراضيًا، تُضبط قيمةmax_download_buffer_sizeعلى 10MiB. وفي بعض الحالات، يمكنك زيادة حجم هذه الذاكرة المؤقتة بأمان إلى 50 MB (max_download_buffer_size=52428800) بهدف ضمان تنزيل الملفات الأصغر بواسطة خيط واحد فقط. ويمكن أن يقلل ذلك من الوقت الذي يقضيه كل خيط في إجراء استدعاءات إلى S3، وبالتالي يخفض أيضًا وقت انتظار S3. راجع هذه التدوينة للاطلاع على مثال على ذلك.
system.query_log.
بالنظر إلى استعلامنا السابق، فإن مضاعفة max_threads إلى 16 (القيمة الافتراضية لـ max_thread هي عدد الأنوية على العقدة) تحسن أداء استعلام القراءة بمقدار الضعف مقابل زيادة استهلاك الذاكرة. أما زيادة max_threads إلى ما بعد ذلك فتؤدي إلى عوائد متناقصة، كما هو موضح.
ضبط الخيوط وحجم الكتلة لعمليات الإدراج
insert block size و(2) مستوى مناسب من insert parallelism استنادًا إلى (3) عدد أنوية CPU وكمية RAM المتاحة. باختصار:
- كلما زاد حجم كتلة الإدراج الذي نُعدّه، قلّ عدد الأجزاء التي يحتاج ClickHouse إلى إنشائها، وقلّت عمليات I/O لملفات القرص وعمليات الدمج في الخلفية المطلوبة.
- كلما زاد عدد خيوط الإدراج المتوازية، زادت سرعة معالجة البيانات.
CPU ومساحة الذاكرة من خيوط الدمج في الخلفية.
للاطلاع على وصف تفصيلي لكيفية تأثير سلوك هذه المعلمات في الأداء والموارد، نوصي بقراءة هذه التدوينة. وكما هو موضح في هذه التدوينة، قد يتطلب الضبط موازنة دقيقة بين هذين المعلمَين. ونظرًا لأن هذا الاختبار الشامل يكون غير عملي في كثير من الأحيان، فنوصي باختصار بما يلي:
min_insert_block_size_rows على 0 (لتعطيل العتبة المستندة إلى الصفوف)، مع ضبط max_insert_threads على القيمة المختارة وmin_insert_block_size_bytes على النتيجة المحسوبة من الصيغة أعلاه.
وباستخدام هذه الصيغة مع مثال Stack Overflow السابق:
max_insert_threads=4(8 أنوية لكل عقدة)peak_memory_usage_in_bytes- 32 GiB (100% من موارد العقدة) أو34359738368بايت.min_insert_block_size_bytes=34359738368/(3*4) = 2863311530
33%. ونترك للقارئ اختبار ما إذا كان بإمكانه تحسين أداء العقدة الواحدة بدرجة أكبر.
التوسّع عبر الموارد والعُقد
التوسّع الرأسي
قد تُشكّل العقد الفردية أيضًا عنق زجاجة بسبب الشبكة وطلبات GET من S3، مما يمنع تحقّق توسّع خطي في الأداء عند التوسّع الرأسي.
التوسّع الأفقي
s3Cluster كما هو موضح في استخدام العناقيد. يتيح ذلك توزيع عمليات القراءة عبر العُقد.
يقوم الخادم الذي يتلقى استعلام الإدراج أولًا بتفسير نمط glob، ثم يوزّع معالجة كل ملف مطابق ديناميكيًا بينه وبين الخوادم الأخرى.
نكرر استعلام القراءة السابق مع توزيع عبء العمل عبر 3 عُقد، مع تعديل الاستعلام لاستخدام s3Cluster. ويتم ذلك تلقائيًا في ClickHouse Cloud، من خلال الإشارة إلى العنقود default.
كما هو مذكور في استخدام العناقيد، يُوزَّع هذا العمل على مستوى الملفات. وللاستفادة من هذه الميزة، ستحتاج إلى عدد كافٍ من الملفات، أي عدد لا يقل عن > عدد العُقد.
s3Cluster، فإن عمليات الإدراج تتم على العقدة المُبادِرة. وهذا يعني أنه في حين تُنفَّذ عمليات القراءة على كل عقدة، تُوجَّه الصفوف الناتجة إلى العقدة المُبادِرة لتوزيعها. وفي سيناريوهات الإنتاجية العالية، قد يصبح هذا عنق زجاجة. ولمعالجة ذلك، اضبط المعلمة parallel_distributed_insert_select للدالة s3cluster.
يضمن ضبطها على parallel_distributed_insert_select=2 تنفيذ SELECT وINSERT على كل جزء من/إلى الجدول الأساسي لمحرك Distributed على كل عقدة.
مزيد من الضبط
تعطيل إزالة التكرار
INSERT INTO SELECT من تخزين الكائنات. ومن خلال تعطيل هذه الوظيفة وقت الإدراج، يمكننا تحسين الأداء كما هو موضح أدناه:
التحسين عند الإدراج
optimize_on_insert في ما إذا كانت data parts تُدمج أثناء عملية الإدراج. عند تفعيله (حيث تكون القيمة الافتراضية optimize_on_insert = 1)، تُدمج الأجزاء الصغيرة في أجزاء أكبر أثناء إدراجها، مما يحسّن query performance عبر تقليل عدد الأجزاء التي يلزم قراءتها. ومع ذلك، يضيف هذا الدمج عبئًا إضافيًا إلى عملية الإدراج، وقد يؤدي إلى إبطاء عمليات الإدراج عالية الإنتاجية.
يؤدي تعطيل هذا الإعداد (optimize_on_insert = 0) إلى تخطي الدمج أثناء عمليات الإدراج، مما يتيح كتابة البيانات بسرعة أكبر، خاصةً عند التعامل مع عمليات إدراج صغيرة ومتكررة. وتُؤجَّل عملية الدمج إلى الخلفية، مما يتيح أداءً أفضل لعمليات الإدراج، لكنه يزيد مؤقتًا من عدد الأجزاء الصغيرة، وهو ما قد يبطئ الاستعلامات إلى أن يكتمل الدمج في الخلفية. ويُعد هذا الإعداد مثاليًا عندما تكون أولوية الأداء لعمليات الإدراج، ويمكن لعملية الدمج في الخلفية أن تتولى التحسين بكفاءة لاحقًا. كما هو موضح أدناه، يمكن أن يؤدي تعطيل هذا الإعداد إلى تحسين إنتاجية الإدراج:
ملاحظات متفرقة
- في حالات انخفاض الذاكرة، فكّر في خفض
max_insert_delayed_streams_for_parallel_writeإذا كنت تُدرِج البيانات في S3.