يشكّل إدخال البيانات بكفاءة الأساس لعمليات نشر ClickHouse عالية الأداء. ويمكن أن يؤثر اختيار استراتيجية الإدراج المناسبة بشكل كبير في معدل النقل والتكلفة والموثوقية. يوضّح هذا القسم أفضل الممارسات والمفاضلات وخيارات الإعداد لمساعدتك على اتخاذ القرار المناسب لعبء العمل لديك.
يفترض ما يلي أنك تُرسل البيانات إلى ClickHouse عبر عميل. وإذا كنت تسحب البيانات إلى ClickHouse، على سبيل المثال باستخدام دوال الجداول المضمّنة مثل s3 وgcs، فنوصي بالاطلاع على دليلنا “تحسين أداء الإدراج والقراءة لـ S3”.
عمليات الإدراج المتزامنة افتراضيًا
تكون عمليات الإدراج في ClickHouse متزامنة افتراضيًا. ينشئ كل استعلام insert فورًا جزء تخزين على القرص، بما في ذلك البيانات الوصفية والفهارس.
استخدم عمليات الإدراج المتزامنة إذا كان بإمكانك تجميع البيانات على جهة العميلإذا لم يكن ذلك ممكنًا، فراجع عمليات الإدراج غير المتزامنة أدناه.
نستعرض بإيجاز آلية الإدراج في MergeTree في ClickHouse أدناه:
لتحقيق أفضل أداء، يجب ① تجميع البيانات في دفعات، ما يجعل حجم الدفعة أول قرار يجب اتخاذه.
يخزّن ClickHouse البيانات المُدرجة على القرص، مرتبة وفق أعمدة المفتاح الأساسي للجدول. ويتمثل القرار الثاني في ② فرز البيانات مسبقًا قبل إرسالها إلى الخادم من عدمه. فإذا وصلت الدفعة مرتبة مسبقًا وفق أعمدة المفتاح الأساسي، يمكن لـ ClickHouse تخطي خطوة الفرز ⑩، مما يسرّع إدخال البيانات.
إذا لم يكن للبيانات المراد إدخالها تنسيق محدد مسبقًا، فإن القرار الأساسي هو اختيار التنسيق. يدعم ClickHouse إدخال البيانات بأكثر من 70 تنسيقًا. ومع ذلك، عند استخدام العميل الخاص بسطر الأوامر في ClickHouse أو عملاء اللغات البرمجية، غالبًا ما يُحسم هذا الاختيار تلقائيًا. وعند الحاجة، يمكن أيضًا تجاوز هذا الاختيار التلقائي صراحةً.
القرار الأساسي التالي هو ④ ما إذا كان ينبغي ضغط البيانات قبل إرسالها إلى خادم ClickHouse. يقلل الضغط من حجم البيانات المنقولة ويحسّن كفاءة الشبكة، مما يؤدي إلى نقل أسرع للبيانات واستهلاك أقل لعرض النطاق، خاصةً مع مجموعات البيانات الكبيرة.
تُرسَل البيانات ⑤ إلى إحدى واجهات شبكة ClickHouse — إما الواجهة الأصلية أو واجهة HTTP (واللتين نقارنهما لاحقًا في هذه المقالة).
بعد ⑥ استلام البيانات، يفك ClickHouse ⑦ ضغطها إذا كان قد استُخدم الضغط، ثم ⑧ يحلّلها انطلاقًا من التنسيق الذي أُرسلت به أصلًا.
وباستخدام القيم الواردة في تلك البيانات المنسّقة وتعليمة DDL الخاصة بالجدول الهدف، ينشئ ClickHouse ⑨ كتلة داخل الذاكرة بصيغة MergeTree، و⑩ يرتّب الصفوف حسب أعمدة المفتاح الأساسي إذا لم تكن مرتبة مسبقًا، و⑪ ينشئ فهرسًا أساسيًا متناثرًا، و⑫ يطبّق ضغطًا لكل عمود، و⑬ يكتب البيانات إلى القرص باعتبارها ⑭ جزء بيانات جديدًا.
عمليات الإدراج على دفعات في الوضع المتزامن
توضّح الآليات المذكورة أعلاه وجود تكلفة إضافية ثابتة بغضّ النظر عن حجم الإدخال، مما يجعل حجم الدفعة العامل الأهم لتحسين معدل استيعاب البيانات. ويؤدي تجميع عمليات الإدخال في دفعات إلى تقليل هذه التكلفة كنسبة من إجمالي وقت الإدخال وتحسين كفاءة المعالجة.
نوصي بإدخال البيانات في دفعات لا تقل عن 1,000 صف، ومن الأفضل أن تتراوح بين 10,000 و100,000 صف. فالإدخالات الأقل عددًا والأكبر حجمًا تقلّل عدد الأجزاء المكتوبة، وتخفّف عبء الدمج، وتقلّل الاستخدام الإجمالي لموارد النظام.
لكي تكون استراتيجية الإدخال المتزامن فعّالة، فإن هذا التجميع على جانب العميل مطلوب.
إذا لم تتمكن من تجميع البيانات على جانب العميل، فإن ClickHouse يدعم الإدخالات غير المتزامنة التي تنقل عملية التجميع إلى الخادم (راجع الإدخالات غير المتزامنة).
بغضّ النظر عن حجم عمليات الإدخال لديك، نوصي بالإبقاء على عدد استعلامات الإدخال في حدود استعلام إدخال واحد تقريبًا في الثانية. ويعود سبب هذه التوصية إلى أن الأجزاء التي يتم إنشاؤها تُدمج في الخلفية لتكوين أجزاء أكبر (بهدف تحسين بياناتك لاستعلامات القراءة)، وقد يؤدي إرسال عدد كبير جدًا من استعلامات الإدخال في الثانية إلى حالات لا تتمكن فيها عمليات الدمج الخلفية من مجاراة عدد الأجزاء الجديدة. ومع ذلك، يمكنك استخدام معدل أعلى من استعلامات الإدخال في الثانية عند استخدام الإدخالات غير المتزامنة (راجع الإدخالات غير المتزامنة).
ضمان إعادة المحاولة دون أثر إضافي
تتميّز عمليات الإدراج المتزامنة أيضًا بأنها لا تُحدث أثرًا إضافيًا عند تكرارها. عند استخدام محركات MergeTree، يُزيل ClickHouse التكرار من عمليات الإدراج افتراضيًا. وهذا يوفّر حماية من حالات الفشل غير الواضحة، مثل:
- نجحت عملية الإدراج، لكن العميل لم يتلقَّ تأكيدًا بسبب انقطاع في الشبكة.
- فشلت عملية الإدراج على جهة الخادم وانتهت المهلة الزمنية.
في كلتا الحالتين، من الآمن إعادة محاولة الإدراج — ما دامت محتويات الدفعة وترتيبها متطابقين. ولهذا السبب، من الضروري أن يعيد العميل المحاولة بصورة متسقة، من دون تعديل البيانات أو إعادة ترتيبها.
بالنسبة إلى الـ clusters المقسّمة إلى shards، لديك خياران:
- نفّذ الإدراج مباشرةً في جدول MergeTree أو ReplicatedMergeTree. هذا هو الخيار الأكثر كفاءة عندما يكون العميل قادرًا على تنفيذ موازنة الحمل عبر الـ shards. عند استخدام
internal_replication = true، يتولى ClickHouse النسخ المتماثل بشفافية.
- نفّذ الإدراج في جدول Distributed. يتيح ذلك للعملاء إرسال البيانات إلى أي عقدة وترك ClickHouse يمررها إلى الـ shard الصحيح. هذا أبسط، لكنه أقل أداءً قليلًا بسبب خطوة التمرير الإضافية. ولا يزال
internal_replication = true موصى به.
في ClickHouse Cloud، تقرأ جميع العقد وتكتب إلى الـ shard الواحد نفسه. تتم موازنة عمليات الإدراج تلقائيًا عبر العقد. يمكنك ببساطة إرسال عمليات الإدراج إلى نقطة النهاية المتاحة.
يُعد اختيار تنسيق الإدخال المناسب أمرًا بالغ الأهمية لتحقيق كفاءة إدخال البيانات في ClickHouse. ومع توفّر أكثر من 70 تنسيقًا مدعومًا، فإن اختيار الخيار الأفضل أداءً يمكن أن يؤثر بشكل كبير في سرعة insert واستخدام CPU والذاكرة والكفاءة العامة للنظام.
ومع أن المرونة مفيدة في هندسة البيانات وعمليات الاستيراد المعتمدة على الملفات، ينبغي للتطبيقات إعطاء الأولوية للتنسيقات المحسّنة للأداء:
- Native format (موصى به): الأكثر كفاءة. تنسيق عمودي، ويتطلب حدًا أدنى من التحليل على الخادم. ويُستخدم افتراضيًا في عميلَي Go وPython.
- RowBinary: تنسيق فعّال قائم على الصفوف، وهو مثالي إذا كان التحويل إلى تنسيق عمودي صعبًا من جهة العميل. ويستخدمه عميل Java.
- JSONEachRow: سهل الاستخدام، لكنه مكلف من حيث التحليل. مناسب لحالات الاستخدام منخفضة الحجم أو لعمليات التكامل السريعة.
يلعب الضغط دورًا أساسيًا في تقليل الحمل الزائد على الشبكة، وتسريع عمليات الإدراج، وخفض تكاليف التخزين في ClickHouse. وعند استخدامه بفعالية، فإنه يحسّن أداء إدخال البيانات من دون الحاجة إلى تغيير format البيانات أو schema.
يؤدي ضغط بيانات الإدراج إلى تقليل حجم الحمولة المرسلة عبر الشبكة، مما يحدّ من استهلاك النطاق الترددي ويُسرّع عملية النقل.
في عمليات الإدراج، يكون الضغط فعّالًا بشكل خاص عند استخدامه مع Native format، لأنه يتوافق أصلًا مع نموذج التخزين العمودي الداخلي في ClickHouse. وفي هذا الإعداد، يمكن للخادم فك ضغط البيانات وتخزينها مباشرةً بكفاءة مع حدّ أدنى من التحويل.
استخدم LZ4 للسرعة، وZSTD لنسبة الضغط
يدعم ClickHouse عدة codecs للضغط أثناء نقل البيانات. وهناك خياران شائعان:
- LZ4: سريع وخفيف. يقلّل حجم البيانات بدرجة كبيرة مع حد أدنى من الحمل الإضافي على CPU، ما يجعله مثاليًا لعمليات الإدراج عالية الإنتاجية، وهو الخيار الافتراضي في معظم عملاء ClickHouse.
- ZSTD: يوفّر نسبة ضغط أعلى، لكنه يستهلك CPU أكثر. ويكون مفيدًا عندما تكون تكاليف نقل البيانات عبر الشبكة مرتفعة — مثل سيناريوهات العمل عبر المناطق أو لدى موفري الخدمات السحابية — لكنه يزيد قليلًا من متطلبات المعالجة على جهة العميل ووقت فك الضغط على جهة الخادم.
أفضل الممارسات: استخدم LZ4 ما لم يكن عرض النطاق الترددي لديك محدودًا أو كنت تتحمّل تكاليف خروج البيانات — عندها فكّر في استخدام ZSTD.
في اختبارات FastFormats benchmark، قلّصت عمليات الإدراج بصيغة Native والمضغوطة باستخدام LZ4 حجم البيانات بأكثر من 50%، ما خفّض وقت إدخال البيانات من 150 ثانية إلى 131 ثانية لمجموعة بيانات بحجم 5.6 GiB. وعند التبديل إلى ZSTD، انخفض حجم مجموعة البيانات نفسها إلى 1.69 GiB، لكن وقت المعالجة على جهة الخادم ارتفع قليلًا.
يقلّل الضغط من استخدام الموارد
لا يقتصر الضغط على تقليل حركة مرور الشبكة فحسب، بل يحسّن أيضًا كفاءة CPU والذاكرة على الخادم. ومع البيانات المضغوطة، يستقبل ClickHouse عددًا أقل من البايتات ويقضي وقتًا أقل في تحليل المدخلات الكبيرة. وتبرز أهمية هذه الفائدة خصوصًا عند استيعاب البيانات من عدة عملاء متزامنين، كما في سيناريوهات observability.
يكون تأثير الضغط على CPU والذاكرة محدودًا مع LZ4، ومتوسطًا مع ZSTD. وحتى تحت الحمل، تتحسن الكفاءة على جهة الخادم بسبب انخفاض حجم البيانات.
إن الجمع بين الضغط والتجميع على دفعات وتنسيق إدخال فعّال (مثل Native) يحقق أفضل أداء لاستيعاب البيانات.
عند استخدام الواجهة الأصلية (على سبيل المثال clickhouse-client)، يكون ضغط LZ4 مفعّلًا افتراضيًا. ويمكنك اختياريًا التبديل إلى ZSTD عبر الإعدادات.
مع واجهة HTTP، استخدم ترويسة Content-Encoding لتطبيق الضغط (على سبيل المثال: Content-Encoding: lz4). يجب ضغط الحمولة بالكامل قبل إرسالها.
الفرز المسبق إذا كانت تكلفته منخفضة
يمكن أن يؤدي فرز البيانات مسبقًا حسب المفتاح الأساسي قبل الإدراج إلى تحسين كفاءة إدخال البيانات في ClickHouse، خصوصًا مع الدُفعات الكبيرة.
عندما تصل البيانات مفروزة مسبقًا، يمكن لـ ClickHouse تخطي خطوة الفرز الداخلية أو تبسيطها أثناء إنشاء الجزء، مما يقلل من استخدام CPU ويُسرّع عملية الإدراج. كما يحسّن الفرز المسبق كفاءة الضغط، لأن القيم المتشابهة تُجمع معًا، ما يتيح لبرامج الضغط مثل LZ4 أو ZSTD تحقيق نسبة ضغط أفضل. ويكون ذلك مفيدًا بشكل خاص عند دمجه مع عمليات الإدراج على دفعات والضغط، لأنه يقلل كلاً من عبء المعالجة الإضافي وكمية البيانات المنقولة.
ومع ذلك، يظل الفرز المسبق تحسينًا اختياريًا وليس متطلبًا. إذ يفرز ClickHouse البيانات بكفاءة عالية باستخدام المعالجة المتوازية، وفي كثير من الحالات يكون الفرز على جهة الخادم أسرع أو أكثر ملاءمة من الفرز المسبق على جهة العميل.
نوصي بالفرز المسبق فقط إذا كانت البيانات مرتبة بالفعل إلى حد كبير، أو إذا كانت الموارد على جهة العميل (CPU والذاكرة) كافية وغير مستغلة بالكامل. وفي حالات الاستخدام الحساسة لزمن الاستجابة أو ذات الإنتاجية العالية، مثل observability، حيث تصل البيانات خارج الترتيب أو من العديد من الوكلاء، يكون من الأفضل غالبًا تخطي الفرز المسبق والاعتماد على الأداء المدمج في ClickHouse.
عمليات الإدراج غير المتزامنة
توفر عمليات الإدراج غير المتزامنة في ClickHouse بديلاً فعّالاً عندما لا يكون التجميع على جانب العميل ممكنًا. وتبرز أهمية ذلك خصوصًا في أحمال عمل observability، حيث يرسل مئات أو آلاف الوكلاء البيانات باستمرار—سجلات ومقاييس وآثار تتبع—وغالبًا ضمن حمولات صغيرة ولحظية. ويؤدي تخزين البيانات مؤقتًا على جانب العميل في هذه البيئات إلى زيادة التعقيد، إذ يتطلب وجود queue مركزية لضمان إرسال دفعات كبيرة بما يكفي.
لا يُنصح بإرسال عدد كبير من الدفعات الصغيرة في الوضع المتزامن، لأن ذلك يؤدي إلى إنشاء عدد كبير من الأجزاء. وينتج عن ذلك ضعف في أداء الاستعلامات وظهور أخطاء “عدد كبير جدًا من الأجزاء”.
تنقل عمليات الإدراج غير المتزامنة مسؤولية التجميع من العميل إلى الخادم، وذلك بكتابة البيانات الواردة إلى مخزن مؤقت في الذاكرة ثم تفريغها إلى التخزين وفقًا لحدود قابلة للتهيئة. ويقلل هذا النهج بدرجة كبيرة من الكلفة الإضافية الناتجة عن إنشاء الأجزاء، ويخفض استخدام CPU، ويضمن بقاء ingestion فعّالة حتى عند ارتفاع مستويات التزامن.
يُتحكَّم في السلوك الأساسي عبر الإعداد async_insert.
تدعم عمليات الإدراج غير المتزامنة كلًّا من واجهتَي HTTP وnative TCP.
عند التفعيل (async_insert = 1)، تُخزَّن عمليات الإدراج مؤقتًا ولا تُكتب إلى القرص إلا عند تحقق أحد شروط التفريغ التالية:
وأي حد يتم بلوغه أولًا يؤدي إلى تشغيل عملية التفريغ.
تكون عملية التجميع هذه غير مرئية للعملاء، وتساعد ClickHouse على دمج حركة insert بكفاءة من مصادر متعددة. ومع ذلك، وحتى حدوث التفريغ، لا يمكن الاستعلام عن البيانات. ومن المهم ملاحظة وجود عدة مخازن مؤقتة لكل تركيبة من شكل insert والإعدادات، وفي clusters، تُحفَظ هذه المخازن لكل عقدة على حدة—مما يتيح تحكمًا دقيقًا في البيئات متعددة المستأجرين. وبخلاف ذلك، تبقى آليات insert مطابقة لما هو موصوف في عمليات الإدراج المتزامنة.
يمكن ضبط سلوك عمليات الإدراج غير المتزامنة بمزيد من الدقة باستخدام الإعداد wait_for_async_insert.
عند ضبطه على 1 (وهو الإعداد الافتراضي)، لا يؤكد ClickHouse عملية insert إلا بعد تفريغ البيانات إلى disk بنجاح. ويضمن ذلك مستوىً قويًا من استمرارية البيانات، كما يجعل التعامل مع error مباشرًا: فإذا حدث خطأ أثناء الـ تفريغ، يُعاد هذا error إلى client. ويُنصح بهذا الوضع في معظم سيناريوهات production، خاصةً عندما يكون من الضروري تتبّع حالات فشل insert بشكل موثوق.
تُظهر المقارنات المعيارية أنه يتوسع جيدًا مع Concurrency، سواء كنت تشغّل 200 أو 500 client، وذلك بفضل inserts التكيفية والسلوك المستقر في إنشاء جزء.
يؤدي ضبط wait_for_async_insert = 0 إلى تفعيل وضع “fire-and-forget”. في هذا الوضع، يؤكد server عملية insert بمجرد تخزين البيانات في مخزن مؤقت، من دون انتظار وصولها إلى Storage.
يوفّر ذلك عمليات insert بزمن latency منخفض جدًا وأقصى throughput، ما يجعله مثاليًا للبيانات عالية التدفق ومنخفضة الأهمية. لكن لهذا الوضع مفاضلاته: فلا يوجد ضمان لاستمرار حفظ البيانات، ولا تظهر الأخطاء إلا أثناء تفريغ، كما لا توجد dead-letter queue لعمليات inserts الفاشلة — ولذلك يتطلب تتبّع حالات الفشل فحص server logs وsystem tables بعد حدوثها. استخدم هذا الوضع فقط إذا كان workload لديك يمكنه تحمّل فقدان البيانات.
وتُظهر المقارنات المعيارية أيضًا انخفاضًا كبيرًا في عدد الأجزاء وتراجعًا في CPU usage عندما تكون عمليات تفريغ للـ مخزن مؤقت غير متكررة (مثلًا كل 30 Seconds)، لكن خطر الفشل الصامت يظل قائمًا.
نوصي بشدة باستخدام async_insert=1,wait_for_async_insert=1 عند استخدام عمليات الإدراج غير المتزامنة. فاستخدام wait_for_async_insert=0 ينطوي على مخاطر كبيرة جدًا، لأن INSERT client قد لا يكتشف وجود أخطاء، وقد يؤدي أيضًا إلى حمل زائد محتمل إذا واصل client الكتابة بسرعة في موقف يحتاج فيه ClickHouse server إلى إبطاء عمليات الكتابة وفرض بعض الضغط العكسي لضمان موثوقية service.
عمليات الإدراج غير المتزامنة التكيفية
اعتبارًا من الإصدار 24.2، يستخدم ClickHouse افتراضيًا مهلات تفريغ تكيفية (async_insert_use_adaptive_busy_timeout). فبدلًا من فاصل زمني ثابت للتفريغ، تُضبط المهلة ديناميكيًا بين حد أدنى (async_insert_busy_timeout_min_ms، والقيمة الافتراضية 50 مللي ثانية) وحد أقصى (async_insert_busy_timeout_max_ms، والقيمة الافتراضية 200 مللي ثانية أو 1000 مللي ثانية على Cloud) استنادًا إلى معدل البيانات الواردة.
عندما تصل البيانات بوتيرة متكررة، تبقى المهلة أقرب إلى الحد الأدنى لتفريغ البيانات بشكل أسرع وتقليل زمن الانتقال من الطرف إلى الطرف. وعندما تكون البيانات متناثرة، ترتفع المهلة باتجاه الحد الأقصى لتجميع دفعات أكبر. ويكون ذلك مفيدًا بشكل خاص في الوضع الافتراضي (wait_for_async_insert=1)، إذ إن المهلة الثابتة المرتفعة ستجبر العميل على الانتظار طوال الفاصل الزمني الكامل حتى عندما تكون البيانات جاهزة للتفريغ.
يحدث التحقق من المخطط وتحليل البيانات أثناء تفريغ المخزن المؤقت، وليس عند استلام عملية insert. إذا احتوى أي صف في استعلام insert على خطأ في التحليل أو في النوع، فلن يُفرَّغ أيٌّ من بيانات ذلك الاستعلام — بل تُرفَض حمولة الاستعلام بالكامل. في الوضع الافتراضي (wait_for_async_insert=1)، يُعاد الخطأ إلى العميل. أما في وضع fire-and-forget، فتُسجَّل الأخطاء في سجلات الخادم وفي جدول system.asynchronous_inserts.
ينشئ كل تفريغ جزءًا واحدًا على الأقل لكل قيمة مميزة لمفتاح partition في المخزن المؤقت. وحتى في الجداول التي لا تحتوي على مفتاح partition، يمكن لعملية تفريغ واحدة أن تُنتج عدة أجزاء إذا تجاوزت البيانات المخزنة مؤقتًا max_insert_block_size (الافتراضي نحو مليون صف).
على الرغم من استخدام async inserts، فقد تظل تواجه أخطاء “too many parts” إذا كان مفتاح partitioning ذا كاردينالية عالية.
بشكل افتراضي، ينفّذ ClickHouse إزالة التكرار تلقائيًا لعمليات الإدراج المتزامنة، مما يجعل إعادة المحاولة آمنة في حالات الفشل. ومع ذلك، تكون هذه الميزة معطّلة لعمليات الإدراج غير المتزامنة ما لم يتم تمكينها صراحةً (ويجب عدم تمكينها إذا كانت لديك عروض مادية تابعة — راجع المشكلة).
عمليًا، إذا كانت إزالة التكرار مفعّلة وأُعيدت محاولة عملية الإدراج نفسها — بسبب، على سبيل المثال، انتهاء المهلة أو انقطاع الشبكة — يمكن لـ ClickHouse تجاهل التكرار بأمان. يساعد ذلك في الحفاظ على خاصية idempotency وتجنّب كتابة البيانات مرتين.
تمكين عمليات الإدراج غير المتزامنة
يمكن تمكين عمليات الإدراج غير المتزامنة لمستخدم معيّن أو لاستعلام محدد:
-
تمكين عمليات الإدراج غير المتزامنة على مستوى المستخدم. يستخدم هذا المثال المستخدم
default، فإذا أنشأت مستخدمًا آخر، فاستبدل اسم المستخدم بهذا الاسم:
-
يمكنك تحديد إعدادات الإدراج غير المتزامن باستخدام عبارة SETTINGS في استعلامات
INSERT:
-
يمكنك أيضًا تحديد إعدادات الإدراج غير المتزامن كمعلمات اتصال عند استخدام عميل ClickHouse لإحدى لغات البرمجة.
على سبيل المثال، إليك كيفية تنفيذ ذلك ضمن سلسلة اتصال JDBC عند استخدام برنامج تشغيل ClickHouse Java JDBC للاتصال بـ ClickHouse Cloud:
لا تنطبق عمليات الإدراج غير المتزامنة على استعلامات INSERT INTO ... SELECT. وعندما يتضمن الإدراج عبارة SELECT، يُنفَّذ الاستعلام دائمًا بشكل متزامن بغض النظر عن الإعداد async_insert.
تفريغ المخازن المؤقتة عند إيقاف التشغيل
لتفريغ جميع مخازن async insert المؤقتة قيد الانتظار — على سبيل المثال، أثناء إيقاف تشغيلٍ منظّم أو قبل إجراء الصيانة — شغّل:
يضمن ذلك كتابة أي بيانات موجودة في الذاكرة المؤقتة إلى التخزين قبل توقف الخادم.
تُعد عمليات الإدراج غير المتزامنة البديل الحديث لـجداول Buffer. الاختلافات الرئيسية:
- لا حاجة إلى أي تغييرات في DDL. تعمل عمليات الإدراج غير المتزامنة بشفافية — إذ تفعّل إعدادًا، ولا تنشئ جداول إضافية.
- التخزين المؤقت لكل بنية. تحتفظ عمليات الإدراج غير المتزامنة بمخازن مؤقتة منفصلة لكل بنية query فريدة ولكل مجموعة إعدادات، مما يتيح سياسات تفريغ دقيقة. أما جداول Buffer فتستخدم مخزنًا مؤقتًا واحدًا لكل table مستهدفة.
- الاستمرارية. في الوضع الافتراضي (
wait_for_async_insert=1)، يتم تأكيد البيانات على القرص قبل أن يتلقى العميل الإقرار. أما جداول Buffer فتعمل بأسلوب fire-and-forget — وتُفقد البيانات المخزنة مؤقتًا عند حدوث crash.
- سلوك cluster. في clusters، تُدار مخازن عمليات الإدراج غير المتزامنة المؤقتة على مستوى كل node. وتتطلب جداول Buffer إنشاءها صراحةً على كل node.
اختر واجهة اتصال — HTTP أم الواجهة الأصلية
يوفّر ClickHouse واجهتين رئيسيتين لإدخال البيانات: الواجهة الأصلية وواجهة HTTP، ولكلٍ منهما مفاضلات بين الأداء والمرونة. الواجهة الأصلية، التي يستخدمها clickhouse-client وبعض عملاء اللغات مثل Go وC++، مُصمَّمة خصيصًا لتحقيق أعلى أداء. فهي تنقل البيانات دائمًا باستخدام تنسيق Native عالي الكفاءة الخاص بـ ClickHouse، وتدعم الضغط على مستوى block باستخدام LZ4 أو ZSTD، وتقلّل المعالجة على جهة الخادم إلى الحد الأدنى من خلال نقل مهام مثل parsing وتحويل format إلى العميل.
كما تتيح أيضًا احتساب قيم الأعمدة MATERIALIZED وDEFAULT على جهة العميل، مما يسمح للخادم بتجاوز هذه الخطوات بالكامل. وهذا يجعل الواجهة الأصلية مثالية لسيناريوهات إدخال البيانات عالية throughput حيث تكون الكفاءة عاملًا حاسمًا.
على عكس كثير من قواعد البيانات التقليدية، يدعم ClickHouse أيضًا واجهة HTTP. وفي المقابل، تُعطي هذه الواجهة الأولوية للتوافق والمرونة. فهي تتيح إرسال البيانات بأي تنسيق مدعوم—بما في ذلك JSON وCSV وParquet وغيرها—كما تحظى بدعم واسع في معظم عملاء ClickHouse، بما في ذلك Python وJava وJavaScript وRust.
وغالبًا ما يكون هذا الخيار مفضّلًا على البروتوكول الأصلي في ClickHouse لأنه يسهّل تحويل حركة المرور باستخدام موازنات التحميل. ونتوقع وجود فروق طفيفة في أداء الإدراج مع البروتوكول الأصلي، لأنه يضيف عبئًا إضافيًا أقل قليلًا.
ومع ذلك، فإنه يفتقر إلى مستوى التكامل الأعمق الذي يوفّره البروتوكول الأصلي، ولا يمكنه تنفيذ تحسينات من جهة العميل مثل حساب القيم المُجسَّدة أو التحويل التلقائي إلى تنسيق Native. ومع أن عمليات الإدراج عبر HTTP تظل قابلة للضغط باستخدام ترويسات HTTP القياسية (مثل Content-Encoding: lz4)، فإن الضغط يُطبَّق على الحمولة بالكامل بدلًا من كتل البيانات الفردية. وغالبًا ما تُفضَّل هذه الواجهة في البيئات التي تكون فيها بساطة البروتوكول، أو موازنة التحميل، أو التوافق الواسع مع التنسيقات أهم من الأداء البحت.
للاطلاع على وصف أكثر تفصيلًا لهذه الواجهات، راجع هنا.