Data Topologies (โทโพโลยีข้อมูล)

ตลอดบทนี้เราได้พูดถึงว่าข้อมูลมีบทบาทสำคัญเพียงใดในสถาปัตยกรรม microservices อันที่จริง microservices เป็นสถาปัตยกรรมสไตล์เดียวที่ บังคับ ให้สถาปนิกต้องแยกข้อมูลออกจากกัน แม้ว่าจะ เป็นไปได้ (แม้จะไม่ค่อยได้ผลนัก) ที่จะใช้ฐานข้อมูล monolithic ใน distributed architecture แบบอื่น แต่ใน microservices นั้นไม่ใช่ทางเลือกเลย domain database ก็เช่นกัน ตามที่เราพูดถึงใน "Data Topologies" และใน "Data Topologies" ด้วยเช่นกัน ทั้งนี้เนื่องจากธรรมชาติที่ละเอียดมาก (fine-grained) ของ microservices, bounded context และจำนวน service ที่มากมายใน microservices ecosystem ส่วนใหญ่

เพื่อแสดงให้เห็นว่าทำไมฐานข้อมูล monolithic จึงไม่เหมาะกับ microservices ลองพิจารณาสถานการณ์ที่ 60 service ใช้ฐานข้อมูลเดียวกัน ปัญหาแรกที่จะเกิดขึ้นคือการควบคุมการเปลี่ยนแปลงในสถาปัตยกรรม ดังที่ Figure 18-13 แสดงให้เห็น การเปลี่ยนโครงสร้างของฐานข้อมูลนั้น (เช่น เปลี่ยนชื่อคอลัมน์หรือลบตาราง) จะต้องเปลี่ยนแปลง service ทั้ง 60 ตัว ที่ใช้ข้อมูลนั้นตามไปด้วย ลองนึกภาพการประสานงาน maintenance, testing และ release ของ service ที่ deploy แยกกันถึงห้าสิบกว่าตัว พร้อมกับต้อง release การเปลี่ยนแปลงฐานข้อมูลไปพร้อมกันด้วย งานนี้จะยากลำบากอย่างมาก และมีแนวโน้มจะจบลงด้วยหายนะ

Change control issues

Figure 18-13. การควบคุมการเปลี่ยนแปลงด้วยฐานข้อมูล monolithic เป็นงานที่ท้าทายอย่างมาก

บางทีปัญหาใหญ่ที่สุดของการรวมโทโพโลยีข้อมูลแบบ monolithic เข้ากับ microservices ก็คือมันทำลายแนวคิดเรื่อง bounded context ในเชิงกายภาพไปทั้งหมด อย่าลืมว่า bounded context ครอบคลุม ทุกอย่าง ที่จำเป็นต่อการทำงานของฟังก์ชันหรือซับโดเมนหนึ่ง ๆ รวมถึงฐานข้อมูลและโครงสร้างข้อมูลที่เกี่ยวข้อง หากทุก service ใช้ฐานข้อมูลและโครงสร้างข้อมูลเดียวกัน bounded context ก็จะหายไป

อีกปัญหาหนึ่งของข้อมูลแบบ monolithic คือเรื่อง scalability และ elasticity แม้เครื่องมือและผลิตภัณฑ์ปฏิบัติการจำนวนมาก จะคอยตรวจสอบโหลดพร้อมกันและปรับจำนวน instance ของ service โดยอัตโนมัติเพื่อรองรับการเพิ่มขึ้น แต่ฐานข้อมูลส่วนใหญ่ไม่สามารถ scale ตามได้ ความไม่สมดุลนี้อาจทำให้เกิดปัญหาเรื่อง responsiveness โดยรวมและ request timeout การจัดการ connection ของฐานข้อมูล ซึ่งโดยทั่วไปอยู่ในแต่ละ instance ของ service ก็เป็นอีกความกังวลหนึ่ง เมื่อจำนวน service และ instance เพิ่มขึ้น service อาจใช้ database connection ที่มีอยู่จนหมดอย่างรวดเร็ว ส่งผลให้เกิดการรอ connection และ request timeout มากขึ้นไปอีก

สุดท้าย หากฐานข้อมูลไม่สามารถใช้งานได้เนื่องจากล่ม การบำรุงรักษาตามแผน หรือการสำรองข้อมูล microservices ecosystem ทั้งหมดก็จะล่มไปด้วย—เช่นเดียวกับสถาปัตยกรรมสไตล์ใดก็ตามที่ใช้ฐานข้อมูล monolithic แม้จะไม่รุนแรงเท่า แต่โทโพโลยี ฐานข้อมูลแบบ domain-based ก็อาจประสบปัญหาเดียวกันในเรื่อง scalability, การจัดการ database connection pool, availability และ fault tolerance

ด้วยเหตุผลเหล่านี้ โทโพโลยีฐานข้อมูลมาตรฐานสำหรับ microservices คือรูปแบบ Database-per-Service ด้วยโทโพโลยีนี้ แต่ละ microservice เป็นเจ้าของข้อมูลของตัวเอง ซึ่งเก็บอยู่ในรูปตารางภายในฐานข้อมูลหรือ schema แยกต่างหาก ดังแสดงใน Figure 18-14

Database-per-Service topology

Figure 18-14. รูปแบบ Database-per-Service เป็นโทโพโลยีฐานข้อมูลทั่วไปสำหรับ microservices

โทโพโลยีนี้รักษา bounded context ไว้ ทำให้สถาปนิกควบคุมการเปลี่ยนแปลงได้ง่ายขึ้น เนื่องจาก service อื่นที่ต้องการข้อมูล ต้องขอผ่านสัญญา (contract) บางอย่างจาก service เจ้าของข้อมูล พวกมันจึง decouple จากโครงสร้างภายในของข้อมูลนั้น การเปลี่ยนโครงสร้างฐานข้อมูลจะกระทบเฉพาะ service เจ้าของภายใน bounded context เท่านั้น ทำให้สถาปนิกมีอิสระในการเปลี่ยน ประเภทฐานข้อมูล (เช่น จาก relational database เป็น document database) โดยไม่กระทบ service อื่น

โทโพโลยี Database-per-Service ยังให้ scalability, elasticity, availability และ fault tolerance ที่ยอดเยี่ยม ซึ่งเป็นคุณลักษณะทางสถาปัตยกรรมที่มักแย่ลงภายใต้โทโพโลยีฐานข้อมูลแบบ monolithic หรือ domain-based ยิ่งไปกว่านั้น การจัดการ connection ไปยังฐานข้อมูลภายใน bounded context ก็ง่ายกว่าฐานข้อมูลแบบ monolithic หรือ domain-based มาก

แม้โทโพโลยี Database-per-Service จะถูกใช้อย่างแพร่หลายใน microservices แต่ก็มีข้อเสียเช่นกัน ตัวอย่างเช่น จะเกิดอะไรขึ้นถ้ามีสอง service ขึ้นไปเขียนลงตารางฐานข้อมูลเดียวกัน หรือถ้า service ที่อยู่นอก bounded context จำเป็นต้อง query ฐานข้อมูลโดยตรงด้วยเหตุผลด้าน performance ในกรณีเหล่านี้ (ซึ่งพบได้ค่อนข้างบ่อย) เป็นไปได้ที่ service สองสามตัว จะแชร์ฐานข้อมูลร่วมกัน ดังแสดงใน Figure 18-15 เราแนะนำว่าไม่ควรมี service เกินห้าหรือหกตัวแชร์ฐานข้อมูล (หรือ schema) เดียวกัน หากมากกว่านั้น คุณจะเริ่มเจอปัญหาเดิม ๆ เรื่อง change control, scalability, elasticity, availability, fault tolerance และอื่น ๆ

Sharing data

Figure 18-15. การแชร์ข้อมูลระหว่าง microservice บางตัวเป็นไปได้

กรอบสี่เหลี่ยมรอบ service และฐานข้อมูลใน Figure 18-15 แสดงถึง bounded context การที่ service แชร์ฐานข้อมูลกันไม่ได้แปลว่าไม่มี bounded context เลย มันเพียงหมายความว่าสถาปนิกได้สร้าง bounded context ที่ กว้างขึ้น ตัวอย่างเช่น พวกเขาอาจมีเหตุผลที่ดีในการแยกการประมวลผลการชำระเงินออกเป็นประเภทต่าง ๆ (เช่น บัตรเครดิต บัตรของขวัญ PayPal คะแนนสะสม และอื่น ๆ) แต่แต่ละ service เหล่านี้ก็ยังต้องอัปเดตและเข้าถึงข้อมูลเดียวกัน ในทำนองเดียวกัน สถาปนิกอาจแยก shipping service เดียวออกเป็น service ที่ deploy แยกกันหลายตัว ตัวละหนึ่งวิธีการจัดส่ง แต่ service เหล่านั้นก็ยังต้องอัปเดตและเข้าถึงข้อมูลเดียวกันอยู่ดี

trade-off หลักของการแชร์ข้อมูลระหว่าง microservice ภายใน bounded context ที่กว้างขึ้นคือการควบคุมการเปลี่ยนแปลงฐานข้อมูล เมื่อ schema ของฐานข้อมูลเปลี่ยน สถาปนิกต้องประสานงานการเปลี่ยนแปลงและ deploy ของ service หลายตัว ทำให้การเปลี่ยนแปลง ฐานข้อมูลเสี่ยงขึ้นและคล่องตัวน้อยลง อาจมีผลเสียต่อ scalability, elasticity และ fault tolerance ด้วยเช่นกัน ขึ้นอยู่กับปัญหาทางธุรกิจและสถานการณ์