أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Read Replicas في PostgreSQL للمتوسط: وزّع 80% من القراءات بدون تعديل سطر كود

📅 ١٠ مايو ٢٠٢٦⏱ 5 دقائق قراءة
Read Replicas في PostgreSQL للمتوسط: وزّع 80% من القراءات بدون تعديل سطر كود
المستوى: متوسط · زمن القراءة المتوقع: 9 دقائق · الفرضية: عندك خدمة PostgreSQL إنتاجية بـ 5 جيجا بيانات على الأقل، ومعظم الـ workload قراءة (≥ 70%).

لو كل الـ dashboards بتاعتك بتفتح في 4.8 ثانية الساعة 9 الصبح، والسيرفر الواحد PostgreSQL بياكل CPU 92%، أنت مش محتاج تكبّر الـ instance. أنت محتاج تفصل القراءة عن الكتابة. Read Replica بتقفل المعادلة دي بدون ما تلمس سطر كود في التطبيق، وبتنزّل P95 من 480ms لـ 38ms على نفس التكلفة تقريبًا.

Read Replicas في PostgreSQL: لماذا instance واحد لا يكفي بعد 8K طلب/دقيقة

صفوف خوادم في مركز بيانات تمثل قواعد بيانات PostgreSQL متعددة موزّعة كنسخ قراءة

المشكلة باختصار

PostgreSQL الافتراضي بيشغّل process واحد لكل اتصال، والـ buffer pool واحد، والـ WAL writer واحد. لمّا تيجي 8K طلب/دقيقة بـ 70% منهم SELECT و 30% INSERT/UPDATE، الـ writes بتاخد lock على نفس الـ pages اللي الـ reads محتاجاها. النتيجة: queries بسيطة بتاخد 480ms لأن أنا بستنّى writes تخلص.

تخيّل المكتبة العامة (للمبتدئ)

تخيّل مكتبة عامة فيها 200 طالب جايين يستعيروا كتب، و 5 موظفين بيرتّبوا الرفوف ويسجّلوا كتب جديدة. الـ 200 طالب لازم يستنّوا لمّا الموظف يخلّص الترتيب علشان الرف ميتحركش وهم بيدوّروا. لو عملنا فرعين للمكتبة (نسخة من نفس الكتب) وقلنا "الفرع الأول للقراءة بس، الفرع التاني للموظفين والترتيب"، الـ 200 طالب يبقوا أحرار. ده اللي بيحصل بالظبط مع Read Replicas.

التعريف العلمي الدقيق

Read Replica في PostgreSQL هي instance ثانوي (Hot Standby) بتستقبل WAL stream (Write-Ahead Log) من الـ primary بشكل غير متزامن أو شبه متزامن، وتطبّق نفس التغييرات على نسختها من البيانات. الميكانيكية الرسمية اسمها Streaming Replication وموثّقة في PostgreSQL 16 Documentation – Chapter 27. الـ replica بترفض أي عملية كتابة برّيق cannot execute UPDATE in a read-only transaction، فالتطبيق بيعرف يوصلها للـ reads فقط بأمان.

الخطوات العملية: من Primary واحد إلى Primary + Replica

هنفترض إنك شغّال PostgreSQL 16 على Ubuntu 22.04، الـ primary على 10.0.0.5، والـ replica الجديدة على 10.0.0.6.

1) على الـ primary: اسمح بالـ replication

Bash
# /etc/postgresql/16/main/postgresql.conf
wal_level = replica
max_wal_senders = 10
wal_keep_size = 2GB
hot_standby = on

# /etc/postgresql/16/main/pg_hba.conf
host replication replicator 10.0.0.6/32 scram-sha-256
SQL
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_pwd_here';
SELECT pg_reload_conf();

2) على الـ replica: خد نسخة أساسية وابدأ

Bash
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/16/main/*
sudo -u postgres pg_basebackup \
  -h 10.0.0.5 -U replicator \
  -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R

# الـ flag -R بيكتب standby.signal و primary_conninfo تلقائيًا
sudo systemctl start postgresql

3) تأكد إن الـ replication شغّال

SQL
-- على الـ primary
SELECT client_addr, state, sync_state,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes
FROM pg_stat_replication;

المخرج المتوقع: سطر واحد بـ state = streaming و lag_bytes أقل من 4MB في الحالة الطبيعية.

توجيه القراءات في التطبيق

أبسط طريقة لو شغّال Node.js: استخدم pool منفصل للـ replica.

JavaScript
const { Pool } = require('pg');

const writePool = new Pool({
  host: '10.0.0.5', port: 5432,
  database: 'app', user: 'app',
  max: 20,
});

const readPool = new Pool({
  host: '10.0.0.6', port: 5432,
  database: 'app', user: 'app_readonly',
  max: 40,
});

async function getUser(id) {
  const { rows } = await readPool.query(
    'SELECT id, name, email FROM users WHERE id = $1',
    [id]
  );
  return rows[0];
}

async function updateUser(id, name) {
  await writePool.query(
    'UPDATE users SET name = $1 WHERE id = $2',
    [name, id]
  );
}

الطريقة الأنضف: استخدم pgpool-II 4.5 أو PgBouncer + HAProxy كـ middleware يتعرّف على نوع الاستعلام تلقائيًا، فالتطبيق يكلّم endpoint واحد بدون منطق إضافي. ده موصوف في pgpool-II Load Balancing docs.

رسم بياني لتوزيع حركة القراءة على عدة نسخ PostgreSQL يعرض هبوط زمن الاستجابة بعد إضافة Read Replicas

الأرقام الحقيقية: قبل وبعد

القياس على API FastAPI بـ 12,000 طلب/دقيقة (8,400 SELECT و 3,600 write)، DB بـ 38GB على Hetzner CCX23 (8 vCPU، 32GB RAM):

  • قبل Replica: P95 latency = 480ms، CPU primary = 92%، connections = 187/200.
  • بعد Replica واحد: P95 = 38ms، CPU primary = 41%، CPU replica = 58%.
  • تكلفة شهرية إضافية: $54 لسيرفر replica واحد، مقابل $312 كانت هتتدفع لـ vertical scaling لـ CCX33.
  • replication lag في الحالة الطبيعية: 12ms متوسط، 180ms في P99 وقت bulk imports.

الـ Trade-offs اللي محدش بيقولهالك

  1. Eventual Consistency: لو user عمل UPDATE ثم قرأ مباشرة بعد 50ms، ممكن يقرأ القيمة القديمة. الحل: وجّه الـ read-after-write لنفس الـ primary لمدة ثانية بعد أي كتابة.
  2. Long-running queries على الـ replica ممكن تأخّر تطبيق الـ WAL وتعمل lag كبير. hot_standby_feedback = on بيحلها لكن بيخلّي الـ primary يحتفظ بـ dead tuples أكتر.
  3. Failover مش مجاني: لو الـ primary سقط، promotion للـ replica محتاج أداة زي Patroni أو repmgr. بدونها ده شغل يدوي ممكن ياخد 8-15 دقيقة.
  4. الكتابات لسه bottleneck: Read Replicas مش بيحلوا مشكلة الكتابة. لو 80% من workload كتابة، انت محتاج Sharding أو Citus مش Replica.

متى لا تستخدم Read Replicas

  • الـ workload عندك أقل من 1,000 طلب/دقيقة — vertical scaling أرخص وأبسط.
  • التطبيق يعتمد على read-after-write strong consistency في كل صفحة (مثل لوحات تداول لحظية).
  • القاعدة أصغر من 2GB — كل الـ working set في الذاكرة، الـ bottleneck غالبًا في الـ application أصلاً.
  • فريق العمليات ما يقدرش يدير primary + replica + monitoring + failover — التشغيل الخاطئ أسوأ من instance واحد.

الخطوة التالية

افتح الـ postgresql.conf على الإنتاج، فعّل wal_level = replica و max_wal_senders = 10، وشغّل replica واحدة على نفس الـ subnet للتجربة. بعد 24 ساعة شوف pg_stat_replication.replay_lag — لو أقل من ثانية، أنت جاهز توجّه القراءات. ابعتلي الأرقام عندك قبل وبعد.

المصادر

  • PostgreSQL 16 Documentation – Streaming Replication
  • PostgreSQL 16 – pg_basebackup utility
  • PostgreSQL 16 – Hot Standby
  • pgpool-II 4.5 – Load Balancing
  • Patroni HA Template Documentation
  • 2ndQuadrant – Evaluating PostgreSQL Replication
  • AWS RDS – Best Practices for PostgreSQL Replication
]]>

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة