todos عبر عملية ترحيل باستخدام sqlx-cli، ثم تُنفّذ استعلامات الإنشاء والقراءة والتحديث والحذف من خلال خادم axum صغير. ويستخدم كل اتصال بروتوكول TLS مع تحقق كامل من الشهادة.
المتطلبات الأساسية
- Rust الإصدار 1.94 أو أحدث. اختُبر هذا الدليل باستخدام Rust 1.98.1، و
sqlx0.9.0، وsqlx-cli0.9.0، وaxum0.8.9. - حساب ClickHouse Cloud
psql، لإنشاء قاعدة البيانات. ويمكنك بدلًا من ذلك تنفيذ عبارةCREATE DATABASEفي وحدة تحكم SQL.
إنشاء خدمة ClickHouse Managed Postgres
في وحدة تحكم ClickHouse Cloud، انقر على New service ثم اختر Postgres. سيصبح المثيل جاهزًا في غضون دقائق قليلة. راجع دليل البدء السريع للاطلاع على شرح مفصّل للخطوات.الحصول على بيانات الاتصال
انقر على Connect في الشريط الجانبي الأيسر لخدمتك. أبقِ الخيار Directly محددًا وفعّل Use SSL. سينتهي عنوان URL للاتصال في علامة التبويب url الآن بـsslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem، وسيكون المنفذ 5432.
انقر على Download CA certificate. يمكنك أيضًا تنزيل الشهادة لاحقًا من Settings → CA Certificate. هذه الشهادة فريدة لمثيلك، ما يتيح للمشغّل استخدامها للتحقق من أنه يتصل بخادمك فعلًا.
يتصل هذا الدليل مباشرةً بـ Postgres على المنفذ 5432، سواء من التطبيق أو من sqlx-cli. فخادم axum عملية تعمل لفترات طويلة، ويدير PgPool مجمّع الاتصالات الخاص به، لذا لا حاجة إلى وسيط تجميع اتصالات إضافي أمام Postgres. ويجب أن تستخدم عمليات الترحيل الاتصال المباشر دائمًا. إذا كنت تشغّل مثيلات عديدة من التطبيق، فراجع استخدام PgBouncer.
إعداد المشروع
أنشئ مشروعًا وأضف إليهsqlx مع مشغّل Postgres وبيئة تشغيل Tokio والواجهة الخلفية rustls الخاصة بـ TLS، إلى جانب axum وبعض حزم crate المساعدة:
sqlx-cli باستخدام الواجهة الخلفية نفسها لـ TLS:
تهيئة الاتصال
انقل شهادة CA التي نزّلتها إلى دليل المشروع، وغيّر اسمها إلىca-certificate.pem.
أنشئ قاعدة بيانات للتطبيق. استبدل <PASSWORD> والمضيف بالقيم الظاهرة في نافذة Connect:
.env في جذر المشروع، أو حدّث قيمة DATABASE_URL في ملفك الحالي، بحيث تشير إلى قاعدة البيانات guide_rust. يقرأ كلٌّ من التطبيق وsqlx-cli قيمة DATABASE_URL من هذا الملف:
.env
sslmode وsslrootcert من URL. ومع verify-full، يتحقق من أن شهادة الخادم موقّعة من الـ CA الخاصة بالمثيل لديك، ومن تطابقها مع اسم المضيف. ويُحدَّد مسار sslrootcert نسبةً إلى الدليل الذي تشغّل منه الأوامر. احرص على إبقاء الملف .env خارج نظام التحكم في الإصدارات، وإذا احتوت كلمة المرور على محارف مثل @ أو / أو #، فرمّزها بترميز النسبة المئوية (percent-encoding).
إنشاء الجدول باستخدام عملية ترحيل
أنشئ ملف ترحيل:migrations وأضف إليه تعريف الجدول:
migrations/<timestamp>_create_todos.sql
sqlx migrate run عمليات الترحيل المطبّقة في جدول _sqlx_migrations، ولا ينفّذ في الاستدعاءات اللاحقة سوى عمليات الترحيل الجديدة. ثبّت الدليل migrations مع الشيفرة الخاصة بك. وإن أردت بدلاً من ذلك تطبيق عمليات الترحيل عند بدء تشغيل التطبيق، فاستدعِ sqlx::migrate!().run(&pool).await? داخل main، شريطة أن يستخدم مجمّع الاتصالات الاتصال المباشر.
بناء واجهة برمجة التطبيقات
استبدل محتوىsrc/main.rs بخادم axum صغير ينفّذ استعلامًا واحدًا لكل مسار. أما إذا كان لديك تطبيق قائم، فأنشئ مجمّع الاتصالات بالطريقة نفسها المتّبعة في main، ثم أضف البنية Todo (struct) والمعالجات والمسارات إلى الموجّه (router) الخاص بك:
src/main.rs
$1) باستخدام .bind، ولا تُدرَج أبدًا ضمن string الخاص بـ SQL. ويُحضَّر كل string فريد من SQL مرة واحدة لكل اتصال، ثم يُحفظ في ذاكرة تخزين مؤقت للعبارات تتسع لـ 100 عبارة، ويتولى sqlx إغلاق العبارات عند إخراجها منها.
التشغيل والتحقق
شغّل الخادم:pg_stat_ssl، وهو يؤكد أن الـ session مشفّرة. في طرفية ثانية، أنشئ مهمتين، ثم علّم الأولى بأنها مكتملة، واحذف الثانية:
-w '\n' على إضافة سطر جديد بعد كل استجابة:
http://localhost:3117/todos في متصفحك لعرض قائمة المهام المتبقية:
guide_rust ثم public، وانقر على جدول todos. أما الجدول _sqlx_migrations المجاور له فيحتفظ بسجل عمليات الترحيل. ويحتوي جدول todos على الصف المتبقي:
استخدام PgBouncer
لتوصيل التطبيق عبر PgBouncer المضمَّن، اختر via PgBouncer في نافذة Connect واستخدم المنفذ6432 في متغير DATABASE_URL الخاص بالتطبيق. ويمكن استخدام شهادة CA نفسها في هذه الحالة أيضًا. فمثلًا، أبقِ ملف .env مضبوطًا على الاتصال المباشر لاستخدامه مع sqlx-cli، واضبط المتغير عند تشغيل التطبيق:
pg_stat_ssl اتصال PgBouncer نفسه بـ Postgres، ولذلك يطبع الفحص القيمة none. ومع ذلك، يظل اتصال تطبيقك بـ PgBouncer خاضعًا للتحقق، إذ تفشل شهادة CA غير الصحيحة بالخطأ UnknownIssuer بالطريقة نفسها.
يعمل PgBouncer في وضع تجميع المعاملات، لذا قد تُنفَّذ كل معاملة على اتصال Postgres مختلف. وعند استخدام sqlx:
- الاتصال يتطلب
.extra_float_digits(None)، كما فيmain.rs. إذ يرسل sqlx افتراضيًاextra_float_digitsبوصفها معلمة بدء تشغيل، فيرفض PgBouncer الاتصال بالخطأunsupported startup parameter: extra_float_digits. وللسبب نفسه، يفشلPgConnectOptions::optionsبالخطأunsupported startup parameter in options. - العبارات المُحضَّرة تعمل مع الإعدادات الافتراضية. فعندما يُخرج sqlx عبارات من ذاكرة التخزين المؤقت الخاصة به، يحرّرها عبر رسالة
Closeعلى مستوى البروتوكول، وهي رسالة يعالجها PgBouncer حتى داخل المعاملات. لا تضبطstatement_cache_capacity(0)، فهذا غير ضروري، كما أن sqlx يظل عند تعطيل ذاكرة التخزين المؤقت يُحضّر عبارات مُسمّاة دون أن يغلقها أبدًا. - لا تستخدم
.persistent(false)مع الاستعلامات التي تُنفَّذ خارج معاملة. ففي هذه الحالة يُحضّر sqlx عبارة غير مُسمّاة ثم ينفّذها في رحلة ذهاب وإياب ثانية، وقد يوجّهها PgBouncer إلى اتصال Postgres مختلف. وعندئذٍ قد يفشل الاستعلام بالخطأunnamed prepared statement does not exist، أو يُنفّذ دون أي تنبيه عبارةً تخص عميلًا آخر فيُعيد نتائج خاطئة. - إعدادات الـ session المضبوطة باستخدام
SET، بما في ذلك داخل خطافafter_connectالخاص بمجمّع الاتصالات، لا تبقى مرتبطة باتصالك، وقد تتسرّب إلى عملاء آخرين. لذا استخدم بدلًا منهاSET LOCALداخل معاملة. - عمليات الترحيل يجب أن تستخدم الاتصال المباشر. فلا يمكن لـ
sqlx-cliولا لماكروquery!الاتصال عبر PgBouncer، لأنها ترسلextra_float_digitsدائمًا. كما يحصلsqlx::migrate!على قفل استشاري على مستوى الـ session (pg_advisory_lock)، وعند المرور عبر PgBouncer قد يصل أمر فكّ القفل إلى اتصال Postgres مختلف. فيبقى القفل عندئذٍ محتجزًا على أحد الاتصالات المُجمَّعة، وتتعلّق عمليات الترحيل اللاحقة، حتى تلك التي تجري عبر الاتصال المباشر، إلى أن يُغلق PgBouncer ذلك الاتصال.
الخطوات التالية
- الاتصال: سلاسل الاتصال وPgBouncer وTLS
- الإعدادات: معلمات Postgres وPgBouncer، مثل
max_connections - النسخ المتماثلة للقراءة: توجيه استعلامات القراءة فقط إلى نسخة متماثلة باستخدام
PgPoolثانٍ - الأمان: قوائم التحكم في الوصول حسب عناوين IP والشبكات الخاصة