Skip to main content
عميل Rust الرسمي للاتصال بـ ClickHouse، وقد طوّره أساسًا Paul Loyd. الشيفرة المصدرية للعميل متاحة في مستودع GitHub.

نظرة عامة

  • يستخدم serde لترميز الصفوف وفك ترميزها.
  • يدعم سمات serde: skip_serializing وskip_deserializing وrename.
  • يستخدم تنسيق RowBinary عبر نقل HTTP.
    • توجد خطط للانتقال إلى Native عبر TCP.
  • يدعم TLS (عبر ميزتَي native-tls وrustls-tls).
  • يدعم الضغط وفك الضغط (LZ4).
  • يوفّر واجهات برمجة تطبيقات للاستعلام عن البيانات أو إدراجها، وتنفيذ أوامر DDL، والتجميع على جهة العميل.
  • يوفّر كائنات محاكاة مناسبة لاختبارات الوحدة.

التثبيت

لاستخدام حزمة، أضف ما يلي إلى ملف Cargo.toml:
راجع أيضًا: صفحة crates.io.

ميزات Cargo

  • lz4 (مفعّلة افتراضيًا) — تفعّل البديلين Compression::Lz4 وCompression::Lz4Hc(_). وإذا كانت مفعّلة، فسيُستخدم Compression::Lz4 افتراضيًا في جميع الاستعلامات باستثناء WATCH.
  • native-tls — تدعم عناوين URL ذات مخطط HTTPS عبر hyper-tls، والذي يرتبط بـ OpenSSL.
  • rustls-tls — تدعم عناوين URL ذات مخطط HTTPS عبر hyper-rustls، والذي لا يرتبط بـ OpenSSL.
  • inserter — تفعّل client.inserter().
  • test-util — تضيف mocks. راجع المثال. استخدمها فقط في dev-dependencies.
  • watch — تفعّل وظيفة client.watch. راجع القسم المقابل لمزيد من التفاصيل.
  • uuid — تضيف serde::uuid للعمل مع حزمة ‏uuid.
  • time — تضيف serde::time للعمل مع حزمة ‏time.
عند الاتصال بـ ClickHouse عبر عنوان URL يستخدم HTTPS، يجب تفعيل إحدى الميزتين native-tls أو rustls-tls. إذا كانت كلتاهما مفعّلتين، فستكون الأسبقية لميزة rustls-tls.

توافق إصدارات ClickHouse

العميل متوافق مع إصدارات LTS أو الأحدث من ClickHouse، وكذلك مع ClickHouse Cloud. يتعامل خادم ClickHouse الأقدم من v22.6 مع RowBinary بشكل غير صحيح في بعض الحالات النادرة. يمكنك استخدام v0.11+ وتمكين الميزة wa-37420 لحل هذه المشكلة. ملاحظة: لا ينبغي استخدام هذه الميزة مع إصدارات ClickHouse الأحدث.

أمثلة

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

الاستخدام

تُعد حزمة ch2rs مفيدة لتوليد نوع يمثّل صفًا من ClickHouse.

إنشاء مثيل للعميل

أعِد استخدام العملاء الذين أنشأتهم أو استنسخهم لإعادة استخدام مجمّع اتصالات hyper الأساسي.

اتصال عبر HTTPS أو ClickHouse Cloud

يعمل HTTPS مع ميزتَي Cargo rustls-tls أو native-tls. بعد ذلك، أنشئ عميل كالمعتاد. في هذا المثال، تُستخدَم متغيرات البيئة لتخزين تفاصيل الاتصال:
يجب أن يتضمّن URL كلاً من البروتوكول والمنفذ، على سبيل المثال: https://instance.clickhouse.cloud:8443.
انظر أيضًا:

تحديد الصفوف

  • يُستبدل العنصر النائب ?fields بـ no, name (حقول Row).
  • يُستبدل العنصر النائب ? بالقيم في استدعاءات bind() اللاحقة.
  • يمكن استخدام الطريقتين المناسبتين fetch_one::<Row>() وfetch_all::<Row>() للحصول على الصف الأول أو جميع الصفوف، على الترتيب.
  • يمكن استخدام sql::Identifier لربط أسماء الجداول.
ملاحظة: بما أن الاستجابة تُرسل بالكامل على شكل تدفق، فقد تُرجِع المؤشرات خطأ حتى بعد إرجاع بعض الصفوف. إذا حدث ذلك في حالة الاستخدام لديك، فيمكنك تجربة query(...).with_option("wait_end_of_query", "1") لتمكين تخزين الاستجابة مؤقتًا على جهة الخادم. مزيد من التفاصيل. وقد يكون الخيار buffer_size مفيدًا أيضًا.
استخدم wait_end_of_query بحذر عند تحديد الصفوف، إذ قد يؤدي ذلك إلى زيادة استهلاك الذاكرة على جانب الخادم، ومن المرجح أن يقلل من الأداء العام.

إدراج الصفوف

  • إذا لم يتم استدعاء end()، فسيتم إلغاء INSERT.
  • تُرسَل الصفوف تدريجيًا على شكل تدفّق لتوزيع حمل الشبكة.
  • يُدرِج ClickHouse الدُفعات بصورة ذرّية فقط إذا كانت جميع الصفوف تقع ضمن partition نفسها وكان عددها أقل من max_insert_block_size.

الإدراج غير المتزامن (التجميع من جهة الخادم)

يمكنك استخدام عمليات الإدراج غير المتزامن في ClickHouse لتجنب تجميع البيانات الواردة من جهة العميل. ويمكنك القيام بذلك ببساطة عبر تمرير الخيار async_insert إلى الدالة insert (أو حتى إلى مثيل Client نفسه، بحيث يسري ذلك على جميع استدعاءات insert).
راجع أيضًا:

ميزة Inserter (التجميع على جهة العميل)

يتطلب ذلك تفعيل ميزة inserter في Cargo.
  • ينهي Inserter عملية الإدراج النشطة في commit() إذا تم بلوغ أيٍّ من العتبات (max_bytes، max_rows، period).
  • يمكن إزاحة الفاصل الزمني بين إنهاء أوامر INSERT النشطة باستخدام with_period_bias لتجنّب ارتفاعات الحمل الناتجة عن أدوات الإدراج المتوازية.
  • يمكن استخدام Inserter::time_left() لاكتشاف موعد انتهاء الفترة الحالية. استدعِ Inserter::commit() مرة أخرى للتحقق من الحدود إذا كان التدفق يُصدر العناصر بوتيرة متباعدة.
  • تُنفَّذ العتبات الزمنية باستخدام حزمة ‏quanta لتسريع inserter. ولا يُستخدم ذلك إذا كان test-util مُمكّنًا (وبالتالي يمكن التحكم في الوقت عبر tokio::time::advance() في الاختبارات المخصّصة).
  • تُدرَج جميع الصفوف بين استدعاءات commit() ضمن عبارة INSERT نفسها.
لا تنسَ تنفيذ flush إذا كنت تريد إنهاء عملية الإدراج/إتمامها:

تنفيذ DDLs

في النشر أحادي العقدة، يكفي تنفيذ DDLs كما يلي:
ومع ذلك، في عمليات النشر العنقودية التي تستخدم موازن تحميل أو ClickHouse Cloud، يُوصى بانتظار تطبيق DDL على جميع النسخ المتماثلة باستخدام الخيار wait_end_of_query. ويمكن إجراء ذلك على النحو التالي:

إعدادات ClickHouse

يمكنك تطبيق إعدادات ClickHouse المختلفة باستخدام الطريقة with_option. على سبيل المثال:
إلى جانب query، يعمل الأمر بالطريقة نفسها مع الطريقتين insert وinserter؛ بالإضافة إلى ذلك، يمكن استدعاء الطريقة نفسها على مثيل Client لضبط إعدادات عامة لجميع الاستعلامات.

معرّف الاستعلام

باستخدام .with_option، يمكنك تعيين الخيار query_id لتمييز الاستعلامات في سجل استعلامات ClickHouse.
إلى جانب query، يعمل الأمر بالمثل مع طريقتَي insert وinserter.
إذا عيّنت query_id يدويًا، فتأكد من أنه فريد. تُعد معرّفات UUID خيارًا جيدًا لهذا الغرض.
انظر أيضًا: مثال query_id في مستودع العميل.

معرّف الجلسة

على غرار query_id، يمكنك تعيين session_id لتنفيذ التعليمات ضمن الجلسة نفسها. ويمكن تعيين session_id إما على مستوى العميل بشكل عام، أو لكل استدعاء query أو insert أو inserter على حدة.
في عمليات النشر العنقودية، ونظرًا لعدم وجود “جلسات مثبتة”، تحتاج إلى الاتصال بـ عقدة معيّنة في العنقود لكي تتمكن من استخدام هذه الميزة بشكل صحيح، لأن موازن التحميل بنظام round-robin، على سبيل المثال، لا يضمن أن الطلبات اللاحقة ستُعالَج على عقدة ClickHouse نفسها.
راجع أيضًا: مثال session_id في مستودع العميل.

رؤوس HTTP مخصصة

إذا كنت تستخدم المصادقة عبر proxy أو تحتاج إلى تمرير رؤوس مخصصة، فيمكنك القيام بذلك كما يلي:
راجع أيضًا: مثال على رؤوس HTTP مخصصة في مستودع مكتبة عميل.

عميل HTTP مخصّص

قد يكون هذا مفيدًا لتعديل إعدادات مجمّع اتصالات HTTP الأساسي.
يعتمد هذا المثال على واجهة برمجة تطبيقات Hyper القديمة، وهو قابل للتغيير مستقبلًا.
انظر أيضًا: مثال على عميل HTTP مخصص في مستودع مكتبة عميل.

أنواع البيانات

  • يقابل (U)Int(8|16|32|64|128) في التحويل من/إلى الأنواع المناظرة (u|i)(8|16|32|64|128) أو newtypes المبنية عليها.
  • لا يتوفر دعم مباشر لـ (U)Int256، ولكن يوجد حل بديل لذلك.
  • يقابل Float(32|64) في التحويل من/إلى f(32|64) المناظرة أو newtypes المبنية عليها.
  • يقابل Decimal(32|64|128) في التحويل من/إلى i(32|64|128) المناظرة أو newtypes المبنية عليها. ويكون استخدام fixnum أو أي تنفيذ آخر للأعداد العشرية الثابتة ذات الإشارة أكثر ملاءمة.
  • يقابل Boolean في التحويل من/إلى bool أو newtypes المبنية عليه.
  • يقابل String في التحويل من/إلى أي نوع من أنواع السلاسل النصية أو البايتات، مثل &str و&[u8] وString وVec<u8> أو SmartString. كما أن الأنواع الجديدة مدعومة أيضًا. ولتخزين البايتات، يُنصح باستخدام serde_bytes، لأنه أكثر كفاءة.
  • النوع FixedString(N) مدعوم على هيئة مصفوفة من البايتات، مثل [u8; N].
  • يُدعَم Enum(8|16) باستخدام serde_repr.
  • يُحوَّل UUID من/إلى uuid::Uuid باستخدام serde::uuid. ويتطلب ذلك الميزة uuid.
  • يقابل IPv6 النوع std::net::Ipv6Addr ذهابًا وإيابًا.
  • يقابل IPv4 النوع std::net::Ipv4Addr ذهابًا وإيابًا باستخدام serde::ipv4.
  • يُحوَّل Date من/إلى u16 أو إلى نوعٍ من نمط newtype مبنيّ عليه، ويمثّل عدد الأيام المنقضية منذ 1970-01-01. كما أن time::Date مدعوم أيضًا باستخدام serde::time::date، وهذا يتطلب الميزة time.
  • يُحوَّل Date32 من/إلى i32 أو newtype يلتف حوله، ويمثل عدد الأيام المنقضية منذ 1970-01-01. كما أن time::Date مدعوم عند استخدام serde::time::date32، وهذا يتطلب الميزة time.
  • يُحوَّل DateTime من وإلى u32 أو newtype مبني عليه، ويمثل عدد الثواني المنقضية منذ حقبة Unix. كما أن time::OffsetDateTime مدعوم أيضًا باستخدام serde::time::datetime، ويتطلب ذلك تفعيل ميزة time.
  • يُربَط DateTime64(_) مع/من i32 أو مع newtype يغلّفه، ويمثل زمنًا منقضيًا منذ حقبة UNIX. كما أن time::OffsetDateTime مدعوم أيضًا باستخدام serde::time::datetime64::*، وهذا يتطلب تفعيل الميزة time.
  • Tuple(A, B, ...) يقابل ذهابًا وإيابًا (A, B, ...) أو newtype يغلّفه.
  • Array(_) يقابل ذهابًا وإيابًا أي slice، مثل Vec<_> و&[_]. كما أن الأنواع الجديدة مدعومة أيضًا.
  • Map(K, V) يتعامل مثل Array((K, V)).
  • LowCardinality(_) مدعوم بسلاسة.
  • Nullable(_) يقابل ذهابًا وإيابًا Option<_>. وبالنسبة إلى الدوال المساعدة clickhouse::serde::*، أضِف ::option.
  • يُدعَم Nested عبر توفير عدة مصفوفات مع إعادة تسميتها.
  • الأنواع Geo مدعومة. ويعمل Point مثل زوجٍ مرتب (f64, f64)، أما بقية الأنواع فهي مجرد تسلسلات من النقاط.
  • لا تزال أنواع البيانات Variant وDynamic وJSON (النوع الجديد) غير مدعومة بعد.

المحاكاة

توفر الحزمة أدوات مساعدة لمحاكاة خادم CH واختبار استعلامات DDL وSELECT وINSERT وWATCH. ويمكن تمكين هذه الوظيفة باستخدام الميزة test-util. استخدمها فقط كاعتماد تطويري. راجع المثال.

استكشاف الأخطاء وإصلاحها

CANNOT_READ_ALL_DATA

السبب الأكثر شيوعًا لخطأ CANNOT_READ_ALL_DATA هو أن تعريف الصف في جهة التطبيق لا يطابق التعريف في ClickHouse. لننظر إلى الجدول التالي:
ثم، إذا كان EventLog مُعرَّفًا في التطبيق بأنواع غير متطابقة، على سبيل المثال:
عند إدراج البيانات، قد يحدث الخطأ التالي:
في هذا المثال، يُحَلّ ذلك بالتعريف الصحيح للبنية EventLog:

القيود المعروفة

  • أنواع البيانات Variant وDynamic وJSON (الجديدة) غير مدعومة حتى الآن.
  • ربط المعلّمات على جهة الخادم غير مدعوم حتى الآن؛ راجع هذه التذكرة لمتابعة الحالة.

تواصل معنا

إذا كانت لديك أي أسئلة أو كنت بحاجة إلى مساعدة، فلا تتردد في التواصل معنا عبر Slack الخاص بالمجتمع أو من خلال تذاكر GitHub.
آخر تعديل في ٢٣ يوليو ٢٠٢٦