المتطلبات الأساسية
- uv وبايثون 3.11 أو إصدار أحدث. اختُبر هذا الدليل باستخدام بايثون 3.13 وFastAPI 0.142 وSQLAlchemy 2.1 وasyncpg 0.31 وAlembic 1.20 وUvicorn 0.54.
- حساب على ClickHouse Cloud
psql، لإنشاء قاعدة البيانات. ويمكنك بدلًا من ذلك تنفيذ عبارةCREATE DATABASEفي SQL console.
إنشاء خدمة ClickHouse Managed Postgres
في وحدة تحكم ClickHouse Cloud، انقر على New service ثم اختر Postgres. سيكون المثيل جاهزًا في غضون بضع دقائق. للاطلاع على شرح مفصّل للخطوات، راجع دليل البدء السريع.الحصول على بيانات الاتصال
انقر على Connect في الشريط الجانبي الأيسر لخدمتك. تعرض النافذة المنبثقة اسم المستخدم وكلمة المرور والخادم والمنفذ، وتتضمّن مفتاح تبديل بين Directly وvia PgBouncer. يستخدم هذا الدليل كلا الاتصالين:- PgBouncer (المنفذ
6432) للتطبيق. يحتفظ SQLAlchemy بمجمّع اتصالات في كل عامل من عمّال Uvicorn، ويتيح PgBouncer المضمَّن لعدد كبير من العمّال والنسخ المتماثلة مشاركة عدد محدود من اتصالات Postgres، وهو يعمل في وضع تجميع المعاملات. - الاتصال المباشر (المنفذ
5432) لـ Alembic. تنفّذ عمليات الترحيل أوامر DDL، وقد تستغرق وقتًا طويلًا، وقد تعتمد على حالة session، لذا ينبغي أن تتصل بـ Postgres مباشرةً.
sslmode=verify-full&sslrootcert=.... ونظرًا إلى أن asyncpg لا يقرأ هذه المعلمات، انسخ كلمة المرور والمضيف فقط من النافذة المنبثقة؛ إذ يمرّر التطبيق شهادة CA داخل الشيفرة بدلًا من ذلك (راجع تهيئة الاتصال).
إعداد المشروع
أنشئ مشروعًا وثبّت FastAPI وUvicorn وSQLAlchemy مع حزمة الاعتماديات الإضافيةasyncio الخاصة بها، إلى جانب asyncpg وAlembic:
تهيئة الاتصال
انقل شهادة CA التي نزّلتها إلى دليل المشروع، ثم أعد تسميتها إلىca-certificate.pem.
أنشئ قاعدة بيانات للتطبيق. استبدل <PASSWORD> والمضيف بالقيم الظاهرة في النافذة المنبثقة Connect:
.env في جذر المشروع، أو أضف هذه المتغيرات إلى ملفك الحالي. لا يختلف عنوانا URL إلا في المنفذ، ويستخدم كلاهما المخطط postgresql+asyncpg، ولا يحتويان على أي معلمات SSL:
.env
DATABASE_CA_CERT نسبةً إلى الدليل الذي تُشغِّل منه الأوامر. وإذا كانت كلمة المرور تحتوي على محارف خاصة مثل @ أو / أو #، فرمِّزها بترميز URL. واحرص على إبقاء .env خارج نظام التحكم في الإصدارات.
أنشئ الملف app/db.py. يتولى هذا الملف تهيئة إعدادات TLS والمحرك، إضافةً إلى مصنع session يتشاركه سائر أجزاء التطبيق:
app/db.py
ssl.SSLContext المُنشأ باستخدام PROTOCOL_TLS_CLIENT شهادةً صالحة، ويتحقق من اسم المضيف، وهو ما يعادل sslmode=verify-full. ويمرّر SQLAlchemy هذا الكائن إلى asyncpg عبر connect_args.
إذا كنت تفضّل إبقاء إعدادات TLS في عنوان URL، أو كان تطبيقك يستخدم sessions SQLAlchemy متزامنة، فاستخدم المشغّل psycopg بدلًا من asyncpg. فهو مبني على libpq ويقبل المعلمات الواردة في نافذة Connect، مثل
postgresql+psycopg://...:5432/guide_fastapi?sslmode=verify-full&sslrootcert=ca-certificate.pem، مع كلٍّ من create_engine وcreate_async_engine.تعريف النموذج
أنشئ الملفapp/models.py وضمّنه نموذج SQLAlchemy محدد الأنواع:
app/models.py
تشغيل عمليات الترحيل
أنشئ بيئة Alembic باستخدام القالب غير المتزامن:migrations/env.py الذي تم إنشاؤه. تحمّل النسخة الجديدة نماذجك لتستخدمها ميزة autogenerate، وتتصل مباشرةً بـ Postgres بإعدادات TLS نفسها التي يستخدمها التطبيق:
migrations/env.py
sqlalchemy.url في alembic.ini، لأن env.py يتولى إنشاء المحرك بنفسه.
أنشئ ملف ترحيل انطلاقًا من النموذج، ثم طبّقه:
migrations/versions ثم ثبّته (commit) مع الشيفرة الخاصة بك. يسجّل Alembic الـ revision المُطبَّق في الجدول alembic_version. وكلما غيّرت نموذجًا، شغّل revision --autogenerate وupgrade head مجددًا.
إضافة نقاط نهاية واجهة برمجة التطبيقات
أنشئ الملفapp/main.py. يحصل كل طلب على AsyncSession خاصة به عبر تبعية FastAPI، ويُغلَق مجمّع الاتصالات الخاص بالمحرك عند إيقاف تشغيل التطبيق:
app/main.py
session.commit. وعند إغلاق الـ session، يُتراجَع عن أي عمل غير مُثبَّت. أما عند تنفيذ INSERT، فيستعيد SQLAlchemy قيمتَي id وcreated_at المُولَّدتين باستخدام RETURNING، ولذلك لا تحتاج create_todo إلى استعلام إضافي.
التشغيل والتحقق
شغّل التطبيق:DELETE الرمز 204 No Content. أما طلب عنصر مهام غير موجود فيُعيد الرمز 404:
pg_stat_ssl باستخدام إعدادات TLS نفسها التي يستخدمها التطبيق:
guide_fastapi ثم public، ثم انقر على جدول todos. ويحتفظ جدول alembic_version المجاور له بسجل عمليات الترحيل، بينما يحتوي جدول todos على الصف المتبقي:
أوقف التطبيق بالضغط على Ctrl+C.
استخدام PgBouncer
يعمل التطبيق عبر PgBouncer باستخدام إعدادات asyncpg وSQLAlchemy الافتراضية:- ينفّذ asyncpg كل استعلام بوصفه عبارة مُحضَّرة مُسمّاة على مستوى البروتوكول، ويخزّن SQLAlchemy ما يصل إلى 100 منها مؤقتًا لكل اتصال. يدعم PgBouncer المرفق هذه العبارات في وضع تجميع المعاملات، ويحرّرها asyncpg عبر رسالة
Closeعلى مستوى البروتوكول بدلًا من أمر SQLDEALLOCATE. لذا لا حاجة إلىstatement_cache_size=0ولا إلى دالةprepared_statement_name_funcمخصّصة. وإذا عطّلت مع ذلك ذاكرة التخزين المؤقت للعبارات في asyncpg، فأضف أيضًاprepared_statement_cache_size=0إلى عنوان URL لتعطيل ذاكرة التخزين المؤقت في SQLAlchemy. - إعدادات session المضبوطة باستخدام
SET، مثلsearch_path، لا تنتقل إلى المعاملة التالية، وقد تتسرّب إلى عملاء آخرين. لذا استخدمSET LOCALداخل المعاملة بدلًا من ذلك. - يعرض
pg_stat_sslمعلومات الاتصال بين PgBouncer وPostgres، لذا يُرجع فحص TLS المذكور أعلاه القيمة(False, None)عبر المنفذ6432. ومع ذلك يظل اتصال التطبيق بـ PgBouncer خاضعًا للتحقق، إذ يفشل الاتصال بالطريقة نفسها عند استخدام شهادة CA خاطئة. - لا يستخدم Alembic الأقفال الاستشارية، وينفّذ كل عملية
upgradeضمن معاملة واحدة، لذا يعمل هو أيضًا عبر PgBouncer. ومع ذلك يبقى الاتصال المباشر الخيار الأفضل لعمليات الترحيل الطويلة.
الخطوات التالية
- الاتصال: سلاسل الاتصال وPgBouncer وTLS
- الإعدادات: معلمات Postgres وPgBouncer، مثل
max_connections - النسخ المتماثلة للقراءة: توجيه الاستعلامات المخصصة للقراءة فقط إلى نسخة متماثلة تعمل بمحرك ثانٍ
- الأمان: قوائم الوصول المستندة إلى عناوين IP والشبكات الخاصة