ข้ามไปยังเนื้อหา

ความสอดคล้องของข้อมูลใน MongoDB

คนที่มาจากโลกของฐานข้อมูลเชิงสัมพันธ์มักจะคว้า transaction ทันทีที่ต้องเปลี่ยนแปลงข้อมูลมากกว่าหนึ่งอย่าง แต่ใน MongoDB สัญชาตญาณนั้นมักจะพาคุณหลงทาง ฐานข้อมูลให้การรับประกันที่แข็งแกร่งกับคุณฟรี ๆ และการข้ามการรับประกันเหล่านั้นไปหา multi-document transaction เป็นสิ่งที่คุณทำได้ยาก ๆ และอย่างจงใจ ไม่ใช่ทำเป็นค่าเริ่มต้น โมดูลนี้พูดถึงการเข้าใจอย่างชัดเจนว่าคุณมีอะไรอยู่แล้ว สิ่งที่คุณขอเพิ่มได้เมื่อจำเป็นจริง ๆ และวิธีปรับ durability และ visibility ของทุก operation ขึ้นหรือลง

ข้อเท็จจริงเดียวที่ทุกอย่างที่เหลือยึดเกาะอยู่คือ การเขียนไปยัง document หนึ่งฉบับ เป็น atomic เมื่อคุณอัปเดตเรคคอร์ดของสมาชิกคนหนึ่ง MongoDB จะนำการเปลี่ยนแปลงทั้งหมดไปใช้ — แม้จะแตะ nested object หลายฟิลด์ และ array ทั้งหมดในคราวเดียว — เป็นขั้นตอนเดียวที่แบ่งแยกไม่ได้ ไม่มี reader คนอื่นเห็น document ในสภาพที่เปลี่ยนไปครึ่งหนึ่ง และถ้าการเขียนล้มเหลว document จะถูกทิ้งไว้ในสภาพเดิมเป๊ะ คุณไม่ต้องเปิดอะไร ไม่ต้อง commit อะไร และไม่ต้องจ่ายต้นทุนเพิ่มใด ๆ atomicity เป็นเพียงวิธีที่การเขียน document ทำงาน

เพราะหนึ่ง document คือหน่วยของ atomicity วิธีที่คุณ ออกแบบโมเดล ข้อมูลจึงเป็นตัวกำหนดว่าความสอดคล้องของคุณจะมาฟรีมากแค่ไหน ข้อมูลที่เปลี่ยนแปลงไปด้วยกันและอยู่ด้วยกันควรอยู่ใน document เดียวกัน เพื่อให้การเขียนครั้งเดียวรักษาความสอดคล้องไว้ได้ เมื่อข้อมูลที่เกี่ยวข้องกันกระจายอยู่ในหลาย document หรือหลาย collection จริง ๆ และต้องเปลี่ยนแปลงเป็นหน่วยเดียวกัน MongoDB มี multi-document transaction ให้ — transaction แบบ ACID จริง ๆ ข้าม session ใช้งานได้จริง แต่มีต้นทุนสูงกว่าและต้องใช้ replica set จึงอยู่ก้นกล่องเครื่องมือมากกว่าจะอยู่บนสุด

ที่ซ้อนทับอยู่บนทั้งสองอย่างคือปุ่มปรับคู่หนึ่งที่ใช้กับทุก operation write concern ควบคุมว่าสมาชิกของ replica set กี่ตัวต้องตอบรับการเขียน และต้อง flush ลง on-disk journal ด้วยหรือไม่ ก่อนที่ driver จะถือว่าการเขียนเสร็จสิ้น — นี่คือปุ่ม durability ส่วน read concern ควบคุมว่าข้อมูลที่คุณอ่านต้องสด และ commit แล้วมากแค่ไหน — นี่คือปุ่ม visibility ทั้งสองอย่างรวมกันช่วยให้คุณแลก latency กับความปลอดภัยได้ทีละ operation

flowchart TD
  W["A write request"] --> Q{"How many documents?"}
  Q -->|"One document"| A["Atomic automatically — no transaction needed"]
  Q -->|"Many documents as a unit"| T["Multi-document transaction in a session"]
  A --> WC["Write concern tunes durability"]
  T --> WC
  WC --> RC["Read concern tunes what readers see"]
เส้นทางการตัดสินใจ: single-document atomicity เป็นค่าเริ่มต้น ใช้ transaction เฉพาะเมื่อหลาย document ต้องเปลี่ยนเป็นหน่วยเดียว โดยมี concern ปรับ durability และ visibility
  • Single-document atomicity — ทำไมการเปลี่ยนแปลงใด ๆ ในหนึ่ง document ลึกแค่ไหนก็ตาม จึงเป็นแบบ all-or-nothing และวิธีออกแบบโมเดลข้อมูลให้สิ่งนี้ครอบคลุมความต้องการส่วนใหญ่ของคุณ
  • Multi-document transactions — การเปิด session การรันหลาย operation เป็นหน่วย ACID เดียว และการ commit หรือ abort พร้อมตัวอย่างคลาสสิกของการโอนเงินระหว่างบัญชี
  • Read and write concerns — การตั้งค่า w, j และ wtimeout สำหรับการเขียน ระดับ local, majority และ linearizable สำหรับการอ่าน และ read preference สำหรับเลือกว่าสมาชิกตัวไหนเป็นผู้ตอบ
  • Change streams — การ subscribe ฟีดสด ๆ ของ insert, update และ delete เพื่อให้แอปพลิเคชันของคุณตอบสนองต่อการเปลี่ยนแปลงข้อมูลได้ทันทีที่เกิดขึ้น
  • Single-document atomicity — update ที่ล้มเหลวไม่เปลี่ยนอะไรเลย; read-modify-write พร้อมกัน 100 ครั้งทำให้ increment ส่วนใหญ่หายขณะที่ $inc ไม่หาย; updateMany ถูกสังเกตเห็นในสภาพที่ทำไปครึ่งทาง
  • Transaction — rollback, WriteConflict พร้อม retry label, อายุ 60 วินาที และการลืม { session } ที่ทำให้การหักเงิน commit ไปเงียบ ๆ
  • Concern — write concern เริ่มต้นคือ w: "majority" อยู่แล้ว; การเขียน w: 1 ที่ primary ที่ถูก partition acknowledge ไปแล้วถูก rollback; timeout ของ w: 3 ยังคงนำการเขียนไปใช้
  • Change stream — Node driver เปิดแบบ lazy และพลาด insert ที่ทำทันทีหลัง watch(); resume token จริงยาว 188 ตัวอักษร hex

หนึ่ง document คือหน่วยของ atomicity และไม่มีค่าใช้จ่าย อะไรที่ใหญ่กว่านั้นคือลำดับของขั้นตอน atomic ที่คุณต้องรวมเป็น document เดียว, guard ใน filter หรือห่อด้วย transaction concern คือสองปุ่มอิสระซ้อนทับอยู่: write concern คือสิ่งที่ ผู้เขียน ถูกบอก, read concern คือสิ่งที่ ผู้อ่าน เห็น

ตัวเลือกประโยชน์ต้นทุน
ออกแบบ document ให้ single-document atomicity ครอบคลุมความต้องการatomicity ฟรี ไม่มี session หรือ commit latency ต่ำที่สุด (ราวครึ่งหนึ่งของเวลา transaction ในการรันที่วัด)ต้องคิด schema ล่วงหน้า; ไม่เหมาะกับข้อมูลที่ต้องเป็น entity อิสระจริง ๆ
Multi-document transaction (ACID เต็ม)รับประกันความถูกต้องข้าม document และ collectionต้องใช้ replica set, retry เมื่อ WriteConflict, ขีดจำกัด 60 วินาที
Write concern w: "majority" (ค่าเริ่มต้น)การเขียนที่ acknowledge แล้วรอด failoverรอ replication; timeout ถ้าเข้าถึง majority ไม่ได้
Read concern majorityไม่อ่านข้อมูลที่อาจถูก rollbackตามหลัง local และการเขียน w: 1 ของคุณเอง
  • “คว้า transaction ทุกครั้งที่แตะมากกว่าหนึ่ง document” — ถามก่อนว่าข้อมูลที่เปลี่ยนพร้อมกันอยู่ด้วยกันได้ไหม; การเขียน document เดียวถูกที่สุดในทุกการวัด
  • “write concern กับ read concern คือปุ่มเดียวกัน” — ความคงทนสำหรับผู้เขียนเทียบกับการมองเห็นสำหรับผู้อ่าน; อิสระต่อกัน
  • “ตั้ง concern แรงสุดทุกที่” — ค่าเริ่มต้นเป็น majority อยู่แล้ว; การตัดสินใจที่ตั้งใจและเสี่ยงคือการลดมัน
  • “การเขียนที่ acknowledge แล้วปลอดภัย” — เฉพาะเมื่อ concern ครอบคลุม majority; acknowledgement ของ w: 1 ถูก rollback หลัง partition
หน่วยของ atomicity ใน MongoDB โดยค่าเริ่มต้นคืออะไร?
เมื่อไหร่ควรใช้ multi-document transaction?
write concern ควบคุมอะไร?
คุณเรียก session.withTransaction บน mongod แบบ standalone ที่สตาร์ทโดยไม่มี --replSet เกิดอะไรขึ้น?
write concern เริ่มต้นแบบแฝงบน MongoDB 8 สำหรับเซตสามโหนดปกติคืออะไร?