قواعد البيانات12 دقيقة قراءة

توافر PostgreSQL عالٍ مع Patroni على خادم VPS

لا يتحمّل تطبيق SaaS متعدد المستأجرين أو أي تطبيق حسّاس أي انقطاع في قاعدة البيانات. Amazon RDS وAurora يحلّان المشكلة، لكن نموذج فوترتهما يكبر مع الحِمل. يوفّر Patroni 4.1 مع etcd 3.6 نفس مستوى التوافر على ثلاثة خوادم VPS بصلاحية root: تحوّل تلقائي في أقل من 30 ثانية، نسخ متزامن قابل للضبط، وواجهة REST API للتحكم في الكلستر من الطرفية. يشمل هذا الدليل التثبيت الكامل، وعرض التحوّل، والعمليات اليومية.

لماذا التوافر العالي لـ PostgreSQL على VPS وليس RDS

يتعامل ‏Amazon RDS Multi-AZ‏ مع التحوّل بكفاءة، لكن نموذج تسعيره مصمَّم لتنمو الفاتورة بشكل غير خطي: التخزين، وIOPS المُخصَّصة، والاتصالات المتزامنة، وتكرار Multi-AZ كلها تُفوتَر بشكل منفصل. لخدمة SaaS ذات قاعدة بيانات متنامية، يتجاوز الفارق بسرعة تكلفة خادم VPS مخصَّص.

على ثلاثة خوادم VPS بصلاحية root، يوفّر Patroni الخدمة ذاتها: قائد واحد يقبل الكتابة، ونسختان متزامنتان أو غير متزامنتين تتبعانه، وetcd يحتفظ بالنصاب. إن سقط القائد، يكشف Patroni الغياب عبر اتفاقية إيجار ‏etcd‏ (TTL قابل للضبط، عادةً 30 ثانية) ويُرقّي النسخة الأحدث. لا تدخّل بشري، ولا تحديث DNS يدوي إن كان موزّع الأحمال مثل HAProxy يشير إلى نقطة نهاية صحة Patroni.

ما يقدّمه هذا الكلستر

  • تحوّل تلقائي خلال 30 ثانية — يكشف Patroni فقدان القائد بانتهاء اتفاقية ‏etcd‏ ويُرقّي دون تدخّل.
  • نسخ متزامن قابل للضبطsynchronous_mode: true يضمن عدم فقدان أي معاملة مؤكَّدة عند تعطّل القائد.
  • REST API مدمجةGET /leader وGET /health وPOST /switchover: استعلام الكلستر وإدارته دون عميل PostgreSQL.
  • تكلفة ثابتة وقابلة للتنبؤ — ثلاثة خوادم VPS بموارد محدّدة، بدون مفاجآت في الفاتورة.
  • إضافات حرّةpg_hba.conf وpostgresql.conf وpgvector وPostGIS: لا قيود تفرضها خدمة مُدارة.
  • نسخ احتياطي مركزي — يتكامل pgBackRest 2.59 بشكل أصلي مع Patroni لنسخ احتياطي تدريجي من النسخة المتماثلة.

معمارية الكلستر: ثلاث عُقد، نصاب واحد

يرتكز الكلستر على ثلاث طبقات:

etcd يحتفظ بسجل الإعداد الموزَّع (DCS). هو من يملك اتفاقية إيجار القائد. إن لم يجدّد قائد Patroni هذه الاتفاقية خلال مهلة TTL، أطلقها etcd وتنافس عليها العُقد الاحتياطية بالانتخاب. مع ثلاث عُقد etcd (واحدة لكل VPS)، يتحمّل النصابُ فقدانَ عُقدة واحدة دون خسارة التوافر.

Patroni يعمل على كل VPS جنبًا إلى جنب مع PostgreSQL. يتولّى تهيئة الكلستر، وإعداد postgresql.conf وpg_hba.conf، وتتبّع تأخّر النسخ، والتحوّل. يعرض REST API على المنفذ 8008.

PostgreSQL تديره Patroni بالكامل — لا تُعدّل postgresql.conf مباشرةً؛ كل تغيير يمر عبر patronictl edit-config ليبقى متزامنًا على العُقد الثلاث.

تدفّق النسخ: يستقبل القائد الكتابة على شكل WAL، وتتصل النسخ عبر pg_basebackup عند أول تشغيل ثم تتابع تدفّق WAL باستمرار. في الوضع المتزامن، ينتظر القائد تأكيد نسخة واحدة على الأقل قبل إرجاع COMMIT للعميل.

المتطلبات: الموارد والشبكة

كُتب هذا الدليل باستخدام Patroni 4.1.5 وetcd 3.6.6 وPostgreSQL 17 على Debian 12.

الحد الأدنى الموصى به من الموارد لكل عُقدة

  • 2 vCPU / 4 جيجابايت RAM — كافٍ للبدء؛ خطّط لـ 8 جيجابايت RAM بمجرد تجاوز قاعدة البيانات بضعة جيجابايتات في shared_buffers.
  • SSD NVMe — النسخ WAL حسّاس لزمن انتظار الكتابة؛ القرص الدوّار يُدهور تأخّر النسخ.
  • شبكة خاصة بين العُقد الثلاث — يجب ألا يمر تواصل etcd وPatroni مع PostgreSQL عبر الإنترنت.
  • IPv4 مخصَّصة — للوصول الخارجي للعملاء ولـ pg_hba.conf الخاص بالنسخ المتماثلة.
  • NTP مُزامَن (chrony) — انجراف < 1 ثانية — يرفض etcd النصابَ إن انجرفت ساعة عُقدة أكثر من ثانية. هذا الفخ الأكثر شيوعًا على خوادم VPS.

التثبيت: من الصفر إلى كلستر يعمل

01

مزامنة الساعة على العُقد الثلاث

على كل عُقدة، ثبّت chrony وفعّله قبل أي خطوة أخرى:

apt install -y chrony
systemctl enable --now chronyd
chronyc tracking

تأكّد أن System time offset أقل من 0.1 ثانية. أي انجراف يتجاوز ثانية يتسبّب في انتهاء مهلة etcd وحلقات انتخاب لا تنتهي.

02

تثبيت etcd 3.6 على العُقد الثلاث

عرّف متغيرات البيئة الخاصة بكل عُقدة (استبدل NODE1_IP وNODE2_IP وNODE3_IP بعناوين IP الخاصة):

ETCD_VER=v3.6.6
curl -L https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \
  | tar xz -C /usr/local/bin --strip-components=1 etcd-${ETCD_VER}-linux-amd64/etcd \
                                                   etcd-${ETCD_VER}-linux-amd64/etcdctl

أنشئ /etc/etcd/etcd.conf.yml على كل عُقدة (مثال لـ pg-node1):

name: pg-node1
data-dir: /var/lib/etcd
listen-peer-urls: http://NODE1_IP:2380
listen-client-urls: http://NODE1_IP:2379,http://127.0.0.1:2379
initial-advertise-peer-urls: http://NODE1_IP:2380
advertise-client-urls: http://NODE1_IP:2379
initial-cluster: pg-node1=http://NODE1_IP:2380,pg-node2=http://NODE2_IP:2380,pg-node3=http://NODE3_IP:2380
initial-cluster-token: pg-cluster-token
initial-cluster-state: new

أنشئ وحدة systemd، فعّل etcd وشغّله على العُقد الثلاث قبل المتابعة.

03

التحقق من نصاب etcd

من أي عُقدة:

etcdctl --endpoints=http://NODE1_IP:2379,http://NODE2_IP:2379,http://NODE3_IP:2379 \
  endpoint status --write-out=table

انتظر ظهور ثلاثة صفوف — أحدها يُظهر IS LEADER بقيمة true والآخران false — وأن يكون ERRORS فارغًا. إن غابت عُقدة، تحقّق من جدار الحماية على المنفذين 2379 و2380.

04

تثبيت PostgreSQL وPatroni

على العُقد الثلاث:

# PostgreSQL من مستودع PGDG الرسمي
apt install -y curl ca-certificates
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg
echo "deb https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list
apt update && apt install -y postgresql-17

# Patroni ومُشغّل etcd
pip3 install patroni[etcd3] psycopg2-binary

أوقف PostgreSQL — يتولّى Patroni تهيئة الكلستر:

systemctl stop postgresql
systemctl disable postgresql
05

إعداد Patroni على كل عُقدة

أنشئ /etc/patroni/patroni.yml (مثال لـ pg-node1):

scope: pg-cluster
namespace: /service/
name: pg-node1

restapi:
  listen: NODE1_IP:8008
  connect_address: NODE1_IP:8008

etcd3:
  hosts: NODE1_IP:2379,NODE2_IP:2379,NODE3_IP:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    synchronous_mode: true
    synchronous_node_count: 1
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        wal_keep_size: 128MB
        max_wal_senders: 10
        max_replication_slots: 10

  initdb:
    - encoding: UTF8
    - data-checksums

  pg_hba:
    - host replication replicator 0.0.0.0/0 scram-sha-256
    - host all all 0.0.0.0/0 scram-sha-256

postgresql:
  listen: NODE1_IP:5432
  connect_address: NODE1_IP:5432
  data_dir: /var/lib/postgresql/17/main
  bin_dir: /usr/lib/postgresql/17/bin
  authentication:
    replication:
      username: replicator
      password: 'كلمة_مرور_النسخ'
    superuser:
      username: postgres
      password: 'كلمة_مرور_postgres'

عدّل NODE1_IP لكل عُقدة.

06

تشغيل Patroni وتهيئة الكلستر

أنشئ وحدة systemd في /etc/systemd/system/patroni.service:

[Unit]
Description=Patroni PostgreSQL HA
After=network.target etcd.service
Requires=etcd.service

[Service]
Type=simple
User=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

شغّل أوّلًا على pg-node1 (ستقوم هذه العُقدة بـ initdb وستصبح القائد)، ثم على العُقدتين الأخريين بفاصل بضع ثوانٍ:

systemctl daemon-reload
systemctl enable --now patroni

تابع التهيئة:

patronictl -c /etc/patroni/patroni.yml list
07

التحقق من الحالة الأولية للكلستر

المخرجات المتوقعة بعد اكتمال التهيئة:

+ Cluster: pg-cluster (7234567890123456789) +---------+----+-----------+
| Member    | Host             | Role         | State   | TL | Lag in MB |
+-----------+------------------+--------------+---------+----+-----------+
| pg-node1  | NODE1_IP:5432    | Leader       | running |  1 |           |
| pg-node2  | NODE2_IP:5432    | Sync Standby | running |  1 | 0         |
| pg-node3  | NODE3_IP:5432    | Replica      | running |  1 | 0         |
+-----------+------------------+--------------+---------+----+-----------+

تظهر pg-node2 بوصفها Sync Standby: كل معاملة مؤكَّدة على القائد مضمونة على هذه العُقدة قبل إرجاع COMMIT للعميل.

08

إعداد pg_hba.conf عبر Patroni

لا تُعدّل pg_hba.conf مباشرةً. استخدم patronictl edit-config لإضافة قواعد الوصول في قسم pg_hba — يُوزّع Patroni الإعداد على جميع العُقد ويُعيد تحميل PostgreSQL تلقائيًا:

patronictl -c /etc/patroni/patroni.yml edit-config

أضف قواعدك في كتلة YAML الخاصة بـ pg_hba. على VPS، host all all 0.0.0.0/0 scram-sha-256 هي نقطة البداية التي يمكن تضييقها وفق شبكتك الخاصة.

التحوّل التلقائي والتحوّل المُخطَّط: عرض تطبيقي

تحوّل مُحاكى — إيقاف مفاجئ للقائد.

قبل الإيقاف، سجّل حالة الكلستر:

patronictl -c /etc/patroni/patroni.yml list
# → pg-node1 هو Leader، pg-node2 هو Sync Standby

أوقف Patroni على القائد:

systemctl stop patroni   # على pg-node1

تابع الترقية على أحد العُقد الاحتياطية:

patronictl -c /etc/patroni/patroni.yml list
# → (بعد 10 إلى 30 ثانية)
# pg-node2 : Leader  | running | TL 2
# pg-node3 : Replica | running | TL 2 | 0 MB
# pg-node1 : stopped

ينتظر Patroni انتهاء اتفاقية إيجار etcd (TTL = 30 ث)، ثم تحصل pg-node2 (النسخة المتزامنة) على الاتفاقية وتُرقّي نفسها. التأخّر الفعلي بين 10 و30 ثانية تبعًا لقيمة loop_wait.

تحوّل مُخطَّط — تبديل بدون انقطاع.

للصيانة المجدوَلة، فضّل switchover الذي ينتظر حتى تلحق العُقدة المستهدفة بالقائد قبل التبديل:

patronictl -c /etc/patroni/patroni.yml switchover pg-cluster \
  --master pg-node1 --candidate pg-node2

ينتظر Patroni حتى يصبح التأخّر صفرًا، يُشير إلى pg-node2 بالترقية، ثم تُعيد pg-node1 الاتصال كنسخة متماثلة. المدة الفعلية: أقل من 5 ثوانٍ في الظروف الطبيعية.

REST API للحالة.

بدون عميل PostgreSQL، استعلم الحالة من موزّع الأحمال أو سكريبت المراقبة:

curl -s http://NODE1_IP:8008/leader    # 200 = هذه هي العُقدة القائدة
curl -s http://NODE2_IP:8008/replica   # 200 = نسخة متماثلة سليمة
curl -s http://NODE1_IP:8008/health    # JSON: state, role, lag

يمكن لـ HAProxy توجيه فحوصات الصحة نحو /leader و/replica لتوجيه الكتابة والقراءة على العُقد الصحيحة. راجع دليل HAProxy على VPS للتوصيل الكامل.

العمليات اليومية

النسخ الاحتياطي مع pgBackRest 2.59.

ثبّت pgBackRest على العُقد الثلاث وحدّد مستودعًا مشتركًا (تخزين كائنات S3، أو NFS، أو مجلد محلي مخصَّص). يسحب الإعداد الموصى به النسخ الاحتياطية من النسخة المتماثلة لتفادي تحميل القائد:

pgbackrest --stanza=pg-cluster --type=full backup

فعّل الضغط والنسخ الاحتياطي التدريجي اليومي في pgbackrest.conf (repo1-retention-full=7). راجع دليل النسخ الاحتياطي على VPS للاستراتيجيات التكميلية.

مراقبة الكلستر.

patronictl list يُظهر التأخّر بالميجابايت لكل نسخة متماثلة. أنشئ تنبيهًا عند تجاوز التأخّر عتبة محدّدة (مثلًا 50 ميجابايت): يشير ذلك إلى نسخة بطيئة أو مشكلة شبكة. تُعيد نقطة النهاية GET /patroni بيانات JSON كاملة تشمل xlog_location وreplication_state.

التوسّع العمودي.

لزيادة موارد عُقدة: أوقف Patroni عليها (تتحوّل إلى نسخة منفصلة)، أعد تحجيم الـ VPS، وأعد التشغيل. تعيد Patroni الاتصال وتلحق بالتأخّر تلقائيًا عبر pg_rewind أو pg_basebackup حسب حجم الفجوة.

مقايضة synchronous_commit.

مع synchronous_mode: true، ينتظر كل COMMIT تأكيد العُقدة المتزامنة. على شبكة خاصة محلية، يتراوح التأخّر المُضاف بين 0.2 و1 ميلي ثانية. على شبكة أوسع (عُقد في مراكز بيانات مختلفة)، قد يؤثّر هذا التأخّر في التطبيقات كثيفة الكتابة. في هذه الحالة، انتقل إلى synchronous_mode: false مع النسخ غير المتزامن: ستفقد ضمان عدم فقدان البيانات عند تعطّل القائد، لكن الكتابة ستبقى سريعة. هذه مقايضة يجب توثيقها صراحةً في إعداداتك.

التصليب: TLS متبادل بين العُقد

بشكل افتراضي، يسير تواصل etcd واتصالات النسخ لـ PostgreSQL بدون تشفير عبر الشبكة الخاصة. على شبكة مشتركة أو بيئة متعددة المستأجرين، فعّل TLS المتبادل.

لـ etcd، أنشئ CA وشهادات لكل عُقدة، ثم أضف في etcd.conf.yml:

client-transport-security:
  cert-file: /etc/etcd/tls/server.crt
  key-file: /etc/etcd/tls/server.key
  trusted-ca-file: /etc/etcd/tls/ca.crt
  client-cert-auth: true
peer-transport-security:
  cert-file: /etc/etcd/tls/peer.crt
  key-file: /etc/etcd/tls/peer.key
  trusted-ca-file: /etc/etcd/tls/ca.crt
  peer-client-cert-auth: true

لنسخ PostgreSQL، استخدم sslmode=verify-full في معاملات اتصال primary_conninfo الخاصة بـ Patroni. تتحقق كل نسخة متماثلة بذلك من شهادة القائد.

استكشاف الأخطاء: أكثر خمسة أخطاء شيوعًا

1. فقدان نصاب etcd — الكلستر يرفض انتخاب قائد.

العَرَض: يُظهر patronictl list جميع العُقد بحالة running لكن بلا Leader. السبب: عُقدة etcd غير قابلة للوصول والنصاب (2 من 3) لم يعد مكتملًا. تحقق بـ etcdctl endpoint status — ستظهر العُقدة المعطوبة بدون استجابة أو بخطأ اتصال. أصلح العُقدة أو أزلها مؤقتًا من الكلستر (etcdctl member remove).

2. انجراف NTP — حلقة انتخابات.

العَرَض: يتغير القائد كل 30 ثانية، وتُظهر سجلات Patroni failed to update leader key. السبب: ساعة إحدى العُقد تنجرف بأكثر من ثانية. تحقق بـ chronyc tracking على كل عُقدة وأصلح قبل إعادة تشغيل Patroni.

3. احتمال تشقّق الدماغ — pg_rewind يرفض التطبيق.

العَرَض: قائد سابق يُعاد تشغيله وPatroni يرفض إعادة دمجه كنسخة متماثلة مع الخطأ could not connect to the target server: pg_rewind target server must be in standby mode. استمر الخادم في الكتابة بعد فقدان الاتفاقية. الحل: pg_rewind --target-pgdata=/var/lib/postgresql/17/main --source-server='host=NEW_LEADER_IP ...'، ثم أعد تشغيل Patroni.

4. رفض اتصال النظير — إدخال مفقود في pg_hba.conf.

العَرَض: تُهيَّأ النسخ لكنها تفشل مع FATAL: no pg_hba.conf entry for replication connection. القاعدة host replication replicator 0.0.0.0/0 scram-sha-256 غائبة من قسم pg_hba في patroni.yml. أضفها عبر patronictl edit-config — ليس مباشرةً في pg_hba.conf.

5. تأخّر متواصل بعد التحوّل — max_wal_senders غير كافٍ.

العَرَض: تُظهر النسخة تأخّرًا لا يتناقص بعد الترقية. السبب الشائع: max_wal_senders منخفض للغاية (القيمة الافتراضية 10 في بعض الإصدارات) وفتحة النسخ مكتظة. ارفعه إلى 20 عبر patronictl edit-config (المعامل max_wal_senders) وأعد التحميل.

كلستر يُدار ولا يُرتجَل

يغطي Patroni 4.1 مع etcd 3.6 معظم ما تقدّمه الخدمة المُدارة على صعيد التوافر: انتخاب تلقائي، نسخ متزامن، API للإدارة. الفرق هو التحكّم: صلاحية root، إضافات حرّة، تكلفة ثابتة، والقدرة على تشخيص العُقدة المتعثّرة بدلًا من انتظار دعم طرف ثالث.

المتطلب التشغيلي ليس تعقيد Patroni — الإجراء أعلاه يُظهر أنه قابل للإدارة. إنه الانضباط على ثلاثة محاور: NTP مُزامَن، نسخ احتياطية تُتحقَّق منها بانتظام، وكتيّب تشغيل للتحوّل يُختبَر قبل وقوع العطل.

للبدء، يحتاج كلستر Patroni بثلاث عُقد إلى ثلاثة خوادم VPS بصلاحية root وIPv4 مخصَّصة وشبكة خاصة. راجع دليل التثبيت الأساسي PostgreSQL على VPS والمقارنة الاستضافة الذاتية مقابل Amazon RDS لاختيار النهج المناسب لحِملك.

ثلاثة خوادم VPS لكلستر Patroni

يحتاج كلستر PostgreSQL Patroni بثلاث عُقد إلى ثلاثة خوادم VPS بصلاحية root وIPv4 مخصَّصة وشبكة خاصة. جميع قوالب VPS من ServOrbit توفّر صلاحية root كاملة وشبكة خاصة بين المثيلات.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـ العربية والفرنسية والإنجليزية.