การใช้รูปแบบการออกแบบที่สำคัญนี้หมายความว่าเราไม่สามารถค้นหาข้อมูลของเราได้ใช่หรือไม่

ก่อนหน้านี้ ฉันเขียนเกี่ยวกับ มวลรวม ซึ่งเป็นรูปแบบการออกแบบไมโครเซอร์วิสที่สำคัญแต่ยังไม่ค่อยได้รับความชื่นชม บ่อยครั้งเมื่อฉันแนะนำรูปแบบนี้ ฉันได้ยินข้อกังวลทั่วไป: หากเราใช้สถาปัตยกรรมแบบรวม เราจะปิดประตูสู่การค้นหาข้อมูลของเราหรือไม่

คำตอบคือเน้นว่าไม่

ในบทความนี้ เราจะสรุปรูปแบบการรวมนั้น แสดงให้เห็นว่าเหตุใด (เมื่อดูแวบแรก) จึงอาจดูเหมือนว่ารูปแบบดังกล่าวขัดขวางการค้นหา จากนั้นจึงอธิบายว่าทำไมจึงไม่เป็นเช่นนั้นจริง ๆ

มวลรวม เป็นรูปแบบการออกแบบที่สำคัญในการออกแบบไมโครเซอร์วิส ฉันได้อธิบายรูปแบบนี้ ประโยชน์ของมัน และวิธีการนำไปใช้แล้ว ในบทความที่แล้ว แต่ขอสรุปไว้ที่นี่

โดยสรุป มวลรวมคือกลุ่มของเอนทิตีที่เกี่ยวข้องซึ่งถือเป็นหน่วยอะตอมเดี่ยว ตามคำนิยาม มวลรวมประกอบด้วย:

  • หน่วยงานที่เกี่ยวข้องจำนวนหนึ่ง
  • ขอบเขตที่กำหนดเอนทิตีที่มีอยู่ใน Aggregate อย่างชัดเจน (รวมถึงเอนทิตีที่ไม่ใช่)
  • เอนทิตี root เดียว ซึ่งเป็นเอนทิตี เท่านั้น ภายใน Aggregate ที่สามารถเข้าถึงได้โดยตรงจากโลกภายนอก

หนึ่งในตัวอย่างที่ชัดเจนที่สุดของ Aggregate อาจเป็นอ็อบเจ็กต์ User แม้ว่ากรณีการใช้งานเฉพาะอาจแตกต่างกัน แต่เราก็สามารถนึกภาพโมเดลออบเจ็กต์ที่เรามีออบเจ็กต์หลัก User ได้อย่างง่ายดาย (พร้อมช่องต่างๆ เช่น FirstName, LastName, DateOfBirth, NationalId ฯลฯ) เราอาจแนบคอลเลกชันข้อมูลการติดต่อ เช่น Address, Phone หรือ Email เข้ากับออบเจ็กต์ User นั้น

ออบเจ็กต์ User นั้นชัดเจนโดยรูทของ User Aggregate ไม่มีเอนทิตีอื่นใดที่อยู่นอก Aggregate ไม่ควรสามารถเข้าถึง User Aggregate ผ่านเอนทิตีอื่นใดใน Aggregate

การปฏิบัติตามรูปแบบนี้มีประโยชน์มากมายที่ฉันระบุไว้ใน "บทความก่อนหน้า" ของฉัน; เหตุผลเหล่านั้นได้แก่:

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


มวลรวมและไมโครเซอร์วิส

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

กล่าวอีกนัยหนึ่ง ในขณะที่เราออกแบบ Aggregates ของเรา Aggregates เหล่านี้จะขับเคลื่อนการออกแบบของ:

  • สคีมาของฐานข้อมูลที่เก็บ Aggregates
  • API ของไมโครเซอร์วิสที่ให้การเข้าถึงฐานข้อมูลเหล่านั้นโดยตรง

เมื่อดูตัวอย่างผู้ใช้ของเราจากด้านบน เราน่าจะจบลงด้วยคู่ไมโครเซอร์วิสและฐานข้อมูลที่มีลักษณะดังนี้:

โปรดทราบว่าเราจะอธิบาย ReST API ในตัวอย่างของเราเพื่อจุดประสงค์ในการอธิบาย แต่หลักการเดียวกันนี้ใช้กับ Thrift API, gRPC API ฯลฯ ฐานข้อมูลอาจเป็น "RDBMS" เช่น MySQL แต่อาจเป็น "คลังข้อมูลเอกสาร" เช่น MongoDB ได้อย่างง่ายดายพอๆ กัน

ภายในสถาปัตยกรรมของเรา เราจะมีบริการอื่นๆ ระดับสูงกว่าที่จะใช้บริการข้อมูลเหล่านี้ ตัวอย่างเช่น เราอาจมี Orchestration Service ที่รวม Aggregates ต่างๆ เข้าด้วยกัน ตัวอย่างด้านล่างแสดงบริการภายในเว็บไซต์อีคอมเมิร์ซที่รวบรวมภาพรวมของคำสั่งซื้อออนไลน์ไว้ด้วยกัน โดยทำตามขั้นตอนต่อไปนี้:

  • เปิดเผย GET API ที่ใช้คำสั่ง GUID
  • ดึงข้อมูล Order Aggregate ที่แสดงโดย GUID นั้น
  • แยก GUID ของผู้ซื้อและผู้ขาย (ซึ่งเป็นผู้ใช้ทั้งคู่)
  • ดึงข้อมูลกลุ่มผู้ใช้ที่เป็นตัวแทนของผู้ซื้อและผู้ขาย
  • แพ็กเกจการรวมทั้งหมดเหล่านั้นเป็นรูปแบบรายละเอียดการสั่งซื้อระดับสูงและส่งกลับไปยังผู้เรียก

ฟังดูดี. แต่การสืบค้นข้อมูลรวมของเราล่ะ

ข้อกำหนดการนำเข้าประการหนึ่งของ Aggregates ซึ่งต้องทำซ้ำคือ การเข้าถึง Aggregate ทั้งหมดจะต้องผ่านเอนทิตีราก ดังนั้น URL คำขอใดๆ จะต้องขึ้นต้นด้วย
/aggregate/{aggregate-identifier}
ดังนั้น หากเราจัดเตรียม API การอ่านให้กับบริการข้อมูลผู้ใช้ของเรา API เหล่านั้นจะมีลักษณะดังนี้:

GET  /users/{guid}
GET  /users/{guid}/phones
GET  /users/{guid}/phones/{phoneId}

นั่นหมายความว่าเรา ไม่สามารถ ให้บริการ API ดังต่อไปนี้:

GET /users/phones/{phoneId}

ผู้อ่านที่ชาญฉลาดอาจตระหนักว่าเราไม่สามารถให้บริการ API สำหรับ "การค้นหา" ดังต่อไปนี้:

GET /users/[email protected]

ดูเผินๆ นี่ดูเหมือนเป็นปัญหาใหญ่

จะเกิดอะไรขึ้นถ้าเราdoจำเป็นต้องค้นหาผู้ใช้ — ไม่ใช่โดย GUID ของพวกเขา — แต่โดยที่อยู่อีเมลของพวกเขา?

หรือถ้าเราปรับเปลี่ยนตัวอย่าง Order ของเราจากด้านบน จะเกิดอะไรขึ้นหาก Orchestration Service ของเรายอมรับ GUID ผู้ใช้ แทน จากนั้นจำเป็นต้องค้นหาผ่าน คำสั่งซื้อ เพื่อค้นหารายการที่มี GUID ของผู้ซื้อหรือผู้ขาย ที่ตรงกัน

ในวงกว้าง จะเกิดอะไรขึ้นหากเราต้องการค้นหา ใด ๆ รวมด้วยบางสิ่ง อื่น ๆ นอกเหนือจาก GUID ของมัน นี่แทบจะไม่ใช่ความต้องการที่ผิดปกติหรือการถามที่ไม่สมเหตุสมผล แต่สถาปัตยกรรมเชิงรวมจะขัดขวางสิ่งนี้หรือไม่?

วิธีแก้ไข: ใช้บริการจัดทำดัชนีแยกต่างหาก

วิธีแก้ปัญหานี้ง่ายมาก เราจะใช้บริการแยกต่างหากซึ่งได้รับการปรับให้เหมาะสมสำหรับการจัดทำดัชนีคำค้นหา “การค้นหา” ทั้งหมด — นั่นคือคำขอ “GET” ทั้งหมดที่ค้นหาสิ่งอื่นนอกเหนือจากอินสแตนซ์ของการรวมของเราที่ระบุโดย ID — จะถูกดำเนินการกับบริการจัดทำดัชนีนี้

บริการข้อมูลของเราจะยังคงเป็นแหล่งที่มาหรือระบบบันทึกสำหรับ Aggregate การเขียนทั้งหมดไปยัง Aggregates ของเรา (ส่วนแทรก การอัปเดต การลบ ฯลฯ) จะเกิดขึ้นผ่านบริการนี้ ในทางกลับกัน บริการจัดทำดัชนีจะไม่ได้รับการอัปเดตโดยตรง แต่จะได้รับแจ้งถึงการเขียนเหล่านี้แทน — โดยทั่วไปผ่านกลไกอะซิงโครนัส เช่น คาฟคา — และจะถูกเก็บไว้อย่างสม่ำเสมอในที่สุด

เรามาทบทวนปัญหา find-orders-by-user ที่เรานำเสนอไปก่อนหน้านี้ บริการประสานของเราจะต้องสามารถค้นหาคำสั่งซื้อที่ GUID ของผู้ซื้อหรือ GUID ของผู้ขายตรงกับ GUID ผู้ใช้ที่กำหนด

เพื่อสนับสนุนสิ่งนี้ เราจะแนะนำบริการจัดทำดัชนีคำสั่งซื้อ บริการนี้จะได้รับแจ้งจากบริการข้อมูลคำสั่งซื้อเมื่อมีการเพิ่มเติม (หรือการอัปเดต หากเราอนุญาตให้อัปเดตคำสั่งซื้อที่มีอยู่) จากนั้นจะรักษาดัชนี GUID ของผู้ซื้อและผู้ขาย ซึ่งแมปกลับไปยังคำสั่งซื้อที่เกี่ยวข้องกัน จากนั้น Orchestration Service จะสอบถามบริการการจัดทำดัชนีคำสั่งซื้อ

บริการจัดทำดัชนีคำสั่งซื้อจะส่งคืนอะไร หากพบว่าคำสั่งซื้อที่ตรงกัน เรามีทางเลือกสองสามทาง

  1. ส่งคืน GUID ของคำสั่งซื้อที่ตรงกัน บริการจัดทำดัชนีของเราอาจไม่ส่งคืนออบเจ็กต์ Order ด้วยตนเอง แต่เป็นเพียง GUID ของคำสั่งซื้อที่ตรงกัน ผู้เรียก (ในกรณีนี้คือ Order Detail Orchestration Service) จะต้องรับผิดชอบในการเรียก Order Data Service เพื่อดึงรายละเอียดของคำสั่งซื้อที่ตรงกัน
    ประโยชน์หลักของแนวทางนี้คือบริการ Orchestration จะถูกดึงข้อมูลอยู่เสมอ การนำเสนอคำสั่งในปัจจุบัน โปรดทราบว่าจากการออกแบบแล้ว บริการจัดทำดัชนีจะสอดคล้องกันในที่สุด ดังนั้นรายละเอียดที่ส่งคืนอาจไม่เป็นข้อมูลล่าสุด
    ประโยชน์เพิ่มเติมอีกประการหนึ่งคือจำนวนข้อมูลที่ส่งระหว่างบริการทำดัชนีและ Orchestration การบริการลดลงอย่างมาก
    ข้อเสียที่เห็นได้ชัดคือ การโทรเพิ่มเติมที่บริการประสานประสานต้องทำ ขึ้นอยู่กับจำนวนคำสั่งซื้อที่ตรงกัน ซึ่งอาจส่งผลให้มีการโทรไปยังบริการรายละเอียดคำสั่งซื้อเป็นจำนวนมาก
  2. ส่งคืนการแสดงที่สมบูรณ์ของคำสั่งซื้อที่ตรงกัน บริการจัดทำดัชนีของเราอาจส่งคืนออบเจ็กต์ Order ทั้งหมดแทน
    แน่นอนว่าข้อดีและข้อเสียเป็นสิ่งที่ตรงกันข้ามกับแนวทางก่อนหน้า ในที่นี้ Indexing Service จะส่งข้อมูลเพิ่มเติมกลับมา แต่ Orchestration Service จะไม่จำเป็นต้องโทรไปยัง Data Service เพิ่มเติม อย่างไรก็ตาม ข้อมูลที่ส่งคืนโดย Orchestration Service อาจล้าสมัย

แนวทางใดที่จะเป็นประโยชน์นั้นขึ้นอยู่กับการออกแบบเฉพาะของเรา ตัวอย่างเช่น หากข้อมูลของเราเป็นแบบต่อท้ายเท่านั้น ซึ่งไม่ได้อัปเดตเมื่อสร้างแล้ว เราก็ไม่จำเป็นต้องกังวลเกี่ยวกับข้อมูลที่ไม่ซิงค์กัน ในกรณีนี้ เราอาจสนับสนุนตัวเลือกที่ 2

ยิ่งไปกว่านั้น หากเป็นกรณีนี้ เราอาจตัดสินใจที่จะพัฒนาการออกแบบของเราให้ดียิ่งขึ้นไปอีก โดยกำหนดให้การดำเนินการอ่านทั้งหมดต้องผ่านบริการจัดทำดัชนีของเรา ในกรณีนี้ เรามีการแยกที่ชัดเจนยิ่งขึ้นระหว่างบริการข้อมูลและบริการจัดทำดัชนี

สรุป

ก่อนหน้านี้ เราได้นำเสนอการแสดงภาพของ Aggregates และไมโครเซอร์วิสที่แสดงทางด้านซ้ายด้านล่าง เมื่อจำเป็นต้องค้นหา แบบจำลองทางจิตของเราก็ควรปรับให้เป็นตัวแทนทางด้านขวา

แน่นอนว่าเป็นภาพรวมทั่วไป รายละเอียดที่แท้จริงของเราอาจแตกต่างกัน ตัวอย่างเช่น เราอาจสร้างบริการจัดทำดัชนีและการค้นหาแยกต่างหาก หรือเราอาจใช้กลไกที่แตกต่างจากคาฟคาเพื่อให้ระบบซิงค์กัน

แต่ความคิดโดยรวมยังคงเหมือนเดิม เพื่อสนับสนุนสถาปัตยกรรมเชิงรวมพร้อมกับความสามารถในการค้นหา เราควรรวมบริการข้อมูลของเราเข้ากับบริการจัดทำดัชนีร่วมเพื่อรองรับการค้นหา

รับสิทธิ์เข้าถึงมุมมองผู้เชี่ยวชาญ — สมัครสมาชิก DDI Intel