ในโลกของวิศวกรรมซอฟต์แวร์ มีเหตุการณ์ที่ถูกยกให้เป็นกรณีศึกษาที่ร้ายแรงที่สุดครั้งหนึ่ง นั่นคือเหตุการณ์ Therac-25 ในช่วงปี 1985–1987 เครื่องฉายรังสีรักษามะเร็งนี้เกิดความผิดพลาดทางวิศวกรรมที่นำไปสู่การได้รับรังสีเกินขนาดของผู้ป่วยหลายราย
หัวใจของความผิดพลาดนี้คือ Race Condition (ภาวะการแย่งชิงทรัพยากร) ซึ่งเกิดขึ้นเมื่อระบบพึ่งพาการทำงานของซอฟต์แวร์ในการควบคุมความปลอดภัยทั้งหมด แทนที่จะใช้ระบบฮาร์ดแวร์ป้องกัน (Hardware Interlocks) ที่เชื่อถือได้
ในฐานะ System Architect เมื่อเรานำหลักการของความล้มเหลวนี้มาประยุกต์ใช้กับระบบฐานข้อมูลอย่าง PostgreSQL เราจะพบว่าการจัดการสถานะ (State Management) ที่ไม่รัดกุม หรือการทำธุรกรรมที่ขัดแย้งกัน (Conflicting Transactions) ก็สามารถนำไปสู่ผลลัพธ์ที่ผิดพลาดและอันตรายได้เช่นกัน
การป้องกัน Race Condition ใน PostgreSQL: การสร้าง Safety Interlock ทางข้อมูล
ใน Therac-25 ปัญหาเกิดจากซอฟต์แวร์ส่วนหน้า (UI) เปลี่ยนค่าแล้ว แต่ซอฟต์แวร์ส่วนควบคุมหลัก (Data Subroutine) ไม่ได้รับรู้การเปลี่ยนแปลงนั้น ทำให้เกิดความไม่สอดคล้องของสถานะ (State Inconsistency) ในทางฐานข้อมูล เราต้องมั่นใจว่าเมื่อมีการอ่านและเขียนข้อมูลที่เกี่ยวข้องกับสถานะสำคัญ (เช่น Dosage Level หรือ Machine Status) จะต้องถูกล็อกและดำเนินการในระดับที่สูงที่สุด
PostgreSQL มีกลไกที่ทรงพลังในการป้องกันปัญหานี้ โดยเฉพาะการใช้ Transaction Isolation Level ที่เหมาะสม เช่น SERIALIZABLE ซึ่งเป็นการจำลองระบบ Interlock ทางกายภาพให้กลายเป็น Interlock ทางตรรกะของข้อมูล
ตัวอย่าง: การตรวจสอบสถานะเครื่องก่อนการจ่ายพลังงาน (Dosage Check)
สมมติว่าเรามีตาราง `machine_status` ที่เก็บสถานะของเครื่อง และเราไม่ต้องการให้สองธุรกรรม (Transaction) พยายามอัปเดตสถานะพร้อมกันโดยที่ธุรกรรมหนึ่งอ่านค่าที่ล้าสมัย (Stale Data) เราต้องใช้การล็อกอย่างเหมาะสม:
SQL
-- ตั้งค่า Isolation Level ให้เป็น SERIALIZABLE เพื่อป้องกัน Race Condition ที่รุนแรงที่สุด
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 1. ตรวจสอบสถานะปัจจุบันและล็อกแถวนี้ทันที (SELECT FOR UPDATE)
SELECT dosage_level, machine_id FROM machine_status WHERE machine_id = 'THERAC-A' FOR UPDATE;
-- 2. ตรวจสอบเงื่อนไขความปลอดภัย (Interlock Logic)
-- หาก Dosage Level เกินขีดจำกัด (เช่น 100) ให้ยกเลิกธุรกรรม
-- ในโลกจริง: IF dosage_level > 100 THEN ROLLBACK;
-- 3. ดำเนินการอัปเดตสถานะเมื่อผ่านการตรวจสอบแล้ว
UPDATE machine_status
SET dosage_level = 0, last_run = NOW()
WHERE machine_id = 'THERAC-A';
COMMIT;
การใช้ SELECT FOR UPDATE ในระดับ SERIALIZABLE ทำให้มั่นใจได้ว่าไม่มีธุรกรรมอื่นสามารถอ่านหรือแก้ไขแถวข้อมูลนี้ได้จนกว่าธุรกรรมปัจจุบันจะเสร็จสิ้น ซึ่งเป็นการจำลองกลไก Hardware Interlock ที่เชื่อถือได้ทางระบบฐานข้อมูล
บทสรุป: บทเรียนจาก Therac-25 สำหรับสถาปัตยกรรมระบบ
เหตุการณ์ Therac-25 สอนเราว่า การพึ่งพาเพียงชั้นใดชั้นหนึ่งของระบบ (เช่น UI หรือโค้ดแอปพลิเคชัน) นั้นอันตรายเสมอ สถาปนิกระบบที่ดีจึงต้องสร้างชั้นความปลอดภัยที่แข็งแกร่งที่สุดไว้ที่ระดับข้อมูล (Data Layer) เสมอ การใช้ Transaction Management และ Isolation Level ที่ถูกต้องใน PostgreSQL ไม่เพียงแต่ช่วยรักษาความถูกต้องของข้อมูล (Data Integrity) เท่านั้น แต่ยังช่วยสร้าง ‘Interlock’ ทางตรรกะที่ป้องกันความผิดพลาดร้ายแรงที่อาจเกิดขึ้นจากภาวะ Race Condition ได้อย่างมีประสิทธิภาพ