Backup และ security
หน้าที่ด้าน operations สองอย่างสุดท้ายคือสิ่งที่คุณหวังว่าจะไม่ต้องใช้และไม่อาจมองข้ามได้ Backup ให้คุณสร้างใหม่ได้หลังจากดิสก์ล้มเหลว การ deploy ที่ผิดพลาด หรือ DELETE ที่พลาดไป Security ควบคุมว่าใครอาจเชื่อมต่อได้ ใครอาจเห็นอะไร และข้อมูลเดินทางผ่านเครือข่ายอย่างไร ฐานข้อมูลที่เร็วและพร้อมใช้งานสูงก็ยังเป็นภาระอยู่ดี ถ้า restore กลับมาไม่ได้ หรือใครบนอินเทอร์เน็ตก็อ่านได้
บทเรียนนี้ครอบคลุม backup ทั้งสองตระกูลที่ PostgreSQL มีให้ จากนั้นเดินลงไปทีละชั้นของการควบคุมการเข้าถึงจากขอบเครือข่ายไปจนถึง row แต่ละ row
backup สองชนิด
หัวข้อที่มีชื่อว่า “backup สองชนิด”Backup ของ PostgreSQL มีสองสไตล์ที่เหมาะกับความต้องการที่ต่างกัน
| ชนิด | เครื่องมือ | เก็บอะไรไว้บ้าง | เหมาะที่สุดสำหรับ |
|---|---|---|---|
| Logical | pg_dump / pg_restore | SQL หรือ archive ของฐานข้อมูลหนึ่ง | ฐานข้อมูลเดี่ยว, การย้ายเวอร์ชัน |
| Physical | base backup + WAL archiving | ไฟล์ทั้ง cluster แบบ byte-for-byte | cluster ขนาดใหญ่, point-in-time recovery |
logical backup
หัวข้อที่มีชื่อว่า “logical backup”Logical backup รัน pg_dump ซึ่งอ่านฐานข้อมูลและเขียน statement ที่จำเป็นสำหรับสร้างฐานข้อมูลนั้นขึ้นมาใหม่ ไฟล์ที่ได้พกพาข้ามเครื่องและข้าม major version ได้ จึงเหมาะอย่างยิ่งกับการย้ายหรือ clone ฐานข้อมูลเดี่ยว
# Dump one database to a compressed custom-format archivepg_dump --format=custom --file=shop.dump --dbname=shop
# Restore that archive into a fresh databasepg_restore --dbname=shop_restored --create shop.dumpรูปแบบ custom ที่ใช้ในที่นี้ให้ pg_restore restore บางส่วนแบบเลือกได้และรันแบบขนานได้ สำหรับฐานข้อมูลขนาดเล็ก ไฟล์ SQL ธรรมดาที่คุณ replay ด้วย psql ก็ใช้ได้เช่นกัน
physical backup และ point-in-time recovery
หัวข้อที่มีชื่อว่า “physical backup และ point-in-time recovery”สำหรับ cluster ขนาดใหญ่หรือยุ่ง การ dump แบบ logical ช้าเกินไป แทนที่จะทำเช่นนั้น คุณทำ base backup — สำเนาระดับ byte ของไฟล์ข้อมูล — และ archive write-ahead log อย่างต่อเนื่อง การ replay WAL ทับ base backup ให้คุณ restore กลับไปยังจังหวะเวลาใด ๆ ก็ได้ ซึ่งรู้จักกันในชื่อ point-in-time recovery (PITR)
# Take a base backup of the whole clusterpg_basebackup --pgdata=/backups/base --format=tar --gzip --progress# postgresql.conf: keep every WAL segment by archiving itarchive_mode = onarchive_command = 'test ! -f /archive/%f && cp %p /archive/%f'ด้วย base backup บวกกับ WAL ที่ archive ไว้ การ recovery หมายถึงการ restore ไฟล์ base แล้วบอก PostgreSQL ให้ replay WAL ไปจนถึง timestamp ที่เลือก — คุณจึงสามารถย้อนกลับไปยังวินาทีก่อนที่ migration ที่ผิดพลาดจะรันได้
flowchart LR PG[(Primary cluster)] -->|pg_basebackup| Base[Base backup] PG -->|archive_command| WAL[Archived WAL segments] Base --> Restore[Restore] WAL -->|replay to a chosen time| Restore Restore --> Recovered[(Recovered cluster)]
security เป็นชั้น ๆ
หัวข้อที่มีชื่อว่า “security เป็นชั้น ๆ”การควบคุมการเข้าถึงใน PostgreSQL มองภาพได้ดีที่สุดเป็นชุดของประตูที่ request ผ่านไป: ก่อนอื่นคือเครือข่าย จากนั้น authentication แล้วก็ role privilege และสุดท้ายคือกฎระดับ row แต่ละชั้นสามารถหยุด request ที่ชั้นก่อนหน้าปล่อยผ่านมาได้
flowchart LR Client[Client] -->|encrypted with TLS| HBA[pg_hba.conf - who may connect] HBA --> Auth[Authenticate the role] Auth --> Priv[Role privileges - GRANT and REVOKE] Priv --> RLS[Row-level security policy] RLS --> Data[(Table rows)]
ประตูเครือข่าย: pg_hba.conf และ TLS
หัวข้อที่มีชื่อว่า “ประตูเครือข่าย: pg_hba.conf และ TLS”ประตูแรกคือ pg_hba.conf (host-based authentication) แต่ละบรรทัดบอกว่า role ใดอาจเชื่อมต่อกับฐานข้อมูลใดจาก address ใด และต้อง authenticate อย่างไร กฎถูกอ่านจากบนลงล่าง และการ match แรกชนะ
# TYPE DATABASE USER ADDRESS METHODhostssl all app 10.0.0.0/24 scram-sha-256host all all 127.0.0.1/32 scram-sha-256คีย์เวิร์ด hostssl กำหนดให้ connection ต้องเข้ารหัสด้วย TLS ซึ่งคุณเปิดใช้ใน postgresql.conf ด้วยการชี้ไปที่ certificate และ key
ssl = onssl_cert_file = '/etc/postgresql/server.crt'ssl_key_file = '/etc/postgresql/server.key'role และ privilege: GRANT และ REVOKE
หัวข้อที่มีชื่อว่า “role และ privilege: GRANT และ REVOKE”เมื่อเชื่อมต่อแล้ว สิ่งที่ role ทำได้จะกำกับด้วย privilege คุณสร้าง role แล้ว GRANT สิทธิ์ที่ต้องการ หรือ REVOKE คืนก็ได้ หลักการชี้นำคือ least privilege คือให้แต่ละ role เท่าที่จำเป็นต้องใช้จริงเท่านั้น
-- A read-only reporting roleCREATE ROLE reporting LOGIN PASSWORD 'set-a-strong-one';GRANT CONNECT ON DATABASE shop TO reporting;GRANT USAGE ON SCHEMA public TO reporting;GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporting;
-- An application role that may also write to one tableCREATE ROLE app LOGIN PASSWORD 'set-a-strong-one';GRANT SELECT, INSERT, UPDATE ON orders TO app;REVOKE DELETE ON orders FROM app;row-level security
หัวข้อที่มีชื่อว่า “row-level security”Privilege ควบคุมทั้ง table Row-level security (RLS) ลงลึกกว่านั้น โดยให้ policy ตัดสินว่า role อาจเห็นหรือเปลี่ยน row ใด — เป็นรากฐานของระบบ multi-tenant ที่แต่ละ tenant ต้องเห็นเฉพาะข้อมูลของตัวเองเท่านั้น
-- Turn on RLS and add a policy keyed to a session settingALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id')::bigint);ด้วย policy นี้ query บน orders จะคืนค่าเฉพาะ row ที่ tenant_id ตรงกับค่าที่แอปพลิเคชันตั้งไว้สำหรับ session ปัจจุบันอย่างเงียบ ๆ WHERE ที่ลืมไปหนึ่งครั้งจะไม่ทำให้ข้อมูลของ tenant อื่นรั่วไหลอีกต่อไป
เคล็ดลับและข้อควรระวัง
หัวข้อที่มีชื่อว่า “เคล็ดลับและข้อควรระวัง”- Backup จะเป็นของจริงก็ต่อเมื่อคุณ restore กลับมาได้สำเร็จแล้วเท่านั้น จัด table ทดสอบ restore เป็นประจำลงในฐานข้อมูลแบบใช้แล้วทิ้ง และยืนยันว่าข้อมูลยังครบถ้วน
- Logical dump พกพาได้และเยี่ยมสำหรับฐานข้อมูลเดี่ยว; physical base backup บวกกับ WAL archiving คือสิ่งที่คุณต้องการสำหรับ cluster ขนาดใหญ่และ point-in-time recovery
- ใช้ least privilege ในทุกที่ application role ไม่ควรเป็นเจ้าของ schema หรือสามารถ drop table ได้ และ reporting ควรเป็นแบบอ่านอย่างเดียว
- อย่าใช้ authentication แบบ
trustบน address ใดก็ตามที่เข้าถึงได้จากภายนอกเครื่อง — เพราะเปิดให้ใครก็ได้เชื่อมต่อในฐานะ role ใดก็ได้โดยไม่ต้องใช้ password - กำหนดให้ใช้ TLS สำหรับ connection ที่ข้ามเครือข่ายด้วย
hostsslและจำไว้ว่ากฎpg_hba.confถูก match จากบนลงล่าง การ match แรกชนะ
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Automated backup ที่ทดสอบ restore เป็นประจำ | กู้คืนได้จริงเมื่อเกิดภัยพิบัติจริง | เสียพื้นที่ storage และต้องมีวินัยด้าน operations |
| พึ่งพา replication อย่างเดียวเพื่อความทนทานของข้อมูล | failover เร็ว พร้อมใช้งานสูง | replica ไม่ใช่ backup เพราะคัดลอกทั้งความผิดพลาดและการลบข้อมูลตามไปด้วย |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ตั้งค่า backup ครั้งเดียวแล้วไม่เคยทดสอบ restore — ไม่มีใครรู้ว่า backup พังจนกว่าจะต้องใช้จริง จัดตาราง restore drill เป็นประจำ
- ถือว่า replica เป็น backup — replica เป็นสำเนาที่ตามทัน primary แบบเรียลไทม์ ไม่ใช่สำเนาที่ point-in-time recoverable แยกต่างหาก ต้องมี backup จริงควบคู่ไปด้วยเสมอ
- ให้ role ของแอปพลิเคชันมีสิทธิ์กว้างเกินจำเป็น (เช่นใช้ superuser role กับแอป) — ยึดหลัก least privilege ให้แต่ละ role ได้เฉพาะสิทธิ์ที่ต้องใช้จริงเท่านั้น
💡 ตัวอย่างจากของจริง
Instagram — ในช่วง scale ขึ้นไปรองรับผู้ใช้หลายร้อยล้านคน มีการซ้อม sharding และ backup อย่างสม่ำเสมอเป็นส่วนหนึ่งของ infrastructure practice
มาตรฐานทั่วไปในทีม PostgreSQL ระดับโปรดักชัน — การทดสอบ restore แบบอัตโนมัติเป็นประจำถือเป็น practice มาตรฐาน ไม่ใช่แค่การสร้าง backup อย่างเดียว