ความสอดคล้องของข้อมูลใน 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 — ทำไมการเปลี่ยนแปลงใด ๆ ในหนึ่ง 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
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”หนึ่ง 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 ของคุณเอง |
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “คว้า transaction ทุกครั้งที่แตะมากกว่าหนึ่ง document” — ถามก่อนว่าข้อมูลที่เปลี่ยนพร้อมกันอยู่ด้วยกันได้ไหม; การเขียน document เดียวถูกที่สุดในทุกการวัด
- “write concern กับ read concern คือปุ่มเดียวกัน” — ความคงทนสำหรับผู้เขียนเทียบกับการมองเห็นสำหรับผู้อ่าน; อิสระต่อกัน
- “ตั้ง concern แรงสุดทุกที่” — ค่าเริ่มต้นเป็น majority อยู่แล้ว; การตัดสินใจที่ตั้งใจและเสี่ยงคือการลดมัน
- “การเขียนที่ acknowledge แล้วปลอดภัย” — เฉพาะเมื่อ concern ครอบคลุม majority; acknowledgement ของ
w: 1ถูก rollback หลัง partition