Workstation Logo
المنتجات
مختبرات الذكاء الاصطناعيوكلاء OpenAIوكلاء ClaudeGrok BotWorkstation CRM (WSL CRM)التسويقجميع المنتجات
حلول الذكاء الاصطناعي
محطات عمل الذكاء الاصطناعيAI SME Packagesذكاء اصطناعي خاصمجموعات GPUذكاء اصطناعي طرفيمختبر الذكاء الاصطناعي للمؤسساتالذكاء الاصطناعي حسب الصناعة
الخدمات
Platform ModernisationDigital EngineeringData Foundations & AIAutonomous Operationsاستشارات الذكاء الاصطناعيأتمتة DevOpsالأمن السيبرانيتطوير البرمجياتبناء الوكلاءإعداد MLOps
من نحن
الشركاءقصص العملاء
المقالات
الوثائق
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
المدونة
اتصل بناLogin
Workstation

محطات عمل الذكاء الاصطناعي وبرمجيات الوكلاء المتعددة والبنية التحتية لوحدات GPU وحلول الوكلاء الأذكياء للشركات الحديثة.

اتصل بنا

حلول الذكاء الاصطناعي

محطات عمل الذكاء الاصطناعيAI SME Packagesذكاء اصطناعي خاصمجموعات GPUذكاء اصطناعي طرفيمختبر الذكاء الاصطناعي للمؤسساتالذكاء الاصطناعي حسب الصناعة

المنتجات

جميع المنتجاتWSL CRM و ERPالتسويقوكلاء OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

الشركة

من نحنلماذا Workstationالشركاءقصص العملاءالأسعاراتصل

الموارد

المقالاتالتوثيقالمدونةبحثخريطة الموقع
مكتب المملكة المتحدة
77-79 Marlowes, Hemel Hempstead HP1 1LFالاتجاهات - اسلك المخرج 20 من الطريق M25 في لندن الخارجيةرقم الشركة: 11641870الاثنين - الجمعة: 9:00 ص - 6:00 م بتوقيت GMT
+44 7515 356 146
مكتب بلجيكا
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683الاثنين - الجمعة: 9:00 ص - 6:00 م بتوقيت CET
+32 492 45 67 46
مكتب الهند
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. جميع الحقوق محفوظة.

الخصوصيةملفات تعريف الارتباطشروط الخدمةخريطة الموقع الإلكتروني

Loading blog...

Home / Blog
DatabaseKubernetesDevOpsBackend

التوفر العالي الأصلي لـ PostgreSQL: المستفيدون ونسخ البث المباشر واستراتيجيات تجاوز فشل الإنتاج

PostgreSQL Native HA مع Patroni ونسخ البث المباشر وHAProxy

Balinder Walia12 أبريل 202631 min read

يعد تشغيل مثيل PostgreSQL واحدًا أمرًا مباشرًا حتى يذكرك أول انقطاع غير مخطط له بأن قاعدة البيانات لا تقل قيمتها عن مدى توفرها. إن فشل القرص، وذعر النواة، وأقسام الشبكة، والترقيات الفاشلة ليست مخاطر نظرية - فهي يقينيات تشغيلية على جدول زمني طويل بما فيه الكفاية. لا يأتي PostgreSQL مزودًا بميزة تجاوز الفشل التلقائي المضمنة، ولكنه يوفر جميع أساسيات النسخ المتماثل اللازمة لإنشاء مجموعة متاحة للغاية. يقوم Patroni، وهو إطار عمل HA مفتوح المصدر تحتفظ به Zalando، بتنسيق تلك البدائيات في نظام تجاوز الفشل على مستوى الإنتاج والذي تم اختباره على نطاق واسع عبر الآلاف من مجموعات PostgreSQL في جميع أنحاء العالم.

هذه المقالة عبارة عن دليل هندسي متعمق. سنغطي النسخ المتماثل لدفق PostgreSQL (المتزامن وغير المتزامن)، وبنية Patroni وتكوينها، وما إلى ذلك كمخزن تكوين موزع، وHAProxy لتوجيه الاتصال مع تقسيم القراءة والكتابة، وPgBouncer لتجميع الاتصالات، وأرشفة WAL واسترداد النقطة في الوقت المناسب، والنسخ المتماثل المنطقي لمزامنة البيانات الانتقائية، وpg_basebackup لتوفير الاستعداد الأولي، وremgr كبديل لـ Patroni، وأنماط النشر الخاصة بالسحابة بالنسبة إلى AWS وAzure وGCP، ونشر k3s المعدني العاري مع Rancher وLonghorn، والمراقبة باستخدام pg_stat_replication وPrometheus/Grafana، وإجراءات التبديل مقابل تجاوز الفشل، ومنع تقسيم الدماغ، وضبط الإنتاج، وهندسة الفوضى للتحقق من صحة تجاوز الفشل.

PostgreSQL أساسيات النسخ المتدفق

يعد النسخ المتماثل للبث المباشر

بمثابة العمود الفقري للتوفر العالي لـ PostgreSQL. وهو يعمل عن طريق الشحن المستمر لسجلات سجل الكتابة المسبقة (WAL) من خادم أساسي إلى واحد أو أكثر من الخوادم الاحتياطية. يطبق الاحتياطي سجلات WAL هذه في الوقت الفعلي، مع الاحتفاظ بنسخة شبه متطابقة من البيانات الأساسية. تم تقديم هذه الآلية في PostgreSQL 9.0 وتم تحسينها في كل إصدار لاحق.

هناك وضعان لنسخ البث:غير المتزامنوالمتزامن. في الوضع غير المتزامن، لا ينتظر الأساسي حتى تؤكد الاستعدادات استلام سجلات WAL قبل تنفيذ المعاملة. يوفر هذا أقصى أداء للكتابة ولكنه يقدم نافذة لفقدان البيانات المحتمل - إذا فشل الأساسي قبل أن يتلقى الاستعداد أحدث WAL، فسيتم فقدان تلك المعاملات. في الوضع المتزامن، ينتظر الأساسي احتياطيًا واحدًا على الأقل للتأكد من كتابة سجلات WAL على مساحة تخزين دائمة قبل الإبلاغ عن معاملة ملتزم بها. يؤدي هذا إلى التخلص من فقدان البيانات على حساب زيادة زمن الوصول للالتزام، نظرًا لأن كل عملية كتابة يجب أن تذهب ذهابًا وإيابًا إلى وضع الاستعداد.

الاختيار بين النسخ المتزامن وغير المتزامن ليس ثنائيًا. يدعم PostgreSQLsynchronous_commitعلى مستوى الجلسة، لذلك يمكن لأحمال العمل الحساسة لزمن الوصول الاشتراك في الالتزامات غير المتزامنة بينما تستخدم المعاملات المالية الهامة الالتزامات المتزامنة داخل نفس المجموعة.

تكوين الأساسي للنسخ المتماثل

يجب تكوين الخادم الأساسي لإنشاء سجلات WAL بمستوى كافٍ للنسخ المتماثل والسماح بالاتصالات الاحتياطية. تعد إعداداتpostgresql.confالتالية ضرورية.

# postgresql.conf on the primary
wal_level = replica                    # minimum for streaming replication
max_wal_senders = 10                   # max concurrent replication connections
max_replication_slots = 10             # prevent WAL removal before standby consumption
wal_keep_size = 2GB                    # retain WAL as fallback if slots are unused
hot_standby = on                       # allow read queries on standbys
synchronous_commit = on                # 'on' for sync, 'off' for pure async
synchronous_standby_names = 'ANY 1 (standby1, standby2)'  # sync replication targets
archive_mode = on                      # enable WAL archiving for PITR
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
listening_addresses = '*'
port = 5432
تتم معالجة مصادقة

لاتصالات النسخ المتماثل فيpg_hba.conf. تستخدم اتصالات النسخ المتماثل نوع اتصال مخصص.

# pg_hba.conf — replication entries
# TYPE   DATABASE        USER            ADDRESS              METHOD
host     replication     replicator      10.0.1.0/24          scram-sha-256
host     replication     replicator      10.0.2.0/24          scram-sha-256
host     all             all             10.0.0.0/16          scram-sha-256

قم بإنشاء مستخدم النسخ المتماثل على الملف الأساسي.

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_replication_password';

توفير وضع الاستعداد باستخدام pg_basebackup

تقوم الأداة المساعدةpg_basebackupبإنشاء نسخة فعلية من دليل البيانات الأساسي، والذي يصبح نقطة البداية لوضع الاستعداد الجديد. فهو يتعامل مع النسخ الاحتياطي الأساسي وتدفق WAL تلقائيًا، وبالتالي تكون النسخة الناتجة متسقة.

# On the standby server
pg_basebackup -h primary-host -U replicator -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R

# -Fp: plain format
# -Xs: stream WAL during backup
# -P:  show progress
# -R:  create standby.signal and configure primary_conninfo in postgresql.auto.conf

تعتبر علامة-Rأمرًا بالغ الأهمية - فهي تكتبprimary_conninfoفيpostgresql.auto.confوتقوم بإنشاءstandby.signal، الذي يخبر PostgreSQL بالبدء في وضع الاستعداد. في PostgreSQL 12 والإصدارات الأحدث، يتم استبدالrecovery.confبهاتين الآليتين.

# postgresql.auto.conf (generated by pg_basebackup -R)
primary_conninfo = 'host=primary-host port=5432 user=replicator password=strong_replication_password application_name=standby1'
primary_slot_name = 'standby1_slot'

قم بإنشاء فتحة النسخ المتماثل على الجهاز الأساسي قبل بدء وضع الاستعداد، لمنع تنظيف WAL قبل أن يتمكن وضع الاستعداد من استهلاكه.

SELECT pg_create_physical_replication_slot('standby1_slot');
SELECT pg_create_physical_replication_slot('standby2_slot');

Patroni: تنسيق HA الآلي

يمنحك النسخ المتماثل للبث

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

Patroni هو برنامج Python يعمل جنبًا إلى جنب مع كل مثيل PostgreSQL. ويستخدم مخزن التكوين الموزع (DCS) - عادةً ما يكون إلخ، ولكن أيضًا ZooKeeper أو Consul - لتنسيق اختيار القائد وحالة المجموعة. تقوم كل عقدة من عقد Patroni بكتابة حالتها الصحية بشكل مستمر إلى DCS. عندما يفشل القائد (الأساسي) في تجديد مفتاح DCS الخاص به ضمن TTL الذي تم تكوينه، يبدأ Patroni في انتخاب القائد بين الاحتياطيين الصحيين. تتم ترقية الفائز إلى المرحلة الأساسية، وتعيد العقد المتبقية تكوين نفسها كوحدات احتياطية للنقطة الأساسية الجديدة — كل ذلك تلقائيًا، عادةً خلال 10-30 ثانية.

بنيةPatroni HA - مجموعة PostgreSQL ثلاثية العقدعملاء تطبيقHAProxy موازن التحميلمنفذ5000 (RW) · منفذ 5001 (RO)الأساسي (الزعيم)PostgreSQL 16 + باترونيعقدة 1 — 10.0.1.10:5432الاستعداد 1 (مزامنة)PostgreSQL 16 + باترونيعقدة 2 — 10.0.1.11:5432الاستعداد 2 (غير متزامن)PostgreSQL 16 + باترونيالعقدة 3 — 10.0.1.12:5432مزامنة البثالبث غير المتزامنإلخ المجموعة (DCS)3 العقد — انتخاب القائد & مخزن التكوينالابتدائيالاستعدادإلخ DCSهابروكسيتكوين

باتروني YAML

يتم تكوين

Patroni عبر ملف YAML الذي يحدد اتصال DCS ومعلمات PostgreSQL وسلوك النسخ المتماثل وإعدادات التمهيد. فيما يلي تكوين على مستوى الإنتاج للعقدة الأساسية.

# /etc/patroni/patroni.yml — Node 1 (Primary)
scope: pg-ha-cluster
namespace: /postgresql-ha/
name: node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.1.10:8008

etcd3:
  hosts:
    - 10.0.2.10:2379
    - 10.0.2.11:2379
    - 10.0.2.12:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576  # 1MB — only promote standbys within this lag
    synchronous_mode: true
    synchronous_mode_strict: false
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: 'on'
        max_connections: 200
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 2GB
        synchronous_commit: 'on'
        archive_mode: 'on'
        archive_command: 'test ! -f /archive/%f && cp %p /archive/%f'
        archive_timeout: 60
        wal_log_hints: 'on'
        shared_preload_libraries: 'pg_stat_statements'
        track_commit_timestamp: 'on'
      pg_hba:
        - host replication replicator 10.0.0.0/16 scram-sha-256
        - host all all 10.0.0.0/16 scram-sha-256
        - host all all 0.0.0.0/0 scram-sha-256

  initdb:
    - encoding: UTF8
    - data-checksums

  users:
    admin:
      password: 'admin_secure_password'
      options:
        - createrole
        - createdb
    replicator:
      password: 'repl_secure_password'
      options:
        - replication

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.1.10:5432
  data_dir: /var/lib/postgresql/16/main
  bin_dir: /usr/lib/postgresql/16/bin
  config_dir: /var/lib/postgresql/16/main
  pgpass: /tmp/pgpass0
  authentication:
    superuser:
      username: postgres
      password: 'postgres_secure_password'
    replication:
      username: replicator
      password: 'repl_secure_password'
    rewind:
      username: postgres
      password: 'postgres_secure_password'
  parameters:
    unix_socket_directories: '/var/run/postgresql'
  create_replica_methods:
    - basebackup
  basebackup:
    max-rate: 100M
    checkpoint: fast

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

تستخدم العقد الاحتياطية تكوينًا متطابقًا مع قيمnameوconnect_addressوlistenالخاصة بها. يتولى Patroni التعامل مع الباقي — فهو يكتشف ما إذا كانت العقدة يجب أن تكون رائدة أم نسخة طبق الأصل بناءً على حالة DCS ويقوم بتكوين PostgreSQL وفقًا لذلك.

وما إلى ذلك كمخزن التكوين الموزع

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

# Install and configure etcd on three dedicated nodes
# /etc/etcd/etcd.conf.yml — Node etcd1 (10.0.2.10)
name: etcd1
data-dir: /var/lib/etcd
listen-client-urls: http://0.0.0.0:2379
listen-peer-urls: http://0.0.0.0:2380
advertise-client-urls: http://10.0.2.10:2379
initial-advertise-peer-urls: http://10.0.2.10:2380
initial-cluster: etcd1=http://10.0.2.10:2380,etcd2=http://10.0.2.11:2380,etcd3=http://10.0.2.12:2380
initial-cluster-state: new
initial-cluster-token: patroni-etcd-cluster

# Start etcd
systemctl enable --now etcd

# Verify cluster health
etcdctl endpoint health --cluster \
  --endpoints=http://10.0.2.10:2379,http://10.0.2.11:2379,http://10.0.2.12:2379

بالنسبة لعمليات نشر الإنتاج، قم بتمكين TLS بين أقران etcd وبين عملاء etcd وعملاء Patroni. تعرض حركة مرور etcd غير المشفرة بيانات اعتماد المجموعة وتكوينها للمهاجمين على مستوى الشبكة.

HAProxy لتوجيه الاتصال

يعرض

Patroni REST API على كل عقدة (المنفذ 8008 افتراضيًا) الذي يُبلغ عما إذا كانت العقدة هي العقدة الرئيسية الحالية أو نسخة متماثلة. يستخدم HAProxy نقاط نهاية التحقق من السلامة هذه لتوجيه حركة المرور: تنتقل عمليات الكتابة إلى القائد، وتنتقل عمليات القراءة إلى النسخ المتماثلة السليمة. يمنحك هذا تقسيمًا تلقائيًا للقراءة والكتابة دون أي تغييرات على مستوى التطبيق.

# /etc/haproxy/haproxy.cfg
global
    maxconn 2000
    log /dev/log local0
    stats socket /var/run/haproxy.sock mode 660 level admin

defaults
    mode tcp
    log global
    retries 3
    timeout client 30m
    timeout connect 4s
    timeout server 30m
    timeout check 5s
    maxconn 1000

listen pg_write
    bind *:5000
    option httpchk GET /primary
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server node1 10.0.1.10:5432 check port 8008
    server node2 10.0.1.11:5432 check port 8008
    server node3 10.0.1.12:5432 check port 8008

listen pg_read
    bind *:5001
    balance roundrobin
    option httpchk GET /replica
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server node1 10.0.1.10:5432 check port 8008
    server node2 10.0.1.11:5432 check port 8008
    server node3 10.0.1.12:5432 check port 8008

listen stats
    bind *:7000
    mode http
    stats enable
    stats uri /
    stats refresh 10s

تقوم نقطة النهاية/primaryبإرجاع HTTP 200 فقط على قائد Patroni الحالي. تقوم نقطة النهاية/replicaبإرجاع 200 في وضع الاستعداد الصحي. عند حدوث تجاوز الفشل، يبدأ الملف الأساسي الجديد بإرجاع 200 على/primary، ويقوم HAProxy تلقائيًا بإعادة توجيه حركة مرور الكتابة — عادةً خلال فترة زمنية واحدة للتحقق من السلامة (3 ثوانٍ). ينهي توجيهon-marked-down shutdown-sessionsعلى الفور الاتصالات الحالية بالقائد الأساسي الفاشل، مما يجبر العملاء على إعادة الاتصال بالقائد الجديد.

PgBouncer لتجميع الاتصال

يقوم

PostgreSQL بإنشاء عملية خلفية جديدة لكل اتصال عميل. على نطاق واسع - مئات أو آلاف الخدمات الصغيرة التي تحتفظ كل منها بمجموعات الاتصال - يصبح الحمل الزائد لإنشاء العملية واستهلاك الذاكرة كبيرًا. يقع PgBouncer بين التطبيق وPostgreSQL، ويحافظ على مجموعة من الاتصالات من جانب الخادم ويضاعف اتصالات العميل عليها.

# /etc/pgbouncer/pgbouncer.ini
[databases]
* = host=127.0.0.1 port=5432 dbname=appdb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 10
reserve_pool_timeout = 3
server_lifetime = 3600
server_idle_timeout = 600
server_connect_timeout = 5
server_login_retry = 3

log_connections = 1
log_disconnections = 1
stats_period = 60

عند استخدامه مع Patroni، عادةً ما يكون PgBouncer موجودًا في نفس موقع كل عقدة PostgreSQL أو على عقد HAProxy. يعد وضع التجمعtransactionهو الخيار الأفضل لمعظم أحمال العمل - فهو يعين اتصال خادم طوال مدة المعاملة ويعيده إلى التجمع بين المعاملات. يعد هذا أكثر كفاءة بكثير من وضعsession، الذي يحتفظ باتصال لجلسة العميل بأكملها.

أرشفة WAL واسترداد النقاط في الوقت المناسب

يحمي النسخ المتماثل للبث

من فشل الخادم، ولكنه لا يحمي من الأخطاء المنطقية - يتم نسخDROP TABLEغير المقصود أو ترحيل التطبيق السيئ إلى جميع الاستعدادات على الفور. تتيح لك أرشفة WAL مع الاسترداد في الوقت المناسب (PITR) استعادة أي لحظة قبل حدوث الخطأ.

تكتمل نسخ أرشفة

WAL مقاطع WAL إلى أرشيف متين - عادةً ما يكون حاوية S3، أو حامل NFS، أو خادم نسخ احتياطي مخصص. تتعامل أدوات مثلpgBackRestوWAL-Gمع الأرشفة بكفاءة من خلال الضغط والتشفير والنقل المتوازي.

# pgBackRest configuration — /etc/pgbackrest/pgbackrest.conf
[global]
repo1-type=s3
repo1-s3-bucket=pg-wal-archive
repo1-s3-endpoint=s3.eu-west-1.amazonaws.com
repo1-s3-region=eu-west-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest
repo1-retention-full=4
repo1-retention-diff=7
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=strong_encryption_passphrase
compress-type=zst
compress-level=3
process-max=4

[pg-ha-cluster]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

# In postgresql.conf
archive_command = 'pgbackrest --stanza=pg-ha-cluster archive-push %p'
restore_command = 'pgbackrest --stanza=pg-ha-cluster archive-get %f "%p"'

لإجراء عملية استرداد في وقت محدد، حدد طابعًا زمنيًا مستهدفًا.

# Restore to a specific point in time
pgbackrest --stanza=pg-ha-cluster --type=time \
  --target="2026-04-12 11:25:00" \
  --target-action=promote \
  restore

النسخ المتماثل المنطقي لمزامنة البيانات الانتقائية

بينما يقوم النسخ المتماثل المتدفق بإنشاء نسخة فعلية دقيقة من مجموعة قاعدة البيانات بأكملها، يعمل النسخ المتماثل المنطقي على مستوى الجدول، مما يؤدي إلى تكرار الجداول الفردية أو مجموعات فرعية من البيانات بين مثيلات PostgreSQL المستقلة. يعد هذا مفيدًا لترقيات الإصدار الرئيسي بدون توقف، والنسخ المتماثلة للقراءة عبر المناطق التي تحتاج فقط إلى جداول محددة، وتغذية مستودع البيانات، وتوزيع البيانات على مستأجرين متعددين.

# On the publisher (source database)
wal_level = logical  # must be 'logical' — higher than 'replica'

CREATE PUBLICATION app_pub FOR TABLE orders, customers, products;

# On the subscriber (target database)
CREATE SUBSCRIPTION app_sub
  CONNECTION 'host=publisher-host port=5432 dbname=appdb user=replicator password=pass'
  PUBLICATION app_pub;

يمكن تشغيل النسخ المتماثل المنطقي جنبًا إلى جنب مع النسخ المتماثل المتدفق. النمط الشائع هو استخدام النسخ المتماثل المتدفق لـ HA (تجاوز الفشل الفعلي السريع) والنسخ المتماثل المنطقي للنسخ المتماثلة للتحليلات عبر المناطق التي تحتاج فقط إلى مجموعة فرعية من الجداول.

النسخ المتماثل للبث متعدد المناطق

للتعافي من الكوارث وأداء القراءة العالمي، يمكن أن تمتد مجموعات PostgreSQL إلى مناطق متعددة. النمط القياسي هو النسخ المتماثل المتزامن داخل المنطقة (لعدم فقدان البيانات عند تجاوز الفشل المحلي) والنسخ المتماثل غير المتزامن عبر المناطق (لتجنب عقوبات زمن الوصول عبر المناطق في كل عملية كتابة). كل منطقة لديها HAProxy الخاص بها لتوجيه القراءة المحلية.

النسخ المتماثل للبث PostgreSQL متعدد المناطقالمنطقة 1 — AWS الاتحاد الأوروبي الغربي-1الابتدائيpg-node1 (RW)مزامنة الاستعدادpg-node2 (RO)مزامنةHAProxy (محلي)المنطقة 2 - Azure غرب أوروباالاستعداد غير المتزامنpg-node3 (RO)الاستعداد غير المتزامنpg-node4 (RO)مزامنةHAProxy (محلي)المنطقة 3 - GCP أوروبا الغربية 1الاستعداد غير المتزامنpg-node5 (RO)الاستعداد غير المتزامنpg-node6 (RO)مزامنةHAProxy (محلي)غير متزامن وولغير متزامن وول الشحنأرشيف WAL المشترك (S3 / Blob / GCS)pgBackRest أو WAL-G — PITRعبر المناطقDNS العالمية (Route53 / مدير المرور / Cloud DNS)أسطورة:النسخ المتماثل للمزامنة (داخل المنطقة)النسخ المتماثل غير المتزامن (عبر المناطق)أرشفة WAL لتخزين الكائناتالابتدائيالاستعداد

إجراءات تجاوز الفشل والتحويل

يعد فهم الفرق بين تجاوز الفشل والتحويل أمرًا بالغ الأهمية. تجاوز فشلهو عرض ترويجي غير مخطط له ناتج عن فشل المرحلة الأساسية الحالية. يعد التحويلتغييرًا مخططًا ورائعًا للدور - يتم إجراؤه عادةً قبل الصيانة. يدعم باتروني كليهما.

التحول المخطط له

# List cluster members
patronictlctl -c /etc/patroni/patroni.yml list

# Perform switchover to a specific node
patronictlctl -c /etc/patroni/patroni.yml switchover \
  --master node1 --candidate node2 --force

# Or use the Patroni REST API
curl -s http://10.0.1.10:8008/switchover -XPOST \
  -d '{"leader": "node1", "candidate": "node2"}'

أثناء عملية التبديل، يقوم Patroni بتخفيض مستوى الانتخابات التمهيدية الحالية إلى وضع الاستعداد، وترقية المرشح المستهدف، وإعادة تكوين جميع الاستعدادات الأخرى لمتابعة الانتخابات التمهيدية الجديدة. تستغرق العملية 5-15 ثانية. يكتشف HAProxy التغيير من خلال عمليات التحقق من الصحة ويعيد توجيه حركة المرور تلقائيًا.

تسلسل تجاوز الفشل التلقائي

عندما يفشل الإعداد الأساسي بشكل غير متوقع، يتبع Patroni تسلسلًا دقيقًا لاستعادة الخدمة. ويوضح الرسم البياني التالي الخطوات.

Patroni تسلسل تجاوز الفشل التلقائي1فشلالأساسيتعطلأو قسم الشبكة أوفشل قرصعلى العقدة 12يكتشفPatroni عبر DCSتنتهي صلاحية مفتاحTTL فيوما إلى ذلك(الافتراضي 30 ثانية TTL)3انتخاب الزعيمسباقStandbys للحصول علىقفل الزعيمفي إلخ4في وضع الاستعداد تمت ترقيته إلىالفائز فييدير pg_ctl للترويج لـويصبحالأساسي الجديد5تحديثاتHAProxyتكتشف فحوصات الصحةالأساسي الجديد/ العائدات الأولية 200 على القائد الجديد6تمت إعادة توصيل عملاءبـيتم إعادة توصيل تطبيقاتعبر HAProxyإلىالأساسي الجديد بشفافيةإجمالي وقت تجاوز الفشل النموذجيانتهاء صلاحيةDCS TTL: ~15-30 ثانيةانتخاب: ~2-5 ثوانٍكشفHAProxy: ~3-10sأعد توصيل≈ 20-45 ثانية إجماليالمعلمات الرئيسية التي تؤثر على سرعة تجاوز الفشل:• ttl (30 ثانية افتراضية) — كم من الوقت قبل انتهاء صلاحية مفتاح القائد في DCS• حلقة الانتظار (10 ثوانٍ افتراضية) — عدد المرات التي يتحقق فيها Patroni من حالة المجموعة• retry_timeout (العشرات الافتراضية) — المهلة لعمليات DCS وPostgreSQL•max_lag_on_failover (1 ميجابايت) — فقط قم بتعزيز الاستعدادات خلال تأخر النسخ المتماثل هذا

منع انقسام الدماغ

إن تقسيم الدماغ

- حيث تعتقد عقدتان في نفس الوقت أنهما العقدة الأساسية - هو أخطر وضع فشل في أي نظام HA. يمنع باتروني انقسام الدماغ من خلال عدة آليات:

  1. قفل القائد المستند إلى DCS:يمكن لعقدة واحدة فقط الاحتفاظ بمفتاح القائد في إلخ في أي وقت. المفتاح به TTL ويجب على القائد تجديده بشكل مستمر. إذا قام قسم الشبكة بعزل القائد عن etcd، فستنتهي صلاحية المفتاح، ويخفض القائد نفسه.
  2. Watchdog: يمكن لـPatroni تكوين جهاز مراقبة Linux (/dev/watchdog). إذا فقد Patroni الوصول إلى DCS ولم يتمكن من تأكيد أنه يجب أن يظل قائدًا، فسوف تقوم هيئة المراقبة بإعادة تشغيل العقدة أو إيقاف تشغيلها - وهي آلية سياج قوية تضمن عدم استمرار العقدة الأولية القديمة في قبول عمليات الكتابة.
  3. pg_rewind:عندما تعود المرحلة الابتدائية السابقة إلى الاتصال بالإنترنت مرة أخرى، قد تحتوي على سجلات WAL لم يتم نسخها مطلقًا. يقومpg_rewindبإرجاع المخطط الزمني إلى نقطة الاختلاف، مما يسمح للعقدة بالانضمام مرة أخرى كوضع احتياطي بدون نسخة احتياطية أساسية كاملة. يقوم إعدادuse_pg_rewind: trueالخاص بـ Patroni بأتمتة هذا الأمر.
# Enable watchdog in Patroni config
bootstrap:
  dcs:
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_log_hints: 'on'  # required for pg_rewind

# Watchdog configuration
watchdog:
  mode: required        # 'off', 'automatic', or 'required'
  device: /dev/watchdog
  safety_margin: 5      # seconds before TTL expiry to trigger watchdog

remgr كبديل لـ Patroni

rempgrهي أداة HA شائعة أخرى لـ PostgreSQL. فهو يوفر إدارة الاستعداد، وتجاوز الفشل التلقائي، وقدرات التحويل. ومع ذلك، فإنه يأخذ نهجا مختلفا جذريا عن باتروني. يستخدم rempgr عقدة شاهدة وبرنامج خفي (repmgrd) لاكتشاف الفشل بدلاً من مخزن الإجماع الموزع. وهذا يجعل النشر أسهل ولكنه أكثر عرضة للانقسام في سيناريوهات تقسيم الشبكة المعقدة.

# repmgr.conf on the primary
node_id=1
node_name='node1'
conninfo='host=10.0.1.10 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/16/main'
failover=automatic
promote_command='repmgr standby promote -f /etc/repmgr.conf --log-to-file'
follow_command='repmgr standby follow -f /etc/repmgr.conf --log-to-file --upstream-node-id=%n'
monitoring_history=yes
monitor_interval_secs=5
reconnect_attempts=6
reconnect_interval=10

بالنسبة لعمليات النشر الجديدة، يعد Patroni هو الخيار الموصى به نظرًا لما يوفره من ضمانات أقوى لمنع انقسام الدماغ ومجتمع تطوير أكثر نشاطًا. يظل rempgr خيارًا معقولًا للإعدادات أو المؤسسات الأبسط التي استثمرت بالفعل في الأداة.

أنماط نشر السحابة

نشر

AWS: EC2، وEBS، وRoute53

في AWS، قم بنشر كل عقدة PostgreSQL + Patroni على مثيل EC2 مع وحدات تخزين EBS gp3 أو io2. استخدم مثيلات منفصلة عبر مناطق توافر الخدمات المتعددة لـ HA. العقد etcd يجب أن تمتد أيضًا إلى مناطق الوصول.

# Terraform sketch for PostgreSQL HA on AWS
resource "aws_instance" "pg_node" {
  count                = 3
  ami                  = "ami-0abcdef1234567890"  # Ubuntu 22.04
  instance_type        = "r6g.2xlarge"             # 8 vCPU, 64GB RAM
  subnet_id            = aws_subnet.private[count.index].id
  vpc_security_group_ids = [aws_security_group.pg_sg.id]
  availability_zone    = element(["eu-west-1a", "eu-west-1b", "eu-west-1c"], count.index)

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
  }

  tags = {
    Name = "pg-node-${count.index + 1}"
    Role = "patroni"
  }
}

resource "aws_ebs_volume" "pg_data" {
  count             = 3
  availability_zone = element(["eu-west-1a", "eu-west-1b", "eu-west-1c"], count.index)
  size              = 500
  type              = "gp3"
  iops              = 6000
  throughput        = 250
  encrypted         = true

  tags = {
    Name = "pg-data-${count.index + 1}"
  }
}

resource "aws_route53_health_check" "pg_primary" {
  count             = 3
  ip_address        = aws_instance.pg_node[count.index].private_ip
  port              = 8008
  type              = "HTTP"
  resource_path     = "/primary"
  failure_threshold = 3
  request_interval  = 10
}

استخدم Network Load Balancer (NLB) بدلاً من HAProxy إذا كنت تفضل الحل المُدار بواسطة AWS. يمكن لـ NLB استخدام فحوصات صحة المجموعة المستهدفة مقابل Patroni REST API لتوجيه حركة المرور إلى المرحلة الأساسية الحالية.

نشر

Azure: الأجهزة الافتراضية والأقراص المُدارة وAzure LB

في الطراز Azure، استخدم الأجهزة الافتراضية Standard_E8s_v5 (المحسنة للذاكرة) مع أقراص SSD المُدارة المتميزة لأحجام البيانات. النشر عبر مناطق توافر الخدمات. يوفر Azure Load Balancer ما يعادل HAProxy مع تحقيقات الصحة ضد Patroni REST API.

# Azure CLI — create PostgreSQL VM with Managed Disk
az vm create \
  --resource-group pg-ha-rg \
  --name pg-node-1 \
  --image Canonical:0001-com-ubuntu-server-jammy:22_04-lts:latest \
  --size Standard_E8s_v5 \
  --zone 1 \
  --vnet-name pg-vnet \
  --subnet pg-subnet \
  --nsg pg-nsg \
  --admin-username pgadmin \
  --ssh-key-value ~/.ssh/id_rsa.pub

az disk create \
  --resource-group pg-ha-rg \
  --name pg-data-1 \
  --size-gb 512 \
  --sku Premium_LRS \
  --zone 1

az vm disk attach \
  --resource-group pg-ha-rg \
  --vm-name pg-node-1 \
  --name pg-data-1

# Azure Load Balancer health probe for Patroni
az network lb probe create \
  --resource-group pg-ha-rg \
  --lb-name pg-lb \
  --name patroni-primary-probe \
  --protocol Http \
  --port 8008 \
  --path /primary \
  --interval 5 \
  --threshold 3
نشر

GCP: محرك الحوسبة وموازنة التحميل السحابي

على GCP، استخدم مثيلات n2-highmem-8 (8 vCPU، ذاكرة الوصول العشوائي (RAM) سعة 64 جيجابايت) مع أقراص SSD الثابتة. التوزيع عبر المناطق داخل المنطقة. استخدم موازن تحميل TCP/UDP داخلي مع فحوصات صحة Patroni.

# GCP — create instance and persistent disk
gcloud compute instances create pg-node-1 \
  --zone=europe-west1-b \
  --machine-type=n2-highmem-8 \
  --image-family=ubuntu-2204-lts \
  --image-project=ubuntu-os-cloud \
  --boot-disk-size=50GB \
  --network=pg-network \
  --subnet=pg-subnet

gcloud compute disks create pg-data-1 \
  --zone=europe-west1-b \
  --size=500GB \
  --type=pd-ssd

gcloud compute instances attach-disk pg-node-1 \
  --disk=pg-data-1 \
  --zone=europe-west1-b

# Health check for Patroni primary endpoint
gcloud compute health-checks create http patroni-primary-check \
  --port=8008 \
  --request-path=/primary \
  --check-interval=5s \
  --timeout=5s \
  --unhealthy-threshold=3 \
  --healthy-threshold=2
نشر

المعدن العاري k3s مع Rancher وLonghorn

بالنسبة للمؤسسات التي تقوم بتشغيل أجهزتها الخاصة، فإن نشر PostgreSQL HA على المعدن مع k3s وRancher وLonghorn يوفر بنية أساسية مفتوحة المصدر ومستقلة عن السحابة تمامًا. k3s عبارة عن توزيعة Kubernetes خفيفة الوزن تعمل بكفاءة على الخوادم المعدنية دون تحميل توزيع Kubernetes الكامل.

المعدن العاري k3s HA — PostgreSQL مع PatroniIP الظاهري (Keepalived VRRP) - 10.0.0.100Floating VIP لـ HAProxy النشط/الاستعدادHAProxy (نشط)معدن عاري lb1HAProxy (الاستعداد)معدن عاري lb2مجموعةk3s (تديرها Rancher)k3s العقدة 1 (الخادم)PostgreSQL الابتدائيباتروني + PgBouncerحجمذو القرون الطويلة (500 جيجابايت)NVMe SSD — المعدن العاري srv1k3s العقدة 2 (الخادم)PostgreSQL الاستعداد 1باتروني + PgBouncerحجم قرون طويلة (500 جيجابايت)NVMe SSD — المعدن العاري srv2k3s العقدة 3 (الخادم)PostgreSQL الاستعداد 2باتروني + PgBouncerحجمذو القرون الطويلة (500 جيجابايت)NVMe SSD — المعدن العاري srv3مجموعةالخارجية إلخ (3 عقد مخصصة)إلخ d1 (10.0.3.10) · إلخ d2 (10.0.3.11) · إلخ d3 (10.0.3.12)إدارة المزارعواجهة المستخدم+ دورة حياة المجموعةالابتدائيالاستعدادإلخقرون طويلةهابروكسييظهر النسخ المتماثل للبث على شكل أسهم خضراء متقطعة

k3s وإعداد Longhorn

# Install k3s on the first server node
curl -sfL https://get.k3s.io | K3S_TOKEN=my-cluster-token \
  INSTALL_K3S_EXEC="server --cluster-init --disable traefik --disable servicelb" sh -

# Join additional server nodes
curl -sfL https://get.k3s.io | K3S_TOKEN=my-cluster-token \
  K3S_URL=https://10.0.0.1:6443 \
  INSTALL_K3S_EXEC="server" sh -

# Install Longhorn for distributed block storage
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system --create-namespace \
  --set defaultSettings.defaultDataPath=/mnt/longhorn \
  --set defaultSettings.replicaCount=3 \
  --set defaultSettings.storageMinimalAvailablePercentage=15

# Deploy PostgreSQL with Patroni using the Zalando Postgres Operator
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
helm install postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-system --create-namespace
# PostgreSQL cluster manifest for the Zalando Postgres Operator
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-ha-cluster
  namespace: production
spec:
  teamId: "platform"
  numberOfInstances: 3
  volume:
    size: 500Gi
    storageClass: longhorn
  users:
    appuser:
      - superuser
      - createdb
    replicator: []
  databases:
    appdb: appuser
  postgresql:
    version: "16"
    parameters:
      shared_buffers: "16GB"
      effective_cache_size: "48GB"
      work_mem: "256MB"
      maintenance_work_mem: "2GB"
      max_connections: "200"
      max_wal_senders: "10"
      wal_level: replica
      synchronous_commit: "on"
      wal_keep_size: "2GB"
      archive_mode: "on"
      track_commit_timestamp: "on"
  patroni:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    synchronous_mode: true
  resources:
    requests:
      cpu: "4"
      memory: 32Gi
    limits:
      cpu: "8"
      memory: 64Gi

تم الحفاظ عليه لـ HAProxy VIP

# /etc/keepalived/keepalived.conf on lb1
vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 2
    weight 2
}

vrrp_instance VI_PG {
    state MASTER
    interface eth0
    virtual_router_id 52
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass pgha_vip_pass
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        chk_haproxy
    }
}
مراقبة

النسخ المتماثل PostgreSQL

مراقبة صحة النسخ غير قابلة للتفاوض في الإنتاج. يوفر PostgreSQL العديد من طرق العرض المضمنة لهذا الغرض، ويوفر Prometheus مع Grafana الرؤية والتنبيه على المدى الطويل الذي تحتاجه.

استعلامات المراقبة المدمجة

-- Check replication status on the primary
SELECT
    client_addr,
    application_name,
    state,
    sync_state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    (sent_lsn - replay_lsn) AS replication_lag_bytes,
    write_lag,
    flush_lag,
    replay_lag
FROM pg_stat_replication;

-- Check replication slot status
SELECT
    slot_name,
    slot_type,
    active,
    wal_status,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS slot_lag
FROM pg_replication_slots;

-- Check standby recovery status (run on standby)
SELECT
    pg_is_in_recovery() AS is_standby,
    pg_last_wal_receive_lsn() AS last_received,
    pg_last_wal_replay_lsn() AS last_replayed,
    pg_last_xact_replay_timestamp() AS last_replayed_timestamp,
    EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int AS replay_lag_seconds;

-- Monitor WAL generation rate
SELECT
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0')) AS total_wal_generated,
    pg_size_pretty(sum(size)) AS wal_directory_size
FROM pg_ls_waldir();

-- Check for long-running queries that could block replication
SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'
  AND state != 'idle'
ORDER BY duration DESC;

Prometheus وGrafana ستاك

يعرضpostgres_exporterمقاييس PostgreSQL بتنسيق Prometheus. بالدمج معPatoni_exporter، يمكنك الحصول على رؤية كاملة لكل من أداء قاعدة البيانات وحالة مجموعة HA.

# Deploy postgres_exporter as a sidecar or standalone
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# Custom queries for postgres_exporter
# /etc/postgres_exporter/queries.yaml
pg_replication_lag:
  query: |
    SELECT
      CASE WHEN pg_is_in_recovery() THEN
        EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::float
      ELSE 0 END AS lag_seconds
  master: true
  metrics:
    - lag_seconds:
        usage: "GAUGE"
        description: "Replication lag in seconds"

pg_replication_slots:
  query: |
    SELECT
      slot_name,
      active::int AS active,
      pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)::float AS slot_lag_bytes
    FROM pg_replication_slots
  master: true
  metrics:
    - slot_name:
        usage: "LABEL"
    - active:
        usage: "GAUGE"
        description: "Whether the slot is active"
    - slot_lag_bytes:
        usage: "GAUGE"
        description: "Slot lag in bytes"
# PrometheusRule for PostgreSQL HA alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: postgresql-ha-alerts
  namespace: monitoring
spec:
  groups:
    - name: postgresql-replication
      rules:
        - alert: PostgreSQLReplicationLagHigh
          expr: pg_replication_lag_seconds > 30
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "PostgreSQL replication lag exceeds 30s on {{ $labels.instance }}"

        - alert: PostgreSQLReplicationSlotInactive
          expr: pg_replication_slots_active == 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Replication slot {{ $labels.slot_name }} is inactive"

        - alert: PostgreSQLReplicationSlotLagHigh
          expr: pg_replication_slots_slot_lag_bytes > 1073741824
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Replication slot lag exceeds 1GB on {{ $labels.slot_name }}"

        - alert: PatroniClusterUnhealthy
          expr: patroni_cluster_members_count < 3
          for: 2m
          labels:
            severity: critical
          annotations:
            summary: "Patroni cluster has fewer than 3 members"

معلمات ضبط الإنتاج

التكوين الافتراضي لـ

PostgreSQL متحفظ، وتم ضبطه ليناسب بيئة استضافة مشتركة صغيرة. تتطلب مجموعات HA الإنتاج ضبطًا دقيقًا لمعلمات النسخ المتماثل والذاكرة وWAL. يلخص الجدول التالي أهم الإعدادات لخادم ذاكرة الوصول العشوائي (RAM) بسعة 64 جيجابايت مع تخزين NVMe.

# postgresql.conf — Production HA tuning

# === Replication ===
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 4GB
synchronous_commit = on
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
track_commit_timestamp = on
wal_log_hints = on

# === WAL ===
min_wal_size = 1GB
max_wal_size = 8GB
wal_buffers = 64MB
wal_compression = zstd
archive_mode = on
archive_timeout = 300
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min

# === Memory ===
shared_buffers = 16GB              # 25% of RAM
effective_cache_size = 48GB        # 75% of RAM
work_mem = 256MB                   # per-operation sort/hash memory
maintenance_work_mem = 2GB         # for VACUUM, CREATE INDEX
huge_pages = try

# === Connections ===
max_connections = 200              # use PgBouncer for higher client counts
superuser_reserved_connections = 5

# === Query Performance ===
random_page_cost = 1.1             # SSD storage
effective_io_concurrency = 200     # NVMe SSD
default_statistics_target = 500
jit = on

# === Logging ===
log_min_duration_statement = 500   # log queries > 500ms
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0
log_autovacuum_min_duration = 0

# === Autovacuum ===
autovacuum_max_workers = 4
autovacuum_naptime = 30s
autovacuum_vacuum_cost_limit = 2000
autovacuum_vacuum_scale_factor = 0.05
autovacuum_analyze_scale_factor = 0.02

ضبط معلمات Patroni DCS

تؤثر العلاقة بين معلمات Patronittlوloop_waitوretry_timeoutبشكل مباشر على سرعة تجاوز الفشل والمخاطر الإيجابية الخاطئة. يعني TTL الأقصر اكتشافًا أسرع لتجاوز الفشل ولكنه يزيد من خطر تجاوز الفشل غير الضروري أثناء الومضات القصيرة للشبكة.

# Conservative (production default)
ttl: 30
loop_wait: 10
retry_timeout: 10
# Failover detection: ~30-40 seconds

# Aggressive (low-latency failover)
ttl: 15
loop_wait: 5
retry_timeout: 5
# Failover detection: ~15-20 seconds
# Warning: Higher risk of false failovers in unstable networks

هندسة الفوضى واختبار الفشل

نظام تجاوز الفشل الذي لم يتم اختباره مطلقًا هو نظام لا يعمل. تطبق هندسة الفوضى حالات الفشل الخاضعة للتحكم للتحقق من أن إعداد HA الخاص بك يعمل بشكل صحيح في ظل ظروف الفشل الحقيقية. يجب أن تخضع كل مجموعة من مجموعات Patroni لتدريبات منتظمة على تجاوز الفشل.

دليل التشغيل لاختبار تجاوز الفشل

# 1. Verify cluster health before testing
patronictlctl -c /etc/patroni/patroni.yml list
+----------+---------+---------+----+-----------+
| Member   | Host    | Role    | TL | Lag in MB |
+----------+---------+---------+----+-----------+
| node1    | 10.0.1.10| Leader |  5 |           |
| node2    | 10.0.1.11| Replica |  5 |         0 |
| node3    | 10.0.1.12| Replica |  5 |         0 |
+----------+---------+---------+----+-----------+

# 2. Simulate primary crash (on node1)
sudo systemctl stop patroni
# Or more aggressive: sudo kill -9 $(pgrep -f patroni)

# 3. Monitor failover (from any node with patronictl)
watch -n 1 'patronictl -c /etc/patroni/patroni.yml list'

# 4. Verify new leader is elected (within 30-45 seconds)
# Expected: node2 or node3 promoted to Leader

# 5. Test write availability through HAProxy
PGPASSWORD=app_password psql -h haproxy-host -p 5000 -U appuser -d appdb \
  -c "INSERT INTO health_check (ts) VALUES (now()) RETURNING *;"

# 6. Restart the former primary
sudo systemctl start patroni
# Patroni will use pg_rewind to rejoin as a replica

# 7. Verify the former primary rejoins as replica
patronictlctl -c /etc/patroni/patroni.yml list

اختبار قسم الشبكة

# Simulate network partition on the primary using iptables
# Block all traffic to etcd from the primary
sudo iptables -A OUTPUT -d 10.0.2.10 -j DROP
sudo iptables -A OUTPUT -d 10.0.2.11 -j DROP
sudo iptables -A OUTPUT -d 10.0.2.12 -j DROP

# Expected behaviour:
# 1. Primary loses DCS access
# 2. Leader key TTL expires
# 3. Primary demotes itself (with watchdog, node may reboot)
# 4. Standby acquires leader lock and promotes
# 5. After clearing iptables rules, former primary rejoins as replica

# Clean up
sudo iptables -D OUTPUT -d 10.0.2.10 -j DROP
sudo iptables -D OUTPUT -d 10.0.2.11 -j DROP
sudo iptables -D OUTPUT -d 10.0.2.12 -j DROP

اختبار الفوضى الآلي باستخدام Toxiproxy

# Run Toxiproxy alongside your Patroni cluster
# Create proxies for etcd and replication connections
toxiproxy-cli create etcd_proxy -l 0.0.0.0:12379 -u 10.0.2.10:2379
toxiproxy-cli create pg_repl_proxy -l 0.0.0.0:15432 -u 10.0.1.10:5432

# Add latency to etcd connections (simulates degraded network)
toxiproxy-cli toxic add etcd_proxy -t latency -a latency=500 -a jitter=200

# Add bandwidth limit to replication (simulates WAN replication)
toxiproxy-cli toxic add pg_repl_proxy -t bandwidth -a rate=1024

# Completely sever the connection (simulates network partition)
toxiproxy-cli toxic add etcd_proxy -t timeout -a timeout=0

# Monitor Patroni behaviour and verify correct failover
watch -n 2 'curl -s http://10.0.1.10:8008/patroni | python3 -m json.tool'

البرنامج النصي للتحقق المستمر

#!/bin/bash
# continuous_ha_check.sh — Run during chaos tests to measure availability

HAPROXY_HOST="10.0.0.100"
WRITE_PORT=5000
READ_PORT=5001
DATABASE="appdb"
USER="appuser"
LOGFILE="/var/log/ha_test_$(date +%Y%m%d_%H%M%S).log"

write_count=0
write_fail=0
read_count=0
read_fail=0

while true; do
    ts=$(date '+%Y-%m-%d %H:%M:%S.%3N')

    # Test write path
    if PGPASSWORD=app_password psql -h $HAPROXY_HOST -p $WRITE_PORT \
       -U $USER -d $DATABASE -c "SELECT 1" &>/dev/null; then
        ((write_count++))
    else
        ((write_fail++))
        echo "$ts WRITE_FAIL total_fails=$write_fail" >> $LOGFILE
    fi

    # Test read path
    if PGPASSWORD=app_password psql -h $HAPROXY_HOST -p $READ_PORT \
       -U $USER -d $DATABASE -c "SELECT 1" &>/dev/null; then
        ((read_count++))
    else
        ((read_fail++))
        echo "$ts READ_FAIL total_fails=$read_fail" >> $LOGFILE
    fi

    total=$((write_count + write_fail))
    if (( total % 100 == 0 )); then
        write_avail=$(echo "scale=2; $write_count * 100 / $total" | bc)
        read_total=$((read_count + read_fail))
        read_avail=$(echo "scale=2; $read_count * 100 / $read_total" | bc)
        echo "$ts Writes: ${write_avail}% ($write_count/$total) Reads: ${read_avail}% ($read_count/$read_total)"
    fi

    sleep 0.5
done

المتقدم: النسخ المتماثل المتتالي وتأخر الاستعداد

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

# postgresql.auto.conf on a cascading standby
primary_conninfo = 'host=standby1-host port=5432 user=replicator application_name=cascade1'
primary_slot_name = 'cascade1_slot'

وضع الاستعداد المؤجليطبقسجلات WAL عمدًا مع تأخير زمني - عادةً من 1 إلى 4 ساعات. يوفر هذا دفاعًا ضد الأخطاء المنطقية (عمليات الحذف غير المقصودة، وعمليات الترحيل السيئة) التي يتم نسخها على الفور إلى وحدات الاستعداد المتزامنة. في حالة حدوث كارثة، يمكنك إيقاف إعادة تشغيل WAL في وضع الاستعداد المؤجل واستعادة البيانات قبل حدوث الخطأ.

# postgresql.conf on delayed standby
recovery_min_apply_delay = '1h'

استراتيجيات سلسلة الاتصال

يجب دائمًا أن تتصل تطبيقات

التي تتصل بمجموعة يديرها Patroni عبر HAProxy أو تستخدم سلسلة اتصال PostgreSQL المضمنة متعددة المضيفين معtarget_session_attrs. يوفر هذا تجاوز الفشل من جانب العميل دون الاعتماد على موازن التحميل.

# Multi-host connection string with target_session_attrs
# The client tries each host in order and connects to the one matching the target attribute
postgresql://appuser:password@node1:5432,node2:5432,node3:5432/appdb?target_session_attrs=read-write&sslmode=require

# For read-only connections
postgresql://appuser:password@node1:5432,node2:5432,node3:5432/appdb?target_session_attrs=prefer-standby&sslmode=require

يعمل هذا الأسلوب بشكل جيد مع التطبيقات التي لا يمكن إعادة تكوينها بسهولة للإشارة إلى HAProxy VIP. تتعامل مكتبة عميل PostgreSQL (libpq) مع تجاوز الفشل بشفافية.

تقوية الأمان

يجب أن تقوم مجموعة PostgreSQL HA الخاصة بالإنتاج بفرض التشفير أثناء النقل وأثناء الراحة، واستخدام مصادقة قوية، والحد من التعرض للشبكة.

# Enable TLS in postgresql.conf
ssl = on
ssl_cert_file = '/etc/postgresql/certs/server.crt'
ssl_key_file = '/etc/postgresql/certs/server.key'
ssl_ca_file = '/etc/postgresql/certs/ca.crt'
ssl_min_protocol_version = 'TLSv1.3'

# Require TLS for all connections in pg_hba.conf
hostssl replication replicator 10.0.0.0/16 scram-sha-256
hostssl all         all        10.0.0.0/16 scram-sha-256

# etcd TLS
# In Patroni config
etcd3:
  hosts:
    - 10.0.2.10:2379
    - 10.0.2.11:2379
    - 10.0.2.12:2379
  protocol: https
  cacert: /etc/patroni/certs/etcd-ca.crt
  cert: /etc/patroni/certs/etcd-client.crt
  key: /etc/patroni/certs/etcd-client.key
استراتيجية النسخ الاحتياطي

لمجموعات HA

يجب أن تتضمن إستراتيجية النسخ الاحتياطي الشاملة لمجموعات Patroni أرشفة WAL المستمرة، والنسخ الاحتياطي الكامل المنتظم، والنسخ الاحتياطي التفاضلي أو المتزايد بين النسخ الاحتياطية الكاملة. pgBackRest هي الأداة الموصى بها لإدارة النسخ الاحتياطية لـ PostgreSQL للإنتاج.

# Schedule backups via cron
# Full backup weekly (Sunday 2 AM)
0 2 * * 0 pgbackrest --stanza=pg-ha-cluster --type=full backup

# Differential backup daily (2 AM, Mon-Sat)
0 2 * * 1-6 pgbackrest --stanza=pg-ha-cluster --type=diff backup

# Verify backup integrity
pgbackrest --stanza=pg-ha-cluster --set=latest info

# Verify backup can be restored (dry run)
pgbackrest --stanza=pg-ha-cluster --set=latest verify

# List all backups
pgbackrest --stanza=pg-ha-cluster info
            full backup: 20260412-020000F
                timestamp: 2026-04-12 02:00:00 +0000
                wal start/stop: 000000050000000000000040 / 000000050000000000000042
                database size: 150GB, backup size: 150GB
                repository size: 45GB (compressed)
            diff backup: 20260412-020000F_20260413-020000D
                timestamp: 2026-04-13 02:00:00 +0000
                database size: 151GB, backup size: 2.1GB
                repository size: 650MB (compressed)
ملخص دليل التشغيل

يجب على كل فريق يدير مجموعة Patroni أن يحتفظ بدليل تشغيل يغطي السيناريوهات التالية. إن وجود إجراءات موثقة ومختبرة يحول الانقطاع المجهد إلى عملية روتينية.

# === Quick Reference Commands ===

# Cluster status
patronictlctl -c /etc/patroni/patroni.yml list
patronictlctl -c /etc/patroni/patroni.yml history

# Planned switchover
patronictlctl -c /etc/patroni/patroni.yml switchover --master node1 --candidate node2

# Restart PostgreSQL on a specific node (rolling restart)
patronictlctl -c /etc/patroni/patroni.yml restart pg-ha-cluster node2

# Reload PostgreSQL configuration without restart
patronictlctl -c /etc/patroni/patroni.yml reload pg-ha-cluster

# Pause automatic failover (during maintenance)
patronictlctl -c /etc/patroni/patroni.yml pause

# Resume automatic failover
patronictlctl -c /etc/patroni/patroni.yml resume

# Edit DCS configuration (applies to all nodes)
patronictlctl -c /etc/patroni/patroni.yml edit-config

# Reinitialise a failed replica
patronictlctl -c /etc/patroni/patroni.yml reinit pg-ha-cluster node3

# Check Patroni REST API directly
curl -s http://10.0.1.10:8008/patroni | python3 -m json.tool
curl -s http://10.0.1.10:8008/cluster | python3 -m json.tool

قياس الأداء

قبل الانتقال إلى الإنتاج، قم بقياس مجموعة HA الخاصة بك لإنشاء أداء أساسي والتحقق من أن زمن استجابة النسخ المتماثل المتزامن مقبول لأعباء العمل لديك.

# Benchmark with pgbench — initialise test data
pgbench -i -s 100 -h haproxy-host -p 5000 -U appuser appdb

# Run write-heavy benchmark (measures sync replication impact)
pgbench -h haproxy-host -p 5000 -U appuser -c 32 -j 8 -T 300 appdb
# Compare with async: temporarily set synchronous_commit = off

# Run read-only benchmark through read replica port
pgbench -h haproxy-host -p 5001 -U appuser -c 64 -j 16 -T 300 -S appdb

# Measure failover impact on transactions
# Run pgbench in background, then trigger a failover
pgbench -h haproxy-host -p 5000 -U appuser -c 8 -j 4 -T 600 appdb &
sleep 60 && patronictl switchover --master node1 --candidate node2 --force
استنتاج

PostgreSQL لا يعد التوفر العالي الأصلي مع Patroni حلاً بأداة واحدة - بل هو نظام متكامل لنسخ البث المتدفق، والإجماع الموزع، وتوجيه الاتصال، وتجميع الاتصال، وأرشفة WAL، والمراقبة، والانضباط التشغيلي. تعالج كل طبقة وضع فشل محدد: النسخ المتماثل المتدفق يعالج تكرار البيانات، ويتعامل Patroni مع تنسيق تجاوز الفشل التلقائي، وما إلى ذلك يوفر الإجماع الموزع اللازم لانتخاب القائد دون انقسام الدماغ، ويقوم HAProxy بتوجيه الاتصالات إلى القائد الصحيح، ويدير PgBouncer حمل الاتصال على نطاق واسع، وتوفر أرشفة WAL باستخدام pgBackRest خط الدفاع الأخير ضد الأخطاء المنطقية والتعافي من الكوارث.

تختلف أنماط النشر عبر البيئات — AWS مع NLB وRoute53، وAzure مع مناطق توافر الخدمات وAzure Load Balancer، وGCP مع مجموعات المثيلات الإقليمية المُدارة، أو المعدن غير المتضمن مع k3s، وLonghorn، وKeepalived — لكن البنية الأساسية تظل كما هي. ثلاث عقد PostgreSQL أو أكثر تتم إدارتها بواسطة Patroni، مدعومة بمجموعة من ثلاث عقد وغيرها، أمام موازن تحميل يتبع نقاط نهاية فحص الصحة الخاصة بـ Patroni.

إن الاستثمار الأكثر أهمية الذي يمكنك القيام به ليس في التكوين - بل في الاختبار. تشغيل تدريبات تجاوز الفشل شهريًا. حقن أقسام الشبكة. قتل العمليات بشكل غير متوقع. قياس وقت الاسترداد وفقدان البيانات. أنشئ لوحات معلومات تعرض تأخر النسخ المتماثل، ومعدل إنشاء WAL، وتشبع تجمع الاتصال، وصحة DCS في الوقت الفعلي. إن الثقة التي تكتسبها من الاختبار المنهجي هي ما يفصل بين المجموعة التي تنجو من أول انقطاع حقيقي لها عن تلك التي تحول فشل الخادم إلى حادث يؤثر على الأعمال.

يمنحك

PostgreSQL كافة أساسيات النسخ المتماثل. يمنحك Patroni التنسيق. etcd يمنحك الإجماع. وتتمثل مهمتك في ربطها معًا بشكل صحيح، وضبطها لتناسب حجم عملك، والتحقق من صحتها بشكل مستمر. لقد أعطاك هذا الدليل المخططات - يمكنك الآن البناء والاختبار والتشغيل بثقة.