13 คะแนน โดย GN⁺ 12 일 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • สรุปสาเหตุและแนวทางแก้ปัญหาของ การสะสม dead tuple ซึ่งเป็นปัญหาเรื้อรังเมื่อรัน job queue บน Postgres รวมถึง table bloat และประสิทธิภาพที่ลดลงตามมา
  • ตารางคิวมักมีแถวส่วนใหญ่หมุนเวียนแบบ insert-read-delete ในช่วงเวลาสั้น ๆ จึงมีขนาดค่อนข้างคงที่ แต่มี ปริมาณงานสะสมสูงมาก
  • ด้วยโครงสร้าง MVCC ของ Postgres แถวที่ถูกลบจะไม่หายไปทันที แต่จะคงอยู่เป็น dead tuple และต้องถูกเก็บกวาด โดย autovacuum เป็นผู้ทำหน้าที่นี้
  • หากมีทรานแซกชันที่รันนานหรือ query วิเคราะห์ที่รันทับซ้อนกันจน MVCC horizon ถูกตรึงไว้ autovacuum จะไม่สามารถเก็บกวาด dead tuple ได้ ทำให้ประสิทธิภาพของคิวลดลง
  • ฟีเจอร์ Traffic Control ของ PlanetScale (ส่วนขยายของ Insights) ถูกเสนอเป็นวิธีแก้เชิงปฏิบัติด้วยการ จำกัดทรัพยากรตามคลาสของ query

ลักษณะของงานแบบคิว

  • จุดเด่นของตารางคิวคือแถวส่วนใหญ่มีอายุ ชั่วคราว (transient) — ถูก insert, ถูกอ่านหนึ่งครั้ง แล้วถูกลบ
  • ขนาดตารางแทบคงที่ แต่ throughput สะสมมหาศาล
  • ข้อดีหลักของการวาง job queue ไว้ใน Postgres คือสามารถ ซิงก์สถานะของ job กับตรรกะ DB อื่น ๆ ภายในทรานแซกชันเดียวกัน ได้
    • หาก job ล้มเหลว ทรานแซกชันทั้งหมดจะ rollback
    • หากใช้บริการคิวภายนอก การซิงก์กับสถานะทรานแซกชันของแอปพลิเคชันจะซับซ้อนขึ้น

ตัวอย่างตารางคิวและการทำงานของ worker

  • สคีมาพื้นฐานที่ยกมาในบทความ
CREATE TABLE jobs (  
  id BIGSERIAL PRIMARY KEY,  
  run_at TIMESTAMPTZ DEFAULT now(),  
  status TEXT DEFAULT 'pending',  
  payload JSONB  
);  
CREATE INDEX idx_jobs_fetch ON jobs (run_at) WHERE status = 'pending';  
  • worker จะเปิดทรานแซกชันแล้วล็อก pending job ที่เก่าที่สุด ด้วย FOR UPDATE SKIP LOCKED เพื่อป้องกันการประมวลผลซ้ำ
  • ถ้างานสำเร็จจะ DELETE แล้ว COMMIT ถ้าล้มเหลวจะ rollback ทำให้แถวนั้นกลับไปมองเห็นได้สำหรับ worker ตัวอื่น
  • ควรรักษาทรานแซกชันนี้ให้ สั้นที่สุดเท่าที่ทำได้ — ยิ่งเปิดค้างนานยิ่งขัดขวาง vacuum (ตัวอย่างในบทความอิง worker ระดับต่ำกว่า 1 มิลลิวินาที)

ปัญหาไม่ได้อยู่ที่ประสิทธิภาพล้วน ๆ

  • มีการบันทึกไว้แล้วว่า Postgres สามารถรองรับ job queue ขนาดใหญ่ ได้ ดังนั้นความสามารถของระบบไม่ใช่ประเด็น
  • ปัญหาที่แท้จริงคือ การอยู่ร่วมกับงานประเภทอื่นที่แย่งทรัพยากรบน DB เดียวกัน
  • สุขภาพของตารางคิวไม่ได้ขึ้นกับการตั้งค่าของตัวมันเองเท่านั้น แต่ขึ้นกับ พฤติกรรมของทุกทรานแซกชันที่รันอยู่บน Postgres instance เดียวกัน
  • บทความนี้โฟกัสที่ query traffic ที่แข่งขันกันบน primary (ผลกระทบจาก replica และ replication slot เป็นอีกประเด็นหนึ่ง)

ปัญหาจริง: การเก็บกวาด dead tuple

  • Postgres ใช้ MVCC เพื่อเก็บหลายเวอร์ชันของแถวเดียวกัน — แถวที่ถูกลบจะไม่ถูกเอาออกทันที แต่จะถูก ทำเครื่องหมายว่าลบแล้ว และยังคงอยู่ในสถานะมองไม่เห็นสำหรับทรานแซกชันใหม่
  • แถวที่คงอยู่นี้คือ dead tuple และจะถูกเก็บกวาดด้วย การทำงานของ vacuum
  • แม้ dead tuple จะไม่ปรากฏในผล SELECT แต่ก็ยัง สร้างต้นทุน
    • Sequential scan: ตัว executor ต้องอ่าน dead tuple จาก heap page ตรวจสอบ visibility แล้วค่อยทิ้ง
    • Index scan (แบบที่ใช้ในคิวด้วย ORDER BY run_at LIMIT 1): ดัชนี B-tree จะสะสมการอ้างอิงไปยัง dead tuple ทำให้ต้องไล่อ่านรายการที่ชี้ไปยังแถวที่มองไม่เห็นแล้วด้วย
  • dead index entry แต่ละรายการทำให้เกิด I/O เพิ่มเติม แม้แอปจะมองไม่เห็น แต่ต้นทุนจะเพิ่มขึ้นมากตามจำนวน dead tuple
  • รอบการเก็บกวาดถูกกำหนดโดย autovacuum_naptime (ค่าเริ่มต้น 1 นาที) และการตัดสินใจว่าจะรันหรือไม่ขึ้นกับ autovacuum_vacuum_threshold กับ autovacuum_vacuum_scale_factor

กลไกภายในของ dead tuple

  • มี metadata ของแถว 3 อย่างที่สำคัญ
    • ctid: ตำแหน่งทางกายภาพของ tuple ใน heap (page, offset)
    • xmin: transaction ID (XID) ที่ insert แถวนั้น
    • xmax: transaction ID ที่ลบ/ล็อกแถวนั้น ถ้าเป็น 0 แปลว่ายังไม่มีการทำเครื่องหมายลบ
  • แม้จะดึง pending มาเพียง 3 รายการ ก็อาจเกิดกรณีที่ executor ต้องสแกน dead tuple ที่ถูกลบไปก่อนหน้าแล้วถึง 6 รายการก่อน แล้วจึง คืนผลเพียง 3 รายการ
  • ฝั่งดัชนีก็เช่นกัน หาก leaf entry ชี้ไปยัง heap tuple ที่กลายเป็น dead แล้ว ก็จะเกิด งานสูญเปล่าระหว่างการสแกน สะสมขึ้น
  • ถ้า DB เก็บกวาด dead tuple ได้ช้ากว่าอัตราที่มันถูกสร้าง ระบบจะเข้าสู่เส้นทางล้มเหลว
  • Postgres cluster ที่จูนมาดีสามารถรองรับ throughput คิวได้ระดับหลายหมื่นรายการต่อวินาที

สถานการณ์ที่ autovacuum ใช้งานไม่ได้ผล

  • สาเหตุหลักที่ทำให้ autovacuum เก็บกวาด dead tuple ไม่สำเร็จ
    • มี table lock บางตัวขัดขวาง cleanup
    • การตั้งค่า autovacuum ไม่เหมาะสม
    • และที่พบบ่อยที่สุดคือ มี active transaction ขัดขวางการ reclaim dead tuple
  • Postgres จะไม่ vacuum dead tuple ที่ ยังอาจมองเห็นได้สำหรับ active transaction
    • active transaction ที่เก่าที่สุดจะเป็นตัวกำหนด cutoff → MVCC horizon
    • จนกว่าทรานแซกชันนั้นจะจบ dead tuple ทั้งหมดหลัง snapshot นั้นจะยังต้องถูกเก็บไว้
  • เพียงมีทรานแซกชันเดียวที่กินเวลา 2 นาที ก็สามารถ ตรึง horizon ไว้ 2 นาที
  • รูปแบบความล้มเหลวเดียวกันนี้เกิดได้จาก query ระยะกลางหลายตัวที่รันทับซ้อนกัน
    • ตัวอย่าง: query วิเคราะห์ 3 ตัวที่แต่ละตัวใช้เวลา 40 วินาที แต่เริ่มสลับกันทุก 20 วินาที แต่ละตัวอาจไม่ timeout เลย ทว่ามักจะมีอย่างน้อย 1 ตัว active อยู่เสมอ ทำให้ horizon เดินหน้าไม่ได้
  • เมื่อยึดแนวคิด “Just use Postgres” แล้วเอาหลาย workload ไปรวมไว้ใน DB เดียว ปัญหาจึงไม่ใช่ความเร็วของการประมวลผล job แต่เป็น query ช้าที่รันทับกันจนการเก็บกวาด dead tuple ถูกดันออกไป

เครื่องมือเดิมและข้อจำกัด

  • ตัวเลือกสำหรับจูน autovacuum: autovacuum_vacuum_cost_delay, autovacuum_vacuum_cost_limit
  • timeout สำหรับจำกัด query ที่รันนาน
    • statement_timeout (Postgres 7.3): ยุติ SQL statement รายตัวที่เกินเวลาที่กำหนด
    • idle_in_transaction_session_timeout (9.6): ยุติเซสชันที่ idle ค้างอยู่ในทรานแซกชัน
    • transaction_timeout (17.0): ยุติทรานแซกชันทั้งที่ active หรือ inactive หากเกินเวลาที่กำหนด
  • แต่ timeout เหล่านี้ มุ่งเป้าแค่เวลารันของ query เดี่ยว ไม่สามารถจำกัด concurrency หรือค่าใช้จ่ายในการรันได้ จึงไม่เหมาะกับการสกัด workload ที่ ตรึง MVCC horizon อย่างต่อเนื่อง
  • สิ่งที่ต้องการจริง ๆ คือ การแยกตาม traffic class เพื่อคง workload ที่มีความสำคัญสูงไว้เหมือนเดิม และควบคุมเฉพาะอัตราการใช้ทรัพยากรของ workload ความสำคัญต่ำ

Database Traffic Control™

  • เป็นฟีเจอร์เฉพาะของ PlanetScale Postgres ซึ่งเป็นส่วนหนึ่งของ Insights extension ที่ PlanetScale พัฒนา
  • ใช้เมื่อจำเป็นต้องควบคุมประสิทธิภาพและการใช้ทรัพยากรของแต่ละ query อย่างละเอียด
  • ด้วย Resource Budget สามารถกำหนดเพดานทรัพยากรให้ query เป้าหมาย และบล็อกได้หากใช้เกิน
  • กลยุทธ์ในการแก้ปัญหาคือ จำกัดจำนวนและความถี่ของ query ช้าที่รันทับซ้อนกัน เพื่อเปิดช่องให้ autovacuum เก็บกวาด dead tuple ได้ในอัตราที่เหมาะสม
  • query ที่ถูกบล็อกจะไม่ถูกปฏิเสธถาวร แต่จะต้อง retry ดังนั้นแอปจึงต้องมีตรรกะ retry
  • เป็นแนวทางที่รักษาปริมาณงานรวมไว้ แต่ ทำให้ความเร็วในการประมวลผลเรียบขึ้น

การตั้งค่าเดโมและที่มา

  • ไอเดียของบทความนี้มาจากบล็อกปี 2015 ของ Brandur Leach ชื่อ "Postgres Job Queues & Failure By MVCC"
    • บันทึก failure mode ร้ายแรงของ job queue บน Postgres
    • มี test bench ที่พิสูจน์เชิงประจักษ์ถึงปรากฏการณ์ที่ทรานแซกชันที่ไม่ถูกปิดไปตรึง MVCC horizon และขัดขวาง cleanup
  • test bench ต้นฉบับเปิดเผยไว้ที่ brandur/que-degradation-test

การจำลองปัญหา (บน Postgres 18)

  • การทดสอบต้นฉบับอิง Ruby + Que gem v0.x + Postgres 9.4
  • ผู้เขียนเขียนใหม่เป็น TypeScript + Bun เพื่อแยกตรวจสอบพฤติกรรมในระดับ SQL โดยตรง
  • คง รูปแบบ recursive CTE แบบเดียวกับ Que รวมถึง schema, producer rate, work duration, จำนวน worker และรูปแบบ long-runner เดิมไว้
  • รันบน PlanetScale PS-5 cluster (เริ่มต้นที่ $5 ต่อเดือน)
  • ผลลัพธ์: ประสิทธิภาพลดลงอย่างสังเกตได้ แต่ยังอยู่ในระดับจัดการได้
    • การทดสอบต้นฉบับทำให้ DB เข้าสู่ death spiral ภายใน 15 นาที แต่บน PS-5 สามารถคง worker queue ใกล้ 0 ได้ตลอด 15 นาที
    • อย่างไรก็ตาม dead tuple เพิ่มขึ้นแบบเส้นตรง บ่งชี้ว่าหากปล่อยนานกว่านี้ ปัญหาเดิมก็จะกลับมา
    • ด้วยการปรับปรุงการเก็บกวาดดัชนี B-tree (เช่น bottom-up deletion สำหรับ version churn และการลบ dead index tuple ระหว่าง scan) ปัญหาจึง บรรเทาลง แต่ไม่ได้หายไป

ความพยายามปรับปรุง: SKIP LOCKED + การประมวลผลแบบ batch

  • มีการปรับปรุงสมัยใหม่ 2 อย่างที่ไม่มีในปี 2015
    1. FOR UPDATE SKIP LOCKED — แทนที่ recursive CTE ทั้งหมดด้วย SELECT ตัวเดียว และข้ามแถวที่ worker อื่นล็อกไว้
    2. Batch processing (10 jobs ต่อทรานแซกชัน) — ใช้การ acquire lock ครั้งเดียวเพื่อประมวลผล 10 รายการ ช่วย เฉลี่ย ต้นทุนการสแกนดัชนี
  • เงื่อนไขยังเหมือนเดิม: worker 8 ตัว, producer 50 jobs/sec, งานใช้เวลา 10ms, long-runner เริ่มหลัง 45 วินาที
  • ผลลัพธ์สำคัญ
ตัวชี้วัด original (recursive CTE) enhanced (SKIP LOCKED + batch)
Baseline lock time 2–3ms 1.3–3.0ms
End lock time (typical) 10–34ms 9–29ms
Worst spike 84.5ms (dead tuple 33k) 180ms (dead tuple 24k)
Queue depth 0–100 (oscillating) 0 (เกือบทั้งหมด)
Dead tuples at end 42,400 42,450
Throughput ~89/s ~50/s
  • เส้นโค้งการเสื่อมสภาพแทบเหมือนกัน — เพราะทั้งสองวิธีต่างก็สแกนดัชนี B-tree เดียวกันและเจอ dead tuple แบบเดียวกัน
  • ความต่างของ throughput ไม่ได้มาจากกลยุทธ์การล็อก แต่เกิดจาก การออกแบบการทดสอบ (worker แบบ CTE ดึง job ได้เร็วกว่าผู้ผลิต ส่วน worker แบบ batch จะเคลียร์คิวแล้ว backoff sleep)
  • สรุปคือ ดีไซน์คิวที่เมื่อ 10 ปีก่อนทำให้ DB พังใน 15 นาที ทุกวันนี้ทนได้นานขึ้น แต่ ปัญหาพื้นฐานยังคงอยู่ — หากเพิ่มเป็น 500 jobs/sec ปัญหาจะยิ่งเกิดซ้ำเร็วขึ้น

แก้ด้วย Traffic Control

  • เครื่องมือควบคุมที่ Resource Budget มีให้
    • Server share & burst limit: สัดส่วนและอัตราการใช้ทรัพยากรของเซิร์ฟเวอร์
    • Per-query limit: เวลาที่ query สามารถรันได้ วัดเป็นวินาทีตามการใช้ทรัพยากรของเซิร์ฟเวอร์
    • Maximum concurrent workers: สัดส่วนเมื่อเทียบกับ worker process ที่มีอยู่
  • การระบุ query เป้าหมายทำผ่าน metadata ใน แท็ก SQLCommenter เป็นหลัก (เช่น action=analytics)
  • แทนที่จะใช้ long-runner ที่โดนจับได้ด้วย idle_in_transaction_session_timeout ผู้เขียนเลือกสร้างการเสื่อมสภาพด้วย query วิเคราะห์ที่ active และรันทับซ้อนกัน ซึ่งเป็นสถานการณ์ที่สมจริงกว่า (และ session timeout จับไม่ได้)
  • จำกัด Maximum concurrent workers ของ query action=analytics ไว้ที่ 1 worker (max_worker_processes 25%) → ให้รัน query วิเคราะห์พร้อมกันได้เพียง 1 ตัว
  • เพื่อให้เกิด death spiral ภายในกรอบเวลา 15 นาที จึงเพิ่ม producer เป็น 800 jobs/sec
  • รัน workload แบบ "enhanced" 2 รอบจาก EC2 ไปยัง PlanetScale DB เดียวกัน
    • 800 jobs/sec
    • query วิเคราะห์ 3 ตัวที่แต่ละตัวใช้เวลา 120 วินาที รันพร้อมกันแบบเหลื่อมเวลาเพื่อให้ทับซ้อนกันตลอด
    • รันต่อเนื่อง 15 นาที
  • เปรียบเทียบผลลัพธ์
ตัวชี้วัด ปิด Traffic Control เปิด Traffic Control
Queue backlog 155,000 jobs 0 jobs
Lock time 300ms+ 2ms
Dead tuples at end 383,000 0–23,000 (วนรอบ)
Analytics queries 3 concurrent, overlapping ทีละ 1 ตัว, อีก 2 ตัวกำลัง retry
VACUUM effectiveness ถูกขัดขวาง (horizon ถูกตรึง) ปกติ (มีช่วงว่างระหว่าง query ให้เก็บกวาด)
Outcome Death spiral เสถียรอย่างสมบูรณ์
  • Traffic Control จำกัด concurrency ของ workload เฉพาะได้โดยตรง ซึ่งเป็นการควบคุมที่การจูน autovacuum หรือการตั้ง timeout ทำไม่ได้
  • รายงานเชิงวิเคราะห์ยังคงรันต่อไปภายในความจุที่ระบบรับไหว โดยสำเร็จ 15 งานใน 15 นาที และคิวยังคงมีสุขภาพดีตลอดเวลา

สรุป

  • ปัญหา MVCC dead tuple ในคิวที่สร้างบน Postgres ไม่ใช่ของเก่าจากปี 2015
  • Postgres สมัยใหม่ให้พื้นที่เผื่อมากขึ้นด้วย การปรับปรุง B-tree และ SKIP LOCKED แต่ กลไกพื้นฐานยังเหมือนเดิม
    • หาก VACUUM เก็บกวาด dead tuple ไม่ทัน มันก็จะสะสม
    • หากทรานแซกชันที่รันนานหรือรันทับซ้อนกันตรึง MVCC horizon ไว้ VACUUM ก็จะเก็บกวาดไม่ได้
  • ในสภาพแวดล้อมที่ใช้แนวคิด “Just use Postgres” แล้วรวมคิว งานวิเคราะห์ และตรรกะแอปไว้ใน DB เดียว นี่ไม่ใช่ ความเสี่ยงเชิงทฤษฎี แต่เป็น เงื่อนไขการปฏิบัติการตามปกติ
  • รูปแบบอันตรายไม่ใช่การพังแบบฉับพลัน แต่เป็น สภาวะสมดุลที่ค่อย ๆ เสื่อมลงอย่างเงียบ ๆ — lock time ค่อย ๆ เพิ่ม, job ช้าลง และไม่มีสัญญาณเตือนดังขึ้น
  • เครื่องมือ timeout ของ Postgres ไม่สามารถแยกคลาสของ workload หรือจำกัด concurrency ได้
  • หากจะรันคิวร่วมกับ workload อื่น มาตรการที่ได้ผลที่สุดคือ ทำให้แน่ใจว่า VACUUM ตามทันได้ และ Traffic Control ช่วยให้เรื่องนี้ง่ายขึ้น

1 ความคิดเห็น

 
GN⁺ 12 일 전
ความคิดเห็นจาก Hacker News
  • Postgres ยังคงมีปัญหา vacuum horizon อยู่ นี่คืออาการที่คิวรีที่รันนานไปขัดขวางการ vacuum ของตารางที่มีการเปลี่ยนแปลงอย่างรวดเร็ว ปัญหานี้เป็นที่รู้จักกันดีมาตั้งแต่ปี 2015 แล้ว Postgres แบบมาตรฐานไม่มีเครื่องมือดี ๆ สำหรับแก้ปัญหานี้ แต่เวอร์ชันคัสตอมของบริษัทผู้เขียนมีฟีเจอร์ที่จัดการได้ โดยสรุปแล้ว การผสมงานยาวแบบ OLAP กับงานเร็วแบบคิวไว้ใน Postgres อินสแตนซ์เดียวกันยังไม่ใช่ความคิดที่ดีเสมอไป ขึ้นอยู่กับความต้องการ การใช้ message queue อย่าง 0MQ หรือ RMQ อาจเป็นวิธีแก้ที่ง่ายกว่า

    • ตราบใดที่ฐานข้อมูลยังควบคุมแคชหรือ buffer pool อย่างละเอียดไม่ได้ การผสมโหลดที่ต่างกันแบบนี้ก็มักเป็นทางเลือกที่ไม่ดีอยู่เสมอ เพราะไม่มีวิธีป้องกันไม่ให้ตารางสำหรับงานวิเคราะห์ทำให้แคชทั้งหมดสกปรก
  • บทความใช้ได้ แต่มีบางจุดที่อยากทักท้วง

    1. คำอธิบายเรื่อง MVCC horizon ดูเหมือนจะขัดแย้งกันเอง ถ้าทรานแซกชันเริ่มคนละเวลา snapshot ก็จะต่างกัน และเมื่อทรานแซกชันแรกจบลง vacuum ก็ควรจะเดินหน้าต่อได้
    2. ปัญหาด้านประสิทธิภาพของคิวรี SELECT * FROM jobs WHERE status='pending' ORDER BY run_at LIMIT 1 FOR UPDATE SKIP LOCKED; มีอยู่จริง แต่สามารถบรรเทาได้โดยเพิ่มคอลัมน์ที่มีค่าเพิ่มขึ้นแบบ monotonic แล้วสร้างดัชนีไว้ แบบนี้จะไม่ต้องสนใจ dead tuple และมีแค่เปลืองพื้นที่เท่านั้น โดยประสิทธิภาพการอ่านจะลดลงน้อยกว่า อย่างไรก็ตาม การรับประกันการเพิ่มขึ้นแบบ monotonic ในสถานการณ์ที่มีการเขียนพร้อมกันนั้นขึ้นอยู่กับการออกแบบแอปพลิเคชัน
    3. สรุปคือ บทเรียนก็คือ “อย่าใช้ทรานแซกชันที่ยาวมากร่วมกับความถี่ทรานแซกชันที่สูงมากใน Postgres”
    • ต่อให้เพิ่มดัชนี Postgres ก็ยังต้องเก็บ dead tuple ไว้จนกว่าจะจัดการได้หมดอยู่ดี อาจเร็วขึ้นเล็กน้อย แต่สุดท้ายดิสก์ก็จะเต็ม และอาจไปรบกวน vacuum ของตารางอื่นด้วย
  • ผู้เขียนเอง ถ้ามีคำถามก็ถามมาได้เสมอ

    • ดูเหมือนว่าการทำคิวในบล็อกจะคงทรานแซกชันไว้ระหว่างที่งานกำลังรันอยู่ ผมเข้าใจคำแนะนำที่ว่าให้ทำให้สั้นที่สุดเท่าที่เป็นไปได้ แต่สงสัยว่าจะแก้ด้วยการอัปเดตคอลัมน์สถานะเป็น “processing” เพื่อหลีกเลี่ยงทรานแซกชันยาว ๆ ไปเลยได้ไหม
    • อยากรู้ว่าได้ลองตั้งค่า fillfactor ของตารางคิวให้ต่ำกว่า 100 แล้วทดสอบหรือยัง การใช้ HOT update อาจช่วยให้ตอนเปลี่ยนสถานะไม่ต้องสร้างรายการดัชนีใหม่ และนำพื้นที่ที่ตายแล้วกลับมาใช้ซ้ำได้ ซึ่งน่าจะช่วยเลื่อนเวลาที่ปัญหาจะเกิดออกไป
    • อยากรู้ว่าวิธีแก้นี้ต่างจากการใช้ pg_squeeze อย่างไร เราก็เจอปัญหาเดียวกันในระบบคิวและกำลังทดสอบ pg_squeeze อยู่ ซึ่งดูเหมือนว่าจะทำงานได้ค่อนข้างดี
  • มันดูคล้ายโฆษณา แต่คงจะดีถ้ามีคำอธิบายเกี่ยวกับแนวทางแก้ปัญหาเชิงเทคนิคมาบ้างสักหน่อย

  • Postgres ทำอะไรได้เยอะมาก ผู้คนมักเลือก Kafka หรือ SQS แต่จริง ๆ แล้วก็มีงานอีกมากที่ Graphile Worker จัดการได้สบาย

    • แนวคิดแบบ “ให้ Postgres ทำทุกอย่าง” นั้นดีต่อการรักษาความเรียบง่ายในระบบขนาดเล็กหรือกลาง แต่เมื่อระบบใหญ่ขึ้น ก็ควรให้ฐานข้อมูล SQL รับภาระงานให้น้อยที่สุดเท่าที่จะทำได้ เพราะมันมักเป็นคอขวดของระบบส่วนใหญ่
    • SQS เรียบง่ายมากและรวมเข้ากับสภาพแวดล้อม AWS ได้ง่าย Kafka ซับซ้อนกว่ามาก แต่ถ้ามีฟีเจอร์ที่ต้องใช้ก็เป็นตัวเลือกที่ยอดเยี่ยม เพียงแต่ภาระในการดูแลระบบสูง และหลายโปรเจกต์ก็นำมาใช้เพื่อใส่ในเรซูเม่ ขณะที่ SQS ถูกใช้เป็นเครื่องมือเชิงปฏิบัติมากกว่า แต่ถ้าคุณพยายามจะออกจาก AWS การพึ่งพานี้ก็อาจกลายเป็นปัญหาได้
  • ใน Postgres ปัญหาจะร้ายแรงขึ้นมากเมื่อมีการอัปเดตแถว ถ้าใช้แค่การแทรกกับการลบก็ยังพออยู่ได้นานพอสมควร

    • ใน Postgres คำสั่ง UPDATE แท้จริงแล้วคือการผสมกันของ INSERT กับ DELETE