นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล

บันทึก. แปล: Jaana Dogan เป็นวิศวกรที่มีประสบการณ์ของ Google ซึ่งปัจจุบันทำงานเกี่ยวกับความสามารถในการสังเกตบริการการผลิตของบริษัทที่เขียนด้วยภาษา Go ในบทความนี้ ซึ่งได้รับความนิยมอย่างมากในหมู่ผู้ชมที่พูดภาษาอังกฤษ เธอได้รวบรวมรายละเอียดทางเทคนิคที่สำคัญ 17 จุดเกี่ยวกับ DBMS (และบางครั้งระบบแบบกระจายโดยทั่วไป) ที่เป็นประโยชน์ในการพิจารณาสำหรับนักพัฒนาแอปพลิเคชันขนาดใหญ่/ที่มีความต้องการสูง

นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล

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

  1. คุณโชคดีถ้า 99,999% ของเวลาที่เครือข่ายไม่ก่อให้เกิดปัญหา
  2. กรดหมายถึงสิ่งต่าง ๆ มากมาย
  3. แต่ละฐานข้อมูลมีกลไกของตัวเองเพื่อให้มั่นใจถึงความสอดคล้องและการแยกออกจากกัน
  4. การบล็อกในแง่ดีจะช่วยได้เมื่อเป็นเรื่องยากที่จะรักษาแบบปกติ
  5. ยังมีความผิดปกติอื่นๆ นอกเหนือจากการอ่านที่สกปรกและการสูญหายของข้อมูล
  6. ฐานข้อมูลและผู้ใช้ไม่เห็นด้วยกับแนวทางปฏิบัติเสมอไป
  7. การแบ่งส่วนระดับแอปพลิเคชันสามารถย้ายออกนอกแอปพลิเคชันได้
  8. การเพิ่มอัตโนมัติอาจเป็นอันตรายได้
  9. ข้อมูลเก่าอาจมีประโยชน์และไม่จำเป็นต้องล็อก
  10. การบิดเบือนเป็นเรื่องปกติสำหรับแหล่งที่มาของเวลาใดๆ
  11. ความล่าช้ามีหลายความหมาย
  12. ข้อกำหนดด้านประสิทธิภาพควรได้รับการประเมินสำหรับธุรกรรมเฉพาะ
  13. ธุรกรรมที่ซ้อนกันอาจเป็นอันตรายได้
  14. ธุรกรรมไม่ควรเชื่อมโยงกับสถานะแอปพลิเคชัน
  15. นักวางแผนแบบสอบถามสามารถบอกคุณได้มากมายเกี่ยวกับฐานข้อมูล
  16. การโยกย้ายออนไลน์เป็นเรื่องยาก แต่เป็นไปได้
  17. การเพิ่มขึ้นอย่างมีนัยสำคัญในฐานข้อมูลนำมาซึ่งความคาดเดาไม่ได้ที่เพิ่มขึ้น

ฉันขอขอบคุณ Emmanuel Odeke, Rein Henrichs และคนอื่นๆ สำหรับความคิดเห็นเกี่ยวกับบทความเวอร์ชันก่อนหน้า

คุณโชคดีถ้า 99,999% ของเวลาที่เครือข่ายไม่ก่อให้เกิดปัญหา

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

ด้วยอัตราความพร้อมใช้งาน 99,999% สำหรับ Spanner (ฐานข้อมูลที่กระจายทั่วโลกของ Google) Google อ้างว่ามีเพียง ลด 7,6% ปัญหาเกี่ยวข้องกับเครือข่าย ในเวลาเดียวกัน บริษัทเรียกเครือข่ายพิเศษของตนว่า “เสาหลัก” ของความพร้อมใช้งานสูง ศึกษา ไบลิสและคิงส์เบอรีดำเนินการในปี 2014 ท้าทายหนึ่งใน “ความเข้าใจผิดเกี่ยวกับการคำนวณแบบกระจาย" ซึ่ง Peter Deutsch ได้กำหนดขึ้นในปี 1994 เครือข่ายเชื่อถือได้จริงหรือ?

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

เมื่อพิจารณาจากสิ่งที่ผู้เล่นรายใหญ่รายงานเกี่ยวกับระบบของพวกเขา ก็ปลอดภัยที่จะบอกว่าคุณโชคดีหากปัญหาเครือข่ายเป็นสาเหตุของปัญหาการหยุดทำงานที่อาจเกิดขึ้นเพียงเล็กน้อยเท่านั้น การสื่อสารบนเครือข่ายยังคงประสบปัญหาเรื่องเดิมๆ เช่น ความล้มเหลวของฮาร์ดแวร์ การเปลี่ยนแปลงโทโพโลยี การเปลี่ยนแปลงการกำหนดค่าผู้ดูแลระบบ และไฟฟ้าดับ เมื่อเร็วๆ นี้ ฉันรู้สึกประหลาดใจที่ทราบว่ามีการเพิ่มรายการปัญหาที่อาจเกิดขึ้น ฉลามกัด (ใช่คุณได้ยินถูกต้อง)

กรดหมายถึงสิ่งต่างๆ มากมาย

ACID ย่อมาจาก Atomicity, Consistency, Isolation, Reliability คุณสมบัติของธุรกรรมเหล่านี้มีจุดประสงค์เพื่อให้แน่ใจว่ามีความถูกต้องในกรณีที่เกิดความล้มเหลว ข้อผิดพลาด ความล้มเหลวของฮาร์ดแวร์ ฯลฯ หากไม่มี ACID หรือแผนการที่คล้ายกัน นักพัฒนาแอปพลิเคชันอาจเป็นเรื่องยากที่จะแยกแยะระหว่างสิ่งที่พวกเขารับผิดชอบกับสิ่งที่ฐานข้อมูลรับผิดชอบ ฐานข้อมูลธุรกรรมเชิงสัมพันธ์ส่วนใหญ่พยายามที่จะปฏิบัติตามข้อกำหนดของ ACID แต่แนวทางใหม่ๆ เช่น NoSQL ได้ก่อให้เกิดฐานข้อมูลจำนวนมากที่ไม่มีธุรกรรมของ ACID เนื่องจากมีค่าใช้จ่ายสูงในการใช้งาน

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

ไม่ใช่ทุก DBMS ที่จะเป็นไปตามมาตรฐาน ACID; ในขณะเดียวกัน การใช้งานฐานข้อมูลที่รองรับ ACID จะเข้าใจชุดข้อกำหนดที่แตกต่างกัน สาเหตุหนึ่งที่ทำให้การนำ ACID ไปใช้มีความไม่สม่ำเสมอก็เนื่องมาจากต้องเสียข้อดีหลายอย่างในการนำข้อกำหนด ACID ไปใช้ ผู้สร้างอาจนำเสนอฐานข้อมูลของตนว่าเป็นไปตามข้อกำหนดของ ACID แต่การตีความกรณี Edge อาจแตกต่างกันอย่างมาก เช่นเดียวกับกลไกในการจัดการกับเหตุการณ์ที่ "ไม่น่าเป็นไปได้" อย่างน้อยที่สุด นักพัฒนาสามารถเข้าใจในระดับสูงเกี่ยวกับความซับซ้อนของการใช้งานพื้นฐาน เพื่อทำความเข้าใจพฤติกรรมพิเศษและข้อดีข้อเสียของการออกแบบอย่างเหมาะสม

การถกเถียงกันว่า MongoDB ปฏิบัติตามข้อกำหนด ACID ยังคงดำเนินต่อไปแม้ว่าจะเผยแพร่เวอร์ชัน 4 แล้วก็ตาม MongoDB ไม่ได้รับการสนับสนุนมาเป็นเวลานาน การบันทึกแม้ว่าโดยค่าเริ่มต้นข้อมูลจะถูกส่งไปยังดิสก์ไม่เกินหนึ่งครั้งทุกๆ 60 วินาที ลองนึกภาพสถานการณ์ต่อไปนี้: แอปพลิเคชันโพสต์การเขียนสองครั้ง (w1 และ w2) MongoDB จัดเก็บ w1 ได้สำเร็จ แต่ w2 สูญหายเนื่องจากฮาร์ดแวร์ขัดข้อง

นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล
แผนภาพแสดงสถานการณ์ MongoDB ขัดข้องก่อนที่จะสามารถเขียนข้อมูลลงดิสก์ได้

การคอมมิตกับดิสก์เป็นกระบวนการที่มีราคาแพง ด้วยการหลีกเลี่ยงการคอมมิตบ่อยครั้ง นักพัฒนาจึงปรับปรุงประสิทธิภาพการบันทึกโดยสูญเสียความน่าเชื่อถือ ปัจจุบัน MongoDB รองรับการบันทึก แต่การเขียนที่สกปรกยังคงส่งผลกระทบต่อความสมบูรณ์ของข้อมูล เนื่องจากบันทึกจะถูกบันทึกทุกๆ 100 มิลลิวินาทีตามค่าเริ่มต้น นั่นคือสถานการณ์ที่คล้ายกันยังคงเป็นไปได้สำหรับบันทึกและการเปลี่ยนแปลงที่นำเสนอ แม้ว่าความเสี่ยงจะต่ำกว่ามากก็ตาม

แต่ละฐานข้อมูลมีความสอดคล้องและกลไกการแยกของตัวเอง

จากข้อกำหนดของ ACID ความสม่ำเสมอและการแยกส่วนมีจำนวนการใช้งานที่แตกต่างกันมากที่สุด เนื่องจากช่วงของข้อด้อยกว้างกว่า ต้องบอกว่าความสม่ำเสมอและการแยกเป็นฟังก์ชันที่ค่อนข้างแพง พวกเขาต้องการการประสานงานและเพิ่มการแข่งขันเพื่อความสอดคล้องของข้อมูล ความซับซ้อนของปัญหาจะเพิ่มขึ้นอย่างมากเมื่อจำเป็นต้องปรับขนาดฐานข้อมูลในแนวนอนทั่วทั้งศูนย์ข้อมูลหลายแห่ง (โดยเฉพาะอย่างยิ่งหากตั้งอยู่ในภูมิภาคทางภูมิศาสตร์ที่แตกต่างกัน) การบรรลุความสม่ำเสมอในระดับสูงเป็นเรื่องยากมาก เนื่องจากจะลดความพร้อมใช้งานและเพิ่มการแบ่งส่วนเครือข่ายด้วย สำหรับคำอธิบายทั่วไปเพิ่มเติมเกี่ยวกับปรากฏการณ์นี้ ฉันขอแนะนำให้คุณดูที่ ทฤษฎีบทแคป. นอกจากนี้ ยังเป็นที่น่าสังเกตว่าแอปพลิเคชันสามารถจัดการกับความไม่สอดคล้องกันจำนวนเล็กน้อยได้ และโปรแกรมเมอร์สามารถเข้าใจความแตกต่างของปัญหาได้ดีพอที่จะใช้ตรรกะเพิ่มเติมในแอปพลิเคชันเพื่อจัดการกับความไม่สอดคล้องกันโดยไม่ต้องอาศัยฐานข้อมูลมากนักในการจัดการ

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

นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล
การทบทวนโมเดลการทำงานพร้อมกันที่มีอยู่และความสัมพันธ์ระหว่างโมเดลเหล่านั้น

มาตรฐาน SQL กำหนดระดับการแยกเพียงสี่ระดับ แม้ว่าในทางทฤษฎีและการปฏิบัติยังมีระดับอื่นอีกมากมาย Jepson.io นำเสนอภาพรวมที่ยอดเยี่ยมของโมเดลการทำงานพร้อมกันที่มีอยู่ ตัวอย่างเช่น Google Spanner รับประกันความสามารถในการทำให้เป็นอนุกรมภายนอกด้วยการซิงโครไนซ์นาฬิกา และถึงแม้ว่านี่จะเป็นเลเยอร์การแยกที่เข้มงวดกว่า แต่ก็ไม่ได้กำหนดไว้ในเลเยอร์การแยกมาตรฐาน

มาตรฐาน SQL กล่าวถึงระดับการแยกต่อไปนี้:

  • serializable (เข้มงวดที่สุดและมีราคาแพง): การดำเนินการแบบอนุกรมมีผลเช่นเดียวกับการดำเนินการธุรกรรมตามลำดับบางรายการ การดำเนินการตามลำดับหมายความว่าแต่ละธุรกรรมที่ตามมาจะเริ่มต้นหลังจากธุรกรรมก่อนหน้าเสร็จสมบูรณ์เท่านั้น ควรสังเกตว่าระดับ serializable มักนำไปใช้เป็นสิ่งที่เรียกว่าการแยกสแน็ปช็อต (เช่นใน Oracle) เนื่องจากความแตกต่างในการตีความ แม้ว่าการแยกสแน็ปช็อตนั้นไม่ได้แสดงในมาตรฐาน SQL ก็ตาม
  • อ่านซ้ำได้: บันทึกที่ไม่มีข้อผูกมัดในธุรกรรมปัจจุบันจะพร้อมใช้งานสำหรับธุรกรรมปัจจุบัน แต่การเปลี่ยนแปลงที่ทำโดยธุรกรรมอื่น ๆ (เช่นแถวใหม่) ไม่สามารถมองเห็นได้.
  • อ่านมุ่งมั่น: ไม่มีข้อมูลที่ไม่มีข้อผูกมัดสำหรับการทำธุรกรรม ในกรณีนี้ ธุรกรรมสามารถดูได้เฉพาะข้อมูลที่คอมมิต และอาจเกิดการอ่าน Phantom หากธุรกรรมแทรกและยืนยันแถวใหม่ ธุรกรรมปัจจุบันจะสามารถเห็นได้เมื่อมีการสอบถาม
  • อ่านแบบไม่ผูกมัด (ระดับที่เข้มงวดน้อยที่สุดและมีราคาแพง): อนุญาตให้อ่านแบบสกปรกได้ ธุรกรรมสามารถเห็นการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดที่ทำโดยธุรกรรมอื่น ๆ ในทางปฏิบัติ ระดับนี้อาจมีประโยชน์สำหรับการประมาณค่าคร่าวๆ เช่น การสืบค้น COUNT(*) บนโต๊ะ.

Уровень serializable ลดความเสี่ยงของการแข่งขันของข้อมูลให้เหลือน้อยที่สุด ในขณะที่มีค่าใช้จ่ายสูงที่สุดในการติดตั้งและส่งผลให้มีภาระการแข่งขันสูงสุดในระบบ ระดับการแยกอื่นๆ นั้นง่ายต่อการนำไปใช้ แต่เพิ่มโอกาสที่ข้อมูลจะแย่งชิงกัน DBMS บางตัวอนุญาตให้คุณตั้งค่าระดับการแยกแบบกำหนดเองได้ ส่วน DBMS บางตัวมีการตั้งค่าที่ชัดเจนและรองรับเพียงบางระดับเท่านั้น

การสนับสนุนระดับการแยกมักจะได้รับการโฆษณาใน DBMS ที่กำหนด แต่มีเพียงการศึกษาพฤติกรรมของมันอย่างรอบคอบเท่านั้นที่สามารถเปิดเผยสิ่งที่เกิดขึ้นจริงได้

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

Martin Kleppmann ในโครงการของเขา อาศรม เปรียบเทียบระดับการแยกที่แตกต่างกัน พูดคุยเกี่ยวกับความผิดปกติที่เกิดขึ้นพร้อมกัน และฐานข้อมูลสามารถปฏิบัติตามระดับการแยกเฉพาะได้หรือไม่ การวิจัยของ Kleppmann แสดงให้เห็นว่านักพัฒนาฐานข้อมูลคิดต่างกันอย่างไรเกี่ยวกับระดับการแยกตัว

การบล็อกในแง่ดีจะช่วยได้เมื่อเป็นเรื่องยากที่จะรักษาแบบปกติ

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

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

UPDATE products
SET name = 'Telegraph receiver', version = 2
WHERE id = 1 AND version = 1

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

ยังมีความผิดปกติอื่นๆ นอกเหนือจากการอ่านที่สกปรกและการสูญหายของข้อมูล

เมื่อพูดถึงความสอดคล้องของข้อมูล จุดเน้นอยู่ที่ศักยภาพของสภาพการแข่งขันที่อาจนำไปสู่การอ่านที่สกปรกและการสูญเสียข้อมูล อย่างไรก็ตาม ความผิดปกติของข้อมูลไม่ได้หยุดอยู่แค่นั้น

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

ตัวอย่างเช่น ลองพิจารณาแอปพลิเคชันการตรวจสอบที่ต้องมีโอเปอเรเตอร์หนึ่งรายคอยโทรตลอดเวลา:

BEGIN tx1;                      BEGIN tx2;
SELECT COUNT(*)
FROM operators
WHERE oncall = true;
0                               SELECT COUNT(*)
                                FROM operators
                                WHERE oncall = TRUE;
                                0
UPDATE operators                UPDATE operators
SET oncall = TRUE               SET oncall = TRUE
WHERE userId = 4;               WHERE userId = 2;
COMMIT tx1;                     COMMIT tx2;

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

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

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

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

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

เมื่อมองแวบแรกในโปรแกรมด้านล่าง T1 และ T2 จะถูกเรียกตามลำดับ แต่ถ้าฟังก์ชันเหล่านี้ไม่บล็อกและส่งคืนผลลัพธ์ในรูปแบบทันที คำมั่นสัญญาจากนั้นลำดับการโทรจะถูกกำหนดโดยช่วงเวลาที่เข้าสู่ฐานข้อมูล:

result1 = T1() // ผลลัพธ์ที่แท้จริงคือคำมั่นสัญญา
ผลลัพธ์2 = T2()

หากจำเป็นต้องมีอะตอมมิกซิตี (นั่นคือ การดำเนินการทั้งหมดจะต้องเสร็จสมบูรณ์หรือยกเลิก) และเรื่องลำดับ การดำเนินการ T1 และ T2 จะต้องดำเนินการภายในธุรกรรมเดียว

การแบ่งส่วนระดับแอปพลิเคชันสามารถย้ายออกนอกแอปพลิเคชันได้

Sharding เป็นวิธีการแบ่งพาร์ติชันฐานข้อมูลในแนวนอน ฐานข้อมูลบางแห่งสามารถแบ่งข้อมูลในแนวนอนได้โดยอัตโนมัติ ในขณะที่ฐานข้อมูลอื่นๆ ไม่สามารถทำได้หรือทำได้ไม่ดีนัก เมื่อสถาปนิก/นักพัฒนาข้อมูลสามารถคาดการณ์ได้อย่างชัดเจนว่าข้อมูลจะเข้าถึงได้อย่างไร พวกเขาสามารถสร้างพาร์ติชันแนวนอนในพื้นที่ผู้ใช้ แทนที่จะมอบหมายงานนี้ให้กับฐานข้อมูล กระบวนการนี้เรียกว่า "การแบ่งส่วนระดับแอปพลิเคชัน" (การแบ่งส่วนระดับแอปพลิเคชัน).

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

นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล
ตัวอย่างของสถาปัตยกรรมที่แอปพลิเคชันเซิร์ฟเวอร์แยกออกจากบริการการแบ่งส่วน

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

การเพิ่มอัตโนมัติอาจเป็นอันตรายได้

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

  • ในฐานข้อมูลแบบกระจาย การเพิ่มค่าอัตโนมัติถือเป็นปัญหาร้ายแรง ในการสร้าง ID จำเป็นต้องมีการล็อคส่วนกลาง แต่คุณสามารถสร้าง UUID แทนได้ โดยไม่จำเป็นต้องมีการโต้ตอบระหว่างโหนดฐานข้อมูลที่แตกต่างกัน การเพิ่มขึ้นอัตโนมัติด้วยการล็อคอาจทำให้เกิดการโต้แย้งและลดประสิทธิภาพของเม็ดมีดในสถานการณ์ที่มีการกระจายตัวลงอย่างมาก DBMS บางตัว (เช่น MySQL) อาจต้องมีการกำหนดค่าพิเศษและให้ความเอาใจใส่อย่างระมัดระวังมากขึ้นเพื่อจัดระเบียบการจำลองแบบต้นแบบ-ต้นแบบอย่างเหมาะสม และทำให้เกิดข้อผิดพลาดได้ง่ายเมื่อกำหนดค่า ซึ่งจะทำให้การบันทึกล้มเหลว
  • ฐานข้อมูลบางแห่งมีอัลกอริธึมการแบ่งพาร์ติชันตามคีย์หลัก ID ที่ติดต่อกันสามารถนำไปสู่ฮอตสปอตที่ไม่สามารถคาดเดาได้ และเพิ่มภาระงานบนพาร์ติชั่นบางพาร์ติชั่น ในขณะที่บางพาร์ติชั่นยังคงไม่ได้ใช้งาน
  • คีย์หลักคือวิธีที่เร็วที่สุดในการเข้าถึงแถวในฐานข้อมูล ด้วยวิธีที่ดีกว่าในการระบุเรกคอร์ด รหัสตามลำดับสามารถเปลี่ยนคอลัมน์ที่สำคัญที่สุดในตารางให้เป็นคอลัมน์ที่ไม่มีประโยชน์ซึ่งเต็มไปด้วยค่าที่ไม่มีความหมาย ดังนั้น ทุกครั้งที่เป็นไปได้ โปรดเลือกคีย์หลักที่เป็นธรรมชาติและไม่เหมือนใครทั่วโลก (เช่น ชื่อผู้ใช้)

ก่อนที่จะตัดสินใจเลือกแนวทาง ให้พิจารณาผลกระทบของ ID และ UUID ที่เพิ่มขึ้นอัตโนมัติต่อการจัดทำดัชนี การแบ่งพาร์ติชัน และการแบ่งส่วน

ข้อมูลเก่าอาจมีประโยชน์และไม่จำเป็นต้องล็อก

Multiversion Concurrency Control (MVCC) ใช้ข้อกำหนดด้านความสอดคล้องหลายประการตามที่กล่าวไว้ข้างต้นโดยย่อ ฐานข้อมูลบางแห่ง (เช่น Postgres, Spanner) ใช้ MVCC เพื่อ "ฟีด" ธุรกรรมด้วยสแน็ปช็อต ซึ่งเป็นฐานข้อมูลเวอร์ชันเก่า ธุรกรรมสแนปชอตยังสามารถทำให้เป็นอนุกรมได้เพื่อให้มั่นใจถึงความสอดคล้องกัน เมื่ออ่านจากสแน็ปช็อตเก่า ข้อมูลที่ล้าสมัยจะถูกอ่าน

การอ่านข้อมูลเก่าเล็กน้อยอาจมีประโยชน์ เช่น เมื่อสร้างการวิเคราะห์จากข้อมูลหรือคำนวณค่ารวมโดยประมาณ

ข้อได้เปรียบข้อแรกของการทำงานกับข้อมูลเดิมคือเวลาแฝงต่ำ (โดยเฉพาะอย่างยิ่งหากฐานข้อมูลมีการกระจายไปตามภูมิศาสตร์ต่างๆ) ประการที่สองคือธุรกรรมแบบอ่านอย่างเดียวไม่มีการล็อค นี่เป็นข้อได้เปรียบที่สำคัญสำหรับแอปพลิเคชันที่อ่านข้อมูลจำนวนมาก ตราบใดที่แอปพลิเคชันเหล่านั้นสามารถจัดการข้อมูลเก่าได้

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

DBMS จะกำจัดเวอร์ชันเก่าออกโดยอัตโนมัติ และในบางกรณี ช่วยให้คุณสามารถดำเนินการนี้ได้ตามคำขอ ตัวอย่างเช่น Postgres อนุญาตให้ผู้ใช้ทำ VACUUM เมื่อมีการร้องขอและดำเนินการนี้โดยอัตโนมัติเป็นระยะ ๆ Spanner เรียกใช้ตัวรวบรวมขยะเพื่อกำจัดสแนปชอตที่เก่ากว่าหนึ่งชั่วโมง

แหล่งที่มาของเวลาใดๆ ก็ตามอาจมีการบิดเบือนได้

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

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

นาฬิกาอะตอมและนาฬิกาที่มี GPS เหมาะกว่าในการระบุเวลาปัจจุบัน แต่มีราคาแพงและต้องมีการตั้งค่าที่ซับซ้อน ดังนั้นจึงไม่สามารถติดตั้งกับรถยนต์ทุกคันได้ ด้วยเหตุนี้ ศูนย์ข้อมูลจึงใช้วิธีการแบบแบ่งระดับ นาฬิกาอะตอมและ/หรือ GPS จะแสดงเวลาที่แน่นอน หลังจากนั้นจึงออกอากาศไปยังเครื่องอื่นผ่านเซิร์ฟเวอร์รอง ซึ่งหมายความว่าแต่ละเครื่องจะได้รับออฟเซ็ตที่แน่นอนจากเวลาที่แน่นอน

สถานการณ์เลวร้ายลงเนื่องจากความจริงที่ว่าแอปพลิเคชันและฐานข้อมูลมักจะอยู่ในเครื่องที่แตกต่างกัน (หากไม่ได้อยู่ในศูนย์ข้อมูลที่แตกต่างกัน) ดังนั้นเวลาจะแตกต่างกันไม่เพียงแต่ในโหนด DB ที่กระจายไปตามเครื่องต่างๆ เท่านั้น มันจะแตกต่างออกไปบนเซิร์ฟเวอร์แอปพลิเคชันด้วย

Google TrueTime ใช้แนวทางที่แตกต่างไปจากเดิมอย่างสิ้นเชิง คนส่วนใหญ่เชื่อว่าความก้าวหน้าของ Google ในทิศทางนี้อธิบายได้จากการเปลี่ยนไปใช้นาฬิกาอะตอมและนาฬิกา GPS ซ้ำๆ แต่นี่เป็นเพียงส่วนหนึ่งของภาพรวมเท่านั้น นี่คือวิธีการทำงานของ TrueTime:

  • TrueTime ใช้แหล่งข้อมูลสองแหล่งที่แตกต่างกัน ได้แก่ GPS และนาฬิกาอะตอม นาฬิกาเหล่านี้มีโหมดความล้มเหลวที่ไม่สัมพันธ์กัน [ดูหน้า 5 สำหรับรายละเอียด ที่นี่ - ประมาณ แปล.)ดังนั้นการใช้งานร่วมกันจึงเพิ่มความน่าเชื่อถือ
  • TrueTime มี API ที่ผิดปกติ โดยจะส่งกลับเวลาเป็นช่วงเวลาโดยมีข้อผิดพลาดในการวัดและความไม่แน่นอนอยู่ภายใน ช่วงเวลาที่แท้จริงอยู่ระหว่างขอบเขตบนและล่างของช่วงเวลา Spanner ซึ่งเป็นฐานข้อมูลแบบกระจายของ Google เพียงรอจนกว่าจะปลอดภัยที่จะบอกว่าเวลาปัจจุบันอยู่นอกช่วง วิธีนี้จะทำให้เกิดเวลาแฝงในระบบ โดยเฉพาะอย่างยิ่งหากความไม่แน่นอนของต้นแบบอยู่ในระดับสูง แต่รับประกันความถูกต้องแม้ในสถานการณ์ที่กระจายไปทั่วโลก

นักพัฒนาจำนวนมากควรรู้สิ่งนี้เกี่ยวกับฐานข้อมูล
ส่วนประกอบของ Spanner จะใช้ TrueTime โดยที่ TT.now() ส่งคืนช่วงเวลา ดังนั้น Spanner จึงเข้าสู่โหมดสลีปจนถึงจุดที่มั่นใจได้ว่าเวลาปัจจุบันผ่านจุดหนึ่งไปแล้ว

ความแม่นยำที่ลดลงในการกำหนดเวลาปัจจุบันหมายถึงการเพิ่มระยะเวลาการทำงานของ Spanner และประสิทธิภาพที่ลดลง ด้วยเหตุนี้การรักษาความแม่นยำสูงสุดที่เป็นไปได้จึงเป็นสิ่งสำคัญ แม้ว่าจะเป็นไปไม่ได้ที่จะได้นาฬิกาที่มีความแม่นยำครบถ้วนสมบูรณ์ก็ตาม

ความล่าช้ามีหลายความหมาย

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

ข้อกำหนดด้านประสิทธิภาพควรได้รับการประเมินสำหรับธุรกรรมเฉพาะ

บางครั้งคุณลักษณะด้านประสิทธิภาพของ DBMS และข้อจำกัดต่างๆ จะถูกระบุในแง่ของปริมาณงานในการเขียน/อ่านและเวลาแฝง ข้อมูลนี้ให้ภาพรวมทั่วไปของพารามิเตอร์ระบบที่สำคัญ แต่เมื่อประเมินประสิทธิภาพของ DBMS ใหม่ วิธีการที่ครอบคลุมมากขึ้นคือการประเมินการดำเนินการที่สำคัญแยกกัน (สำหรับการสืบค้นแต่ละรายการและ/หรือธุรกรรม) ตัวอย่าง:

  • เขียนปริมาณงานและเวลาแฝงเมื่อแทรกแถวใหม่ลงในตาราง X (ที่มี 50 ล้านแถว) โดยมีข้อจำกัดที่ระบุและช่องว่างภายในแถวในตารางที่เกี่ยวข้อง
  • ความล่าช้าในการแสดงเพื่อนของเพื่อนของผู้ใช้บางรายเมื่อจำนวนเพื่อนโดยเฉลี่ยคือ 500
  • เวลาแฝงในการดึงข้อมูล 100 อันดับแรกจากประวัติของผู้ใช้เมื่อผู้ใช้ติดตามผู้ใช้อื่น 500 รายด้วย X รายการต่อชั่วโมง

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

ระวังคาร์ดินัลลิตี้สูงเมื่อรวบรวมเมทริกสำหรับการดำเนินการแต่ละรายการ ใช้บันทึก การรวบรวมเหตุการณ์ หรือการติดตามแบบกระจายเพื่อรับข้อมูลการแก้ไขข้อบกพร่องที่มีประสิทธิภาพสูง ในบทความ "ต้องการดีบัก Latency หรือไม่?» คุณสามารถทำความคุ้นเคยกับวิธีการดีบักการหน่วงเวลาได้

ธุรกรรมที่ซ้อนกันอาจเป็นอันตรายได้

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

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

การห่อหุ้มธุรกรรมในเลเยอร์ที่แตกต่างกันสามารถนำไปสู่ธุรกรรมที่ซ้อนกันโดยไม่คาดคิด และจากมุมมองของการอ่านโค้ด อาจทำให้เข้าใจความตั้งใจของผู้เขียนได้ยาก ลองดูที่โปรแกรมต่อไปนี้:

with newTransaction():
   Accounts.create("609-543-222")
   with newTransaction():
       Accounts.create("775-988-322")
       throw Rollback();

ผลลัพธ์ของโค้ดข้างต้นจะเป็นอย่างไร? มันจะย้อนกลับทั้งสองธุรกรรมหรือเพียงธุรกรรมภายในหรือไม่? จะเกิดอะไรขึ้นถ้าเราอาศัยไลบรารีหลายชั้นที่ห่อหุ้มการสร้างธุรกรรมให้เรา เราจะสามารถระบุและปรับปรุงกรณีดังกล่าวได้หรือไม่?

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

function newAccount(id string) {
  with newTransaction():
      Accounts.create(id)
}

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

function newAccount(id string) {
   Accounts.create(id)
}
// In main application:
with newTransaction():
   // Read some data from database for configuration.
   // Generate an ID from the ID service.
   Accounts.create(id)
   Uploads.create(id) // create upload queue for the user.

ธุรกรรมไม่ควรเชื่อมโยงกับสถานะแอปพลิเคชัน

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

var seq int64
with newTransaction():
    newSeq := atomic.Increment(&seq)
    Entries.query(newSeq)
    // Other operations...

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

นักวางแผนแบบสอบถามสามารถบอกคุณได้มากมายเกี่ยวกับฐานข้อมูล

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

SELECT * FROM articles where author = "rakyll" order by title;

สามารถรับผลลัพธ์ได้สองวิธี:

  • สแกนเต็มโต๊ะ: คุณสามารถดูแต่ละรายการในตารางและส่งกลับบทความที่มีชื่อผู้เขียนตรงกัน จากนั้นจึงเรียงลำดับได้
  • การสแกนดัชนี: คุณสามารถใช้ดัชนีเพื่อค้นหา ID ที่ตรงกัน รับแถวเหล่านั้น จากนั้นเรียงลำดับได้

งานของผู้วางแผนแบบสอบถามคือการพิจารณาว่ากลยุทธ์ใดดีที่สุด การพิจารณาว่าเครื่องมือวางแผนคิวรีมีความสามารถในการคาดการณ์ที่จำกัดเท่านั้น สิ่งนี้สามารถนำไปสู่การตัดสินใจที่ไม่ดี DBA หรือนักพัฒนาสามารถใช้เพื่อวินิจฉัยและปรับแต่งการสืบค้นที่มีประสิทธิภาพต่ำได้ DBMS เวอร์ชันใหม่สามารถกำหนดค่าตัววางแผนคิวรีได้ และการวินิจฉัยตนเองสามารถช่วยได้เมื่ออัปเดตฐานข้อมูล หากเวอร์ชันใหม่ทำให้เกิดปัญหาด้านประสิทธิภาพ บันทึกการสืบค้นที่ช้า รายงานปัญหาเวลาในการตอบสนอง หรือสถิติเวลาดำเนินการสามารถช่วยระบุการสืบค้นที่ต้องการการปรับให้เหมาะสมได้

ตัวชี้วัดบางตัวที่นำเสนอโดยเครื่องมือวางแผนแบบสอบถามอาจมีสัญญาณรบกวน (โดยเฉพาะอย่างยิ่งเมื่อประมาณค่าเวลาแฝงหรือเวลา CPU) นอกจากนี้ตัวกำหนดเวลาที่ดีคือเครื่องมือสำหรับการติดตามและติดตามเส้นทางการดำเนินการ ช่วยให้คุณสามารถวินิจฉัยปัญหาดังกล่าวได้ (อนิจจาไม่ใช่ว่า DBMS ทั้งหมดจะมีเครื่องมือดังกล่าว)

การโยกย้ายออนไลน์เป็นเรื่องยากแต่เป็นไปได้

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

มีโมเดลการย้ายข้อมูลออนไลน์ที่แตกต่างกัน นี่คือหนึ่งในนั้น:

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

หากต้องการข้อมูลเพิ่มเติมแนะนำให้ติดต่อ статьеซึ่งให้รายละเอียดเกี่ยวกับกลยุทธ์การย้ายข้อมูลของ Stripe ตามแบบจำลองนี้

การเพิ่มขึ้นอย่างมีนัยสำคัญในฐานข้อมูลนำมาซึ่งความคาดเดาไม่ได้ที่เพิ่มขึ้น

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

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

...

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

PS

อ่านเพิ่มเติมในบล็อกของเรา:

ที่มา: will.com

เพิ่มความคิดเห็น