لا يُنصح بإرسال عدد كبير من الدفعات الصغيرة في الوضع المتزامن، لأن ذلك يؤدي إلى إنشاء عدد كبير من الأجزاء. وينتج عن ذلك ضعف في أداء الاستعلامات وظهور أخطاء “عدد كبير جدًا من الأجزاء”.
async_insert.
تدعم عمليات الإدراج غير المتزامنة كلًّا من واجهتَي HTTP وnative TCP.
عند التفعيل (async_insert = 1)، تُخزَّن عمليات الإدراج مؤقتًا ولا تُكتب إلى القرص إلا عند تحقق أحد شروط التفريغ التالية:
- يصل المخزن المؤقت إلى حجم بيانات محدد (
async_insert_max_data_size، والقيمة الافتراضية 100 MiB). - انقضاء حد زمني (
async_insert_busy_timeout_ms، والقيمة الافتراضية 200 ms أو 1000 ms على Cloud). - تراكم عدد أقصى من استعلامات insert (
async_insert_max_query_number، والقيمة الافتراضية 450).
اختيار وضع الإرجاع
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.
عمليات الإدراج غير المتزامنة التكيفية
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)، إذ إن المهلة الثابتة المرتفعة ستجبر العميل على الانتظار طوال الفاصل الزمني الكامل حتى عندما تكون البيانات جاهزة للتفريغ.
معالجة الأخطاء
wait_for_async_insert=1)، يُعاد الخطأ إلى العميل. أما في وضع fire-and-forget، فتُسجَّل الأخطاء في سجلات الخادم وفي جدول system.asynchronous_inserts.
ينشئ كل تفريغ جزءًا واحدًا على الأقل لكل قيمة مميزة لمفتاح partition في المخزن المؤقت. وحتى في الجداول التي لا تحتوي على مفتاح partition، يمكن لعملية تفريغ واحدة أن تُنتج عدة أجزاء إذا تجاوزت البيانات المخزنة مؤقتًا max_insert_block_size (الافتراضي نحو مليون صف).
على الرغم من استخدام async inserts، فقد تظل تواجه أخطاء “too many parts” إذا كان مفتاح partitioning ذا كاردينالية عالية.
إزالة التكرار والموثوقية
تمكين عمليات الإدراج غير المتزامنة
-
تمكين عمليات الإدراج غير المتزامنة على مستوى المستخدم. يستخدم هذا المثال المستخدم
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.