#1. Database Replication คืออะไร

Database Replication คือการคัดลอกและส่งต่อการเปลี่ยนแปลงข้อมูลจากฐานข้อมูลต้นทาง (Primary/Publisher) ไปยังฐานข้อมูลปลายทาง (Replica/Subscriber) อย่างต่อเนื่อง โดย Multi-Cloud Replication หมายถึงการทำงานข้ามผู้ให้บริการคลาวด์ เช่น AWS, Google Cloud และ Azure

สำคัญ: Read Replica ไม่ใช่ Backup และ asynchronous replication อาจมี replication lag หรือสูญเสียธุรกรรมล่าสุดเมื่อเกิด failover

#2. วัตถุประสงค์

  • Disaster Recovery: เตรียมฐานข้อมูลสำรองคนละคลาวด์
  • Read Scaling: กระจายงานอ่านไปยัง replica ที่อยู่ใกล้ผู้ใช้
  • Migration: ย้ายข้อมูลระหว่างคลาวด์โดยลด downtime
  • Cloud Resilience: ลดการพึ่งพาผู้ให้บริการรายเดียว (แต่ต้องออกแบบระบบสลับบริการให้ครบ)

#3. รูปแบบการทำ Replication

รูปแบบ การเขียนข้อมูล ข้อดี ข้อจำกัด
Single Primary + Read Replicas เขียนที่ Primary เท่านั้น เข้าใจง่าย ลด write conflict Replication lag, failover ต้องวางแผน
Logical Replication / CDC ส่งการเปลี่ยนแปลงระดับตารางหรือแถว ยืดหยุ่นสำหรับข้ามระบบ DDL, sequence, schema และสิทธิ์ต้องจัดการเพิ่ม
Physical Streaming Replication ส่ง WAL ระดับคลัสเตอร์ เหมาะกับ PostgreSQL เวอร์ชันและสภาพแวดล้อมที่เข้ากัน ข้อจำกัดของ managed service และเวอร์ชัน
Multi-Primary เขียนได้หลายแห่ง รองรับการเขียนหลายภูมิภาค Conflict resolution และ consistency ซับซ้อน

#4. ตัวอย่างสถาปัตยกรรม AWS → GCP → Azure

flowchart LR
  U[Clients] --> API[API / Read-Write Router]
  API -->|Writes| P[(AWS PostgreSQL Primary)]
  P -->|CDC / Logical Replication| G[(GCP PostgreSQL Replica)]
  P -->|CDC / Logical Replication| A[(Azure PostgreSQL Replica)]
  API -->|Reads: eventual consistency| G
  API -->|Reads: eventual consistency| A
  P --> B[Encrypted Backup / PITR]
  M[Monitoring: Lag, WAL, Network, Alerts] -.-> P
  M -.-> G
  M -.-> A

การส่งข้อมูลข้ามผู้ให้บริการต้องตรวจสอบความสามารถของแต่ละบริการ ไม่ควรสมมติว่าคำสั่งสร้าง read replica ภายในคลาวด์เดียวจะใช้ข้ามคลาวด์ได้ทันที

#5. Workshop: PostgreSQL Logical Replication ด้วย Docker Compose

Workshop นี้จำลองฐานข้อมูลสองคลาวด์ด้วยคอนเทนเนอร์สองตัวบนเครื่องเดียว ไม่ใช่การติดตั้งข้ามคลาวด์จริง เหมาะสำหรับพิสูจน์หลักการก่อนย้ายไป AWS/GCP/Azure

#5.1 สร้างไฟล์ compose.yaml

services:
  primary:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: demo_password
      POSTGRES_DB: shop
    command: ["postgres", "-c", "wal_level=logical", "-c", "max_replication_slots=10", "-c", "max_wal_senders=10"]
    ports: ["5433:5432"]
    volumes: ["primary_data:/var/lib/postgresql/data"]
  replica:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: demo_password
      POSTGRES_DB: shop
    ports: ["5434:5432"]
    volumes: ["replica_data:/var/lib/postgresql/data"]
volumes:
  primary_data:
  replica_data:

เริ่มระบบ:

docker compose up -d

#5.2 สร้างตารางที่ Primary

docker compose exec -T primary psql -U app -d shop <<'SQL'
CREATE TABLE products (
  id BIGINT PRIMARY KEY,
  name TEXT NOT NULL,
  price NUMERIC(10,2) NOT NULL
);
INSERT INTO products VALUES (1, 'Keyboard', 990.00);
CREATE PUBLICATION shop_pub FOR TABLE products;
SQL

#5.3 เตรียม Schema ที่ Replica

Logical replication ไม่สร้างตารางปลายทางให้อัตโนมัติ

docker compose exec -T replica psql -U app -d shop <<'SQL'
CREATE TABLE products (
  id BIGINT PRIMARY KEY,
  name TEXT NOT NULL,
  price NUMERIC(10,2) NOT NULL
);
SQL

#5.4 สร้าง Subscription

docker compose exec -T replica psql -U app -d shop <<'SQL'
CREATE SUBSCRIPTION shop_sub
CONNECTION 'host=primary port=5432 dbname=shop user=app password=demo_password'
PUBLICATION shop_pub;
SQL

บัญชี app เป็น superuser ในภาพจำลองของ official PostgreSQL image สำหรับการทดลองเท่านั้น ห้ามใช้สิทธิ์หรือรหัสผ่านตัวอย่างนี้ใน Production

#5.5 ทดสอบการเปลี่ยนแปลง

docker compose exec primary psql -U app -d shop -c "INSERT INTO products VALUES (2, 'Mouse', 450.00);"
docker compose exec replica psql -U app -d shop -c "SELECT * FROM products ORDER BY id;"

ตรวจสอบสถานะ:

docker compose exec primary psql -U app -d shop -c "SELECT * FROM pg_stat_replication;"
docker compose exec replica psql -U app -d shop -c "SELECT subname, pid, received_lsn, latest_end_lsn FROM pg_stat_subscription;"

หากแถวที่เพิ่มใหม่ยังไม่ปรากฏ ให้รอสักครู่และตรวจสอบ log:

docker compose logs replica

#6. ย้ายจาก Lab ไป Multi-Cloud จริง

  1. เลือก Primary เพียงแห่งเดียว และกำหนดชัดเจนว่าเขียนข้อมูลที่ใด
  2. ตรวจสอบเวอร์ชัน PostgreSQL, logical decoding, replication slot และสิทธิ์ที่ managed database อนุญาต
  3. เชื่อมเครือข่ายระหว่างคลาวด์ผ่าน VPN/private connectivity หรือ TLS พร้อม firewall ที่จำกัดต้นทาง
  4. สร้าง schema และจัดการ initial snapshot ก่อนเริ่ม CDC; ตรวจสอบว่าข้อมูลตรงกัน
  5. ตั้งค่าการส่งข้อมูลต่อเนื่องโดยใช้ native logical replication, pglogical หรือ managed migration/CDC ตามความสามารถจริง
  6. ตรวจสอบ replication lag, WAL retention, slot growth, disk, latency, connection และค่า network egress
  7. ออกแบบ failover พร้อม fencing ป้องกัน split-brain; ระบุ RPO/RTO และทดสอบการกู้คืน
  8. จัดทำ backup/PITR แยกจาก replica; ทดสอบ restore เป็นระยะ

#7. ข้อควรระวังสำคัญ

  • DDL: PostgreSQL logical replication ทั่วไปไม่ส่งคำสั่งเปลี่ยน schema อัตโนมัติ
  • Sequences: ค่า sequence ไม่ได้ซิงก์แบบเดียวกับแถวข้อมูล ต้องจัดการเมื่อ promote
  • Writes: Subscriber อาจเขียนได้ทางเทคนิค แต่ควรกำหนดให้แอปอ่านอย่างเดียวเพื่อลดความขัดแย้ง
  • Consistency: คำสั่งอ่านทันทีหลังเขียนควรกลับไป Primary หากต้องการ read-your-writes
  • Security: เก็บรหัสผ่านใน secret manager, ใช้ TLS, least privilege, network allowlist และ audit logs
  • Cost: คิดค่าทราฟฟิกออกข้ามคลาวด์ ค่าเครื่อง ฐานข้อมูล พื้นที่ WAL และ monitoring
  • Failover: การ promote replica ไม่ได้เปลี่ยน endpoint แอปพลิเคชันหรือป้องกัน split-brain โดยอัตโนมัติ

#8. แนวทางเลือกเทคโนโลยี

  • PostgreSQL → PostgreSQL: เริ่มประเมิน native logical replication และข้อจำกัดของบริการ managed database
  • AWS RDS → GCP Cloud SQL: ตรวจสอบแนวทาง external-server replication ของ Cloud SQL
  • Multi-engine หรือระบบที่ต้องแปลงข้อมูล: ประเมิน CDC เช่น Debezium + Kafka พร้อมการจัดการ schema และ delivery semantics
  • ต้องการ multi-writer: พิจารณาฐานข้อมูลที่ออกแบบเพื่อ distributed writes โดยตรง แทนการต่อ read replicas ให้เขียนพร้อมกัน

#9. เอกสารอ้างอิง