เรื่องราวของนักพัฒนาเกี่ยวกับความสุดโต่งของฐานข้อมูลได้จุดประกายการถกเถียงอย่างเข้มข้นเกี่ยวกับแนวทางที่ถูกต้องในการจัดเก็บข้อมูลและตรรกะทางธุรกิจ เรื่องราวนี้บอกเล่าการเดินทางของทีมหนึ่งจากฝันร้าย stored procedure สู่โซลูชัน key-value store ที่มีปัญหาไม่แพ้กัน โดยเน้นให้เห็นว่าการตัดสินใจด้านสถาปัตยกรรมสามารถแกว่งไปจากความสุดโต่งหนึ่งไปยังอีกความสุดโต่งหนึ่งโดยไม่พบจุดสมดุลที่เหมาะสม
ปัญหาเดิม: Stored Procedures ที่ควบคุมไม่ได้
ระบบเดิมประสบปัญหาคลาสสิกของการออกแบบฐานข้อมูลที่ซับซ้อนเกินไป ตรรกะทางธุรกิจอยู่ใน stored procedures ทั้งหมด ซึ่งมีการ join ที่ซับซ้อนครอบคลุมหลายฐานข้อมูล SQL Server procedures เหล่านี้กลายเป็นคอขวดด้านประสิทธิภาพ กินเวลา CPU บนเซิร์ฟเวอร์ฐานข้อมูลที่มีจำกัด และสร้างปัญหาความล่าช้าที่คาดเดาไม่ได้เมื่อ query plan เปลี่ยนแปลงอย่างไม่คาดคิด ระบบยังพึ่งพา MSDTC (Microsoft Distributed Transaction Coordinator) อย่างมาก ซึ่งมักทำให้เกิด deadlock และระบบล่มบ่อยครั้ง
MSDTC: บริการของ Microsoft ที่ประสานงาน transaction ข้ามหลายฐานข้อมูลหรือระบบ แต่มีชื่อเสียงในด้านการสร้าง deadlock และปัญหาความน่าเชื่อถือ
ปัญหาของระบบเดิม:
- โลจิกทางธุรกิจถูกฝังอยู่ใน stored procedures ที่ซับซ้อน
- ฐานข้อมูล SQL Server หลายตัวกระจายอยู่ในเซิร์ฟเวอร์ต่างๆ
- พึ่งพา MSDTC มากเกินไปทำให้เกิด deadlocks
- การเปลี่ยนแปลง query plan ที่คาดเดาไม่ได้ทำให้เกิด timeouts
- เวลาในการ build นาน 15-30 นาทีและต้องใช้สภาพแวดล้อมการพัฒนาแบบ VM
การแก้ไขที่เกินขอบเขต: ความสุดโต่งของ Key-Value Store
เพื่อตอบสนองต่อปัญหา SQL ทีมสถาปัตยกรรมได้ทำการเปลี่ยนแปลงอย่างรุนแรงไปในทิศทางตรงข้าม พวกเขาตัดสินใจละทิ้งฐานข้อมูลเชิงสัมพันธ์ทั้งหมด เลือกใช้ key-value store แบบพื้นฐานที่มีเพียงสี่การดำเนินการพื้นฐาน: อ่าน แทรก อัปเดต และลบ key เดียว ไม่มี transaction ไม่มี batching ไม่อนุญาตให้มี query ที่ซับซ้อน
แนวทางนี้สร้างปัญหาใหม่ขึ้นมาทันที ข้อมูลทางธุรกิจที่มีความสัมพันธ์สูงต้องถูกแปลงให้เป็นเอกสาร JSON ขนาดใหญ่ บางครั้งมีขนาดถึงหลายร้อยกิโลไบต์ เนื่องจาก key-value store ขาดคุณสมบัติของฐานข้อมูลเอกสาร แม้แต่การอัปเดตเล็กน้อยก็ต้องอ่านเอกสารทั้งหมด ทำการเปลี่ยนแปลงในโค้ดแอปพลิเคชัน จากนั้นเขียนทุกอย่างกลับไป ทีมงานเพิ่มการบีบอัดเพื่อลด network overhead แต่สิ่งนี้ทำให้ข้อมูลไม่สามารถตรวจสอบได้ด้วยเครื่องมือฐานข้อมูลมาตรฐาน
ข้อจำกัดของ Key-Value Store:
- มีเพียง 4 การดำเนินการ: อ่าน แทรก อัปเดต ลบ single keys
- ไม่รองรับ transactions หรือ batching
- เอกสาร JSON มีขนาดถึงหลายร้อย kilobytes
- จำเป็นต้องอ่าน/เขียนเอกสารทั้งหมดสำหรับการอัปเดตบางส่วน
- ต้องใช้การบีบอัด Gzip ทำให้เครื่องมือมาตรฐานใช้งานไม่ได้
การระเบิดของความซับซ้อน: ระบบ Checkpointing
โดยไม่มี database transaction ทีมงานสร้างระบบ checkpointing ที่ซับซ้อนเพื่อจัดการความสอดคล้องของข้อมูล การดำเนินการเขียนทุกครั้งต้องสร้าง UUID และเก็บไว้เป็น checkpoint จากนั้นฝัง UUID นี้ในเอกสารเป้าหมายเพื่อป้องกันการดำเนินการซ้ำระหว่างการลองใหม่ แนวทางนี้เพิ่มจำนวนการเดินทางไปกลับของฐานข้อมูลเกือบเป็นสองเท่าเมื่อเทียบกับระบบเดิม ทำให้ปัญหาความล่าช้าแย่ลงแทนที่จะดีขึ้น
ในทางปฏิบัติ การเขียนข้อมูลไปยังฐานข้อมูลเดียวกันซึ่งก่อนหน้านี้ต้องใช้ 5-10 round trip ตอนนี้ต้องใช้เกือบสองเท่าของจำนวน trip สำหรับการดำเนินการ checkpointing เพิ่มเติม
ค่าใช้จ่ายของระบบ Checkpointing:
- การสร้าง UUID สำหรับทุกการดำเนินการเขียนข้อมูล
- การจัดเก็บ Checkpoint ในระบบแยกต่างหาก
- การฝัง UUID ในเอกสารเป้าหมาย
- การเดินทางไปกลับของฐานข้อมูลเพิ่มขึ้นเกือบสองเท่า (จาก 5-10 เป็น ~20)
- ตรรกะการลองใหม่ที่ซับซ้อนเพื่อความสามารถในการทำซ้ำได้
มุมมองของชุมชน: การถกเถียงเรื่องทางสายกลาง
ชุมชนนักพัฒนายังคงแบ่งแยกอย่างลึกซึ้งเกี่ยวกับตัวเลือกสถาปัตยกรรมฐานข้อมูล นักพัฒนาหลายคนแบ่งปันเรื่องราวสยองขวัญเกี่ยวกับ stored procedure ที่กลายเป็นสัตว์ประหลาดที่ดูแลรักษาไม่ได้ โดยมีตรรกะทางธุรกิจกระจัดกระจายไปทั่วระบบฐานข้อมูลและภาษาต่างๆ คนอื่นๆ โต้แย้งว่า stored procedure ยังมีที่ยืน โดยเฉพาะสำหรับการดำเนินการข้อมูลจำนวนมากและเมื่อแอปพลิเคชันหลายตัวต้องเข้าถึงฐานข้อมูลเดียวกันด้วยกฎทางธุรกิจที่สอดคล้องกัน
การถกเถียงระหว่าง ORM กับ SQL แบบดิบก็ปรากฏขึ้นอย่างชัดเจนในการอภิปราย นักพัฒนาบางคนมอง ORM เป็นตัวเพิ่มประสิทธิภาพที่ประหยัดเวลาแม้จะมีต้นทุนด้านประสิทธิภาพ ในขณะที่คนอื่นๆ มองว่าเป็นการสร้างนามธรรมที่ซ่อนโอกาสการปรับปรุงฐานข้อมูลที่สำคัญ ฉันทามติดูเหมือนจะเป็นว่าการยึดติดแนวทางเดียวอย่างเคร่งครัดมักนำไปสู่ปัญหา
ORM: เครื่องมือ Object-Relational Mapping ที่แปลระหว่างตารางฐานข้อมูลและออบเจ็กต์ภาษาโปรแกรม ทำให้การดำเนินการฐานข้อมูลง่ายขึ้นแต่บางครั้งมีประสิทธิภาพน้อยกว่า
บทเรียนในความสมดุลทางสถาปัตยกรรม
เรื่องราวนี้แสดงให้เห็นรูปแบบทั่วไปในการพัฒนาซอฟต์แวร์: การแก้ปัญหาสุดโต่งหนึ่งด้วยการแกว่งไปสู่ความสุดโต่งตรงข้าม แนวทาง stored procedure เดิมมีปัญหาที่ถูกต้อง แต่โซลูชัน key-value ได้ทิ้งการปรับปรุงฐานข้อมูลหลายทศวรรษพร้อมกับปัญหา แนวทางที่รอบคอบมากกว่าอาจเกี่ยวข้องกับการ refactor stored procedure การปรับปรุงกลยุทธ์การทำดัชนี หรือการใช้ ORM สมัยใหม่พร้อมการตรวจสอบประสิทธิภาพอย่างระมัดระวัง
เรื่องราวนี้เป็นการเตือนใจว่าการตัดสินใจด้านสถาปัตยกรรมควรอิงจากข้อกำหนดทางเทคนิคเฉพาะแทนที่จะเป็นปฏิกิริยาต่อจุดเจ็บปวดในอดีต บางครั้งโซลูชันที่ดีที่สุดไม่ได้อยู่ในการเปลี่ยนแปลงปฏิวัติ แต่อยู่ในการปรับปรุงแบบวิวัฒนาการของระบบที่มีอยู่
อ้างอิง: Wrong ways to use the databases, when the pendulum swung too far