PostgreSQL Streaming Replication

ในระบบฐานข้อมูลที่ต้องรองรับการใช้งานระดับ Production การมีเซิร์ฟเวอร์เพียงตัวเดียวอาจไม่เพียงพอ เพราะหากเกิดปัญหาขึ้น ระบบทั้งหมดจะหยุดทำงานทันที PostgreSQL มีฟีเจอร์ Streaming Replication ที่ช่วยให้สามารถทำสำเนาข้อมูลจากเซิร์ฟเวอร์หลัก (Primary) ไปยังเซิร์ฟเวอร์สำรอง (Standby) แบบ Real-time ผ่าน WAL (Write-Ahead Log)

บทความนี้จะอธิบายหลักการทำงานของ Streaming Replication ใน PostgreSQL ตั้งแต่การตั้งค่า Primary และ Standby Server, การทำ Synchronous และ Asynchronous Replication, การ Promote Standby เป็น Primary, ไปจนถึงการ Monitor และแก้ไขปัญหาที่พบบ่อย เหมาะสำหรับผู้ดูแลระบบที่ต้องการสร้าง High Availability ให้กับฐานข้อมูล

Streaming Replication คืออะไร

Streaming Replication เป็นกลไกที่ PostgreSQL ใช้ส่ง WAL Records จาก Primary Server ไปยัง Standby Server แบบต่อเนื่อง โดย Standby จะรับ WAL Records และ replay ข้อมูลเหล่านั้นเพื่อให้สถานะของฐานข้อมูลตรงกับ Primary อยู่เสมอ วิธีนี้แตกต่างจาก Log Shipping แบบเดิมที่ต้องรอให้ WAL File เต็มก่อนจึงจะส่ง ทำให้ Streaming Replication มี Lag น้อยกว่ามาก

ข้อดีของ Streaming Replication

  • High Availability — หาก Primary ล่ม สามารถ Promote Standby ขึ้นมาทดแทนได้ทันที
  • Read Scaling — กระจายการอ่านข้อมูลไปยัง Standby (Hot Standby) เพื่อลดภาระ Primary
  • Disaster Recovery — มีสำเนาข้อมูลอยู่อีกเซิร์ฟเวอร์ ป้องกันข้อมูลสูญหาย
  • Low Latency — ส่ง WAL Records แบบ Stream ทำให้ข้อมูลใกล้เคียง Real-time
  • Built-in Feature — ไม่ต้องติดตั้ง Extension เพิ่ม รองรับมาตั้งแต่ PostgreSQL 9.0

ประเภทของการทำซ้ำข้อมูล

ประเภทคำอธิบายข้อดีข้อเสีย
AsynchronousPrimary ส่ง WAL โดยไม่รอยืนยันจาก Standbyไม่กระทบ Performance ของ Primaryอาจสูญเสียข้อมูลบางส่วนหาก Primary ล่ม
SynchronousPrimary รอให้ Standby ยืนยันว่าได้รับ WAL แล้วจึง Commitไม่สูญเสียข้อมูล (Zero Data Loss)เพิ่ม Latency ให้ Transaction บน Primary

สถาปัตยกรรมและองค์ประกอบ

การทำ Streaming Replication ประกอบด้วยองค์ประกอบหลัก ดังนี้

  • Primary Server — เซิร์ฟเวอร์หลักที่รับ Write Operations ทั้งหมด และส่ง WAL ไปยัง Standby
  • Standby Server — เซิร์ฟเวอร์สำรองที่รับ WAL จาก Primary และ replay เพื่อให้ข้อมูลตรงกัน
  • WAL Sender — Process บน Primary ที่ทำหน้าที่ส่ง WAL Records ไปยัง Standby
  • WAL Receiver — Process บน Standby ที่รับ WAL Records จาก Primary
  • Replication Slot — กลไกที่ช่วยให้ Primary เก็บ WAL ไว้จนกว่า Standby จะรับไปแล้ว ป้องกัน WAL ถูกลบก่อนเวลา

โฟลว์การทำงานคือ เมื่อมี Transaction เกิดขึ้นบน Primary ข้อมูลจะถูกเขียนลง WAL ก่อน จากนั้น WAL Sender จะส่ง Records เหล่านั้นไปยัง WAL Receiver บน Standby ซึ่งจะ replay ข้อมูลลงฐานข้อมูลของตนเอง

เตรียมความพร้อมก่อนตั้งค่า

ก่อนเริ่มตั้งค่า ให้เตรียมสิ่งต่อไปนี้

  • เซิร์ฟเวอร์ 2 เครื่องที่ติดตั้ง PostgreSQL เวอร์ชันเดียวกัน (แนะนำ 15 ขึ้นไป)
  • เครือข่ายที่เชื่อมต่อถึงกัน (Private Network จะปลอดภัยกว่า)
  • Primary Server IP: 10.0.0.1 และ Standby Server IP: 10.0.0.2 (ตัวอย่าง)
  • PostgreSQL User ที่มีสิทธิ์ REPLICATION
  • พื้นที่ดิสก์เพียงพอบน Standby สำหรับเก็บข้อมูลทั้งหมด

ตั้งค่า Primary Server

สร้าง Replication User

สร้าง User ที่มีสิทธิ์ REPLICATION บน Primary

sudo -u postgres psql

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'StrongPassword123!';

แก้ไข postgresql.conf

เปิดไฟล์ postgresql.conf บน Primary แล้วตั้งค่าดังนี้

# ตำแหน่งไฟล์: /etc/postgresql/16/main/postgresql.conf

# เปิดรับการเชื่อมต่อจากภายนอก
listen_addresses = '*'

# ตั้งค่า WAL สำหรับการส่งข้อมูลซ้ำ
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1GB

# เปิด Replication Slots
max_replication_slots = 5

# เปิด Hot Standby (สำหรับอ่านข้อมูลจาก Standby)
hot_standby = on

# Archive Mode (แนะนำเปิดเพื่อความปลอดภัย)
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'

คำอธิบายพารามิเตอร์ที่สำคัญ

  • wal_level = replica — กำหนดระดับ WAL ให้รองรับการส่งข้อมูลซ้ำ (ค่า default ตั้งแต่ PostgreSQL 10)
  • max_wal_senders = 5 — จำนวน WAL Sender Process สูงสุดที่ Primary รองรับ
  • wal_keep_size = 1GB — ขนาด WAL ขั้นต่ำที่ Primary เก็บไว้ ป้องกัน Standby ตามไม่ทัน
  • max_replication_slots = 5 — จำนวน Replication Slot สูงสุด

แก้ไข pg_hba.conf

เพิ่มกฎอนุญาตให้ Standby เชื่อมต่อเข้ามาได้

# ตำแหน่งไฟล์: /etc/postgresql/16/main/pg_hba.conf

# อนุญาต Replication จาก Standby
host    replication     replicator      10.0.0.2/32     scram-sha-256

# หรือถ้ามีหลาย Standby ในวง 10.0.0.0/24
host    replication     replicator      10.0.0.0/24     scram-sha-256

สร้าง Replication Slot

Replication Slot ช่วยให้ Primary เก็บ WAL ไว้จนกว่า Standby จะรับไป ป้องกัน WAL ถูก Recycle ก่อนเวลา

sudo -u postgres psql

-- สร้าง Physical Replication Slot
SELECT pg_create_physical_replication_slot('standby1_slot');

-- ตรวจสอบ Slot ที่สร้าง
SELECT slot_name, slot_type, active FROM pg_replication_slots;

สร้างโฟลเดอร์ WAL Archive

sudo mkdir -p /var/lib/postgresql/wal_archive
sudo chown postgres:postgres /var/lib/postgresql/wal_archive

รีสตาร์ท Primary

sudo systemctl restart postgresql

ตั้งค่า Standby Server

หยุด PostgreSQL บน Standby

sudo systemctl stop postgresql

ลบข้อมูลเก่าและทำ Base Backup

ใช้ pg_basebackup เพื่อคัดลอกข้อมูลทั้งหมดจาก Primary มายัง Standby

# ลบข้อมูลเก่าบน Standby (ระวัง! จะลบข้อมูลทั้งหมด)
sudo rm -rf /var/lib/postgresql/16/main/*

# ทำ Base Backup จาก Primary
sudo -u postgres pg_basebackup   -h 10.0.0.1   -U replicator   -D /var/lib/postgresql/16/main   -Fp -Xs -P -R   -S standby1_slot

ความหมายของ Flag ที่ใช้

  • -h 10.0.0.1 — IP ของ Primary Server
  • -U replicator — ใช้ User ที่สร้างไว้
  • -D /var/lib/postgresql/16/main — Data Directory ของ Standby
  • -Fp — Output Format แบบ Plain (ไม่บีบอัด)
  • -Xs — Stream WAL ระหว่างทำการคัดลอก
  • -P — แสดง Progress
  • -R — สร้างไฟล์ standby.signal และตั้งค่า primary_conninfo ให้อัตโนมัติ
  • -S standby1_slot — ใช้ Replication Slot ที่กำหนด

ตรวจสอบไฟล์ที่สร้างอัตโนมัติ

หลังจากรัน pg_basebackup ด้วย Flag -R จะได้ไฟล์เหล่านี้อัตโนมัติ

# ตรวจสอบไฟล์ standby.signal
ls -la /var/lib/postgresql/16/main/standby.signal

# ตรวจสอบ primary_conninfo ที่ถูกเพิ่มใน postgresql.auto.conf
cat /var/lib/postgresql/16/main/postgresql.auto.conf

ไฟล์ postgresql.auto.conf จะมีเนื้อหาประมาณนี้

primary_conninfo = 'user=replicator password=StrongPassword123! channel_binding=prefer host=10.0.0.1 port=5432 sslmode=prefer'
primary_slot_name = 'standby1_slot'

ปรับแต่ง Standby (ถ้าต้องการ)

หากต้องการตั้งค่าเพิ่มเติมบน Standby สามารถแก้ไข postgresql.conf ได้

# /etc/postgresql/16/main/postgresql.conf บน Standby

# เปิด Hot Standby — อนุญาตให้อ่านข้อมูลจาก Standby ได้
hot_standby = on

# ตั้งค่า Feedback เพื่อบอก Primary ว่า Standby replay ถึงไหนแล้ว
hot_standby_feedback = on

# กำหนด max_standby_streaming_delay (default 30s)
max_standby_streaming_delay = 30s

สตาร์ท Standby

sudo systemctl start postgresql

ตรวจสอบว่าการทำซ้ำข้อมูลทำงานปกติ

ตรวจสอบจาก Primary

-- ดู WAL Sender ที่กำลังทำงาน
SELECT pid, usename, client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn
FROM pg_stat_replication;

-- ตรวจสอบ Replication Slot
SELECT slot_name, active, restart_lsn, confirmed_flush_lsn
FROM pg_replication_slots;

ผลลัพธ์ที่ควรเห็น — state ควรเป็น streaming และ client_addr ตรงกับ IP ของ Standby

ตรวจสอบจาก Standby

-- ตรวจสอบว่า Standby อยู่ใน Recovery Mode
SELECT pg_is_in_recovery();
-- ผลลัพธ์ควรเป็น true

-- ดูเวลาที่ replay WAL ล่าสุด
SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_last_xact_replay_timestamp();

-- คำนวณ Replication Lag
SELECT now() - pg_last_xact_replay_timestamp() AS replication_lag;

ทดสอบการทำซ้ำข้อมูลจริง

สร้างข้อมูลบน Primary แล้วตรวจสอบว่าปรากฏบน Standby

-- บน Primary
CREATE TABLE test_repl (id serial, msg text, created_at timestamp default now());
INSERT INTO test_repl (msg) VALUES ('Hello from Primary');

-- บน Standby (ควรเห็นข้อมูลภายในไม่กี่วินาที)
SELECT * FROM test_repl;

Synchronous Replication

โดยค่าเริ่มต้น PostgreSQL ใช้ Asynchronous Replication ซึ่ง Primary จะไม่รอ Standby ยืนยัน ทำให้อาจสูญเสียข้อมูลบางส่วนหาก Primary ล่ม หากต้องการป้องกันข้อมูลสูญหาย (Zero Data Loss) ให้เปิด Synchronous Replication

ตั้งค่า Synchronous Replication บน Primary

# /etc/postgresql/16/main/postgresql.conf บน Primary

# กำหนดชื่อ Standby ที่ต้องรอยืนยัน
synchronous_standby_names = 'FIRST 1 (standby1)'

# ระดับการยืนยัน
synchronous_commit = on

ค่า synchronous_standby_names รองรับหลายรูปแบบ

  • FIRST N (name1, name2) — รอยืนยันจาก N ตัวแรกตามลำดับ
  • ANY N (name1, name2) — รอยืนยันจาก N ตัวใดก็ได้
  • ‘*’ — รอยืนยันจาก Standby ตัวใดก็ได้ที่เชื่อมต่ออยู่

ตั้งค่า application_name บน Standby

ชื่อ standby1 ที่ระบุใน synchronous_standby_names ต้องตรงกับ application_name ของ Standby

# แก้ไข primary_conninfo ใน postgresql.auto.conf บน Standby
primary_conninfo = 'user=replicator password=StrongPassword123! host=10.0.0.1 port=5432 application_name=standby1'

ระดับ synchronous_commit

ค่าความหมายความปลอดภัยPerformance
offไม่รอเขียน WAL ลงดิสก์ต่ำเร็วมาก
localรอเขียน WAL ลงดิสก์บน Primary เท่านั้นปานกลางเร็ว
remote_writeรอ Standby เขียนลง OS Cacheสูงปานกลาง
on (default)รอ Standby เขียน WAL ลงดิสก์สูงมากช้าลง
remote_applyรอ Standby replay WAL เสร็จสูงสุดช้าที่สุด

Cascading Replication

Cascading Replication ช่วยให้ Standby ตัวหนึ่งส่ง WAL ต่อไปยัง Standby ตัวอื่นได้ ลดภาระของ Primary ที่ไม่ต้องส่ง WAL ให้ Standby ทุกตัวโดยตรง เหมาะสำหรับระบบที่มี Standby จำนวนมาก หรือกระจายอยู่ในหลาย Data Center

# Topology:
# Primary (10.0.0.1) --> Standby1 (10.0.0.2) --> Standby2 (10.0.0.3)

# บน Standby1: เพิ่มใน postgresql.conf
max_wal_senders = 3

# บน Standby1: เพิ่มใน pg_hba.conf
host    replication     replicator      10.0.0.3/32     scram-sha-256

# บน Standby2: ตั้งค่า primary_conninfo ให้ชี้ไป Standby1 (ไม่ใช่ Primary)
primary_conninfo = 'user=replicator password=StrongPassword123! host=10.0.0.2 port=5432'

Promote Standby เป็น Primary (Failover)

เมื่อ Primary ล่มหรือต้องย้ายบทบาท สามารถ Promote Standby ให้เป็น Primary ตัวใหม่ได้ ซึ่งเป็นหัวใจสำคัญของกระบวนการ Failover

วิธี Promote แบบ Manual

# วิธีที่ 1: ใช้ pg_ctl
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main

# วิธีที่ 2: ใช้ SQL (PostgreSQL 12+)
SELECT pg_promote();

# ตรวจสอบว่า Promote สำเร็จ
SELECT pg_is_in_recovery();
-- ผลลัพธ์ควรเป็น false (ไม่ใช่ Standby แล้ว)

ขั้นตอนหลัง Promote

  1. ตรวจสอบว่า Standby เดิม Promote สำเร็จ (pg_is_in_recovery() = false)
  2. อัพเดต Application Connection String ให้ชี้ไปยัง Primary ตัวใหม่
  3. สร้าง Standby ตัวใหม่จาก Primary ใหม่ (ทำ pg_basebackup ใหม่)
  4. อัพเดต DNS หรือ Load Balancer ให้ชี้ไปยัง Primary ใหม่
  5. ตรวจสอบว่า Primary เก่า (ถ้ายังเปิดอยู่) ไม่รับ Write แล้ว

ใช้ Primary เก่าเป็น Standby (pg_rewind)

หาก Primary เก่ากลับมาออนไลน์ สามารถใช้ pg_rewind เพื่อแปลงเป็น Standby ของ Primary ใหม่ได้โดยไม่ต้องทำ pg_basebackup ใหม่ทั้งหมด

# หยุด Primary เก่าก่อน
sudo systemctl stop postgresql

# ใช้ pg_rewind เพื่อ sync กับ Primary ใหม่
sudo -u postgres pg_rewind   --target-pgdata=/var/lib/postgresql/16/main   --source-server='host=10.0.0.2 port=5432 user=replicator dbname=postgres'   --progress

# สร้างไฟล์ standby.signal
sudo -u postgres touch /var/lib/postgresql/16/main/standby.signal

# อัพเดต primary_conninfo ให้ชี้ไป Primary ใหม่ (10.0.0.2)
# แก้ไข postgresql.auto.conf
primary_conninfo = 'user=replicator password=StrongPassword123! host=10.0.0.2 port=5432'

# สตาร์ท
sudo systemctl start postgresql

ข้อกำหนดในการใช้ pg_rewind — ต้องเปิด wal_log_hints = on หรือ ใช้ data checksums บน Primary เดิม

Monitoring การทำซ้ำข้อมูล

ดู Replication Lag บน Primary

-- วิธีที่ 1: ดู Lag เป็น Byte
SELECT client_addr,
       state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication;

-- วิธีที่ 2: ดู Lag เป็นเวลา (PostgreSQL 10+)
SELECT client_addr,
       write_lag,
       flush_lag,
       replay_lag
FROM pg_stat_replication;

ดู Lag บน Standby

-- คำนวณความล่าช้าจากเวลา replay ล่าสุด
SELECT now() - pg_last_xact_replay_timestamp() AS lag;

-- ดูตำแหน่ง WAL ที่รับและ replay แล้ว
SELECT pg_last_wal_receive_lsn() AS received,
       pg_last_wal_replay_lsn() AS replayed;

Script ตรวจสอบอัตโนมัติ

#!/bin/bash
# check_repl_lag.sh — ตรวจสอบ Replication Lag และแจ้งเตือน

MAX_LAG_SECONDS=60
STANDBY_HOST="10.0.0.2"

LAG=$(psql -h "$STANDBY_HOST" -U postgres -t -c   "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int;")

LAG=$(echo "$LAG" | tr -d ' ')

if [ -z "$LAG" ] || [ "$LAG" = "" ]; then
    echo "CRITICAL: ไม่สามารถดึงค่า Lag ได้"
    exit 2
elif [ "$LAG" -gt "$MAX_LAG_SECONDS" ]; then
    echo "WARNING: Replication Lag = ${LAG}s (เกิน ${MAX_LAG_SECONDS}s)"
    exit 1
else
    echo "OK: Replication Lag = ${LAG}s"
    exit 0
fi

Replication Slots แบบละเอียด

Replication Slot เป็นกลไกสำคัญที่ช่วยให้ Primary จดจำตำแหน่ง WAL ที่ Standby แต่ละตัวต้องการ ป้องกันไม่ให้ WAL ถูกลบก่อนที่ Standby จะรับไป

จัดการ Replication Slots

-- สร้าง Physical Replication Slot
SELECT pg_create_physical_replication_slot('standby1_slot');

-- ดู Slot ทั้งหมด
SELECT slot_name, slot_type, active, restart_lsn,
       pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes
FROM pg_replication_slots;

-- ลบ Slot ที่ไม่ใช้แล้ว (สำคัญมาก! Slot ที่ไม่ active จะทำให้ WAL สะสม)
SELECT pg_drop_replication_slot('standby1_slot');

คำเตือน: Replication Slot ที่ไม่มี Standby เชื่อมต่อจะทำให้ WAL สะสมจนดิสก์เต็ม ต้องตรวจสอบและลบ Slot ที่ไม่ใช้งานอยู่เสมอ

Delayed Standby (Time-Delayed Replica)

Delayed Standby คือ Standby ที่ตั้งใจให้ replay WAL ช้ากว่า Primary ตามเวลาที่กำหนด เหมาะสำหรับกู้คืนข้อมูลจากข้อผิดพลาด เช่น ลบตารางผิด หรือ UPDATE ข้อมูลผิด

# postgresql.conf บน Delayed Standby
recovery_min_apply_delay = '1h'    # replay WAL ช้ากว่า Primary 1 ชั่วโมง

ตัวอย่างการใช้ — หาก DBA ลบตารางผิดบน Primary สามารถดึงข้อมูลจาก Delayed Standby ที่ยังมีตารางนั้นอยู่ (ภายในช่วงเวลา Delay) ได้ทันที

Multiple Standby Servers

ในระบบขนาดใหญ่ อาจต้องการ Standby หลายตัวเพื่อวัตถุประสงค์ที่ต่างกัน

# postgresql.conf บน Primary สำหรับ Multi-Standby
max_wal_senders = 10
max_replication_slots = 10

# Synchronous: รอ 1 ใน 2 Standby ยืนยัน
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
# pg_hba.conf บน Primary
host    replication     replicator      10.0.0.2/32     scram-sha-256
host    replication     replicator      10.0.0.3/32     scram-sha-256
host    replication     replicator      10.0.0.4/32     scram-sha-256

ตัวอย่าง Topology ที่แนะนำ

  • Standby1 (Sync) — อยู่ใน Data Center เดียวกับ Primary สำหรับ Failover แบบรวดเร็ว
  • Standby2 (Async) — อยู่ต่าง Data Center สำหรับ Disaster Recovery
  • Standby3 (Delayed 1h) — สำหรับกู้คืนข้อมูลจากข้อผิดพลาดของผู้ใช้

Connection Pooling กับ Read Replica

เมื่อมี Standby ที่เปิด Hot Standby ควรใช้ Connection Pooler เช่น PgBouncer เพื่อกระจาย Read Query ไปยัง Standby โดยอัตโนมัติ

# pgbouncer.ini — ตัวอย่างการตั้งค่า Read/Write Splitting
[databases]
# Write ไปที่ Primary
mydb = host=10.0.0.1 port=5432 dbname=mydb

# Read ไปที่ Standby
mydb_readonly = host=10.0.0.2 port=5432 dbname=mydb

[pgbouncer]
listen_port = 6432
listen_addr = *
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 200
default_pool_size = 25

Application สามารถเชื่อมต่อไปที่ mydb สำหรับ Write และ mydb_readonly สำหรับ Read เพื่อลดภาระบน Primary

Troubleshooting ปัญหาที่พบบ่อย

Standby ไม่เชื่อมต่อ Primary

  • ตรวจสอบ pg_hba.conf ว่าอนุญาต IP ของ Standby แล้ว
  • ตรวจสอบว่า listen_addresses เปิดรับการเชื่อมต่อจากภายนอก
  • ตรวจสอบ Firewall ว่าเปิด Port 5432
  • ดู Log ของ Primary: tail -f /var/log/postgresql/postgresql-16-main.log

Replication Lag สูง

  • ตรวจสอบ Network Bandwidth ระหว่าง Primary กับ Standby
  • ตรวจสอบ Disk I/O บน Standby — อาจ replay ไม่ทัน
  • เพิ่ม wal_keep_size หาก WAL ถูก Recycle ก่อนที่ Standby จะรับ
  • ใช้ Replication Slot เพื่อป้องกัน WAL ถูกลบ
  • ตรวจสอบ Long-running Query บน Standby ที่อาจบล็อก replay

WAL สะสมจนดิสก์เต็มบน Primary

  • ตรวจสอบ Replication Slot ที่ไม่มี Standby เชื่อมต่อ — ลบ Slot ที่ไม่ใช้
  • ตรวจสอบ wal_keep_size ว่าตั้งค่าสูงเกินไปหรือไม่
  • ตรวจสอบ archive_command ว่า Archive สำเร็จหรือไม่ (ถ้าเปิด Archive Mode)

Standby ถูก Terminate เมื่อมี Conflict

เมื่อ Query บน Standby ขัดแย้งกับ WAL replay (เช่น Primary ลบตาราง แต่ Standby กำลัง Query ตารางนั้น) PostgreSQL จะยกเลิก Query บน Standby

# เพิ่มเวลารอก่อนยกเลิก Query บน Standby
max_standby_streaming_delay = 300s    # รอ 5 นาที (default 30s)

# หรือตั้งค่าให้รอไม่จำกัดเวลา (ไม่แนะนำ — จะทำให้ Lag เพิ่ม)
max_standby_streaming_delay = -1

Error: requested WAL segment has already been removed

เกิดเมื่อ Standby ต้องการ WAL ที่ถูก Recycle ไปแล้ว แก้ไขได้ดังนี้

  • ใช้ Replication Slot (วิธีที่แนะนำ) เพื่อให้ Primary เก็บ WAL ไว้
  • เพิ่ม wal_keep_size เช่น wal_keep_size = 2GB
  • เปิด Archive Mode เพื่อให้ Standby ดึง WAL จาก Archive ได้
  • หาก WAL หายไปแล้ว ต้องทำ pg_basebackup ใหม่

Best Practices

  • ใช้ Replication Slot เสมอ — ป้องกัน WAL ถูกลบก่อนที่ Standby จะรับ แต่ต้องหมั่นตรวจสอบ Slot ที่ไม่ใช้งาน
  • ตรวจสอบ Lag อย่างสม่ำเสมอ — ตั้ง Alert เมื่อ Lag เกินค่าที่กำหนด
  • ใช้ Private Network — การส่ง WAL ระหว่าง Primary กับ Standby ควรผ่าน Private Network เพื่อความปลอดภัยและลด Latency
  • เปิด Archive Mode — เป็น Safety Net หาก Standby ต้องการ WAL ที่เก่ากว่า
  • ทดสอบ Failover เป็นประจำ — อย่ารอจนเกิดปัญหาจริงแล้วค่อย Promote ครั้งแรก
  • เก็บ Password ใน .pgpass — ไม่ควรเขียน Password ใน Config File โดยตรง
  • เวอร์ชัน PostgreSQL ต้องตรงกัน — Primary และ Standby ต้องใช้เวอร์ชัน Major เดียวกัน
  • วางแผน Multi-Standby — แยก Standby ตามวัตถุประสงค์ (HA, DR, Reporting, Delayed)

สรุป

PostgreSQL Streaming Replication เป็นฟีเจอร์ที่ทรงพลังสำหรับสร้าง High Availability และ Disaster Recovery ให้กับฐานข้อมูล โดยส่ง WAL Records จาก Primary ไปยัง Standby แบบ Real-time รองรับทั้ง Asynchronous (ประสิทธิภาพสูง) และ Synchronous (ปลอดภัยสูง) รวมถึง Cascading เพื่อลดภาระ Primary

สิ่งสำคัญคือการตรวจสอบ Replication Lag อย่างสม่ำเสมอ จัดการ Replication Slots ไม่ให้ WAL สะสม และทดสอบ Failover เป็นประจำ เพื่อให้มั่นใจว่าเมื่อเกิดปัญหาจริง ระบบสามารถสลับไปใช้ Standby ได้อย่างราบรื่น

แนะนำบริการ DE

การตั้งค่า Streaming Replication ต้องใช้เซิร์ฟเวอร์อย่างน้อย 2 เครื่องที่สามารถควบคุมได้เต็มที่ ตั้งแต่การแก้ไข postgresql.conf, pg_hba.conf ไปจนถึงการตั้งค่า Network ระหว่างเซิร์ฟเวอร์ Cloud VPS ของ DE เหมาะสำหรับงานนี้ เพราะให้ Root Access เต็มรูปแบบ สามารถเลือกขนาดเซิร์ฟเวอร์ตาม Workload และตั้งค่า Private Network ระหว่าง VPS ได้

สำหรับผู้ที่ต้องการโฮสต์เว็บแอปพลิเคชันที่เชื่อมต่อกับ PostgreSQL Replica Cloud Hosting ของ DE ก็เป็นตัวเลือกที่ดี รองรับการเชื่อมต่อฐานข้อมูลภายนอก และมีระบบจัดการที่ใช้งานง่าย ไม่ต้อง Manage Server เอง