ที่เก็บข้อมูลที่ทนทานและ API ไฟล์ Linux

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

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

ที่เก็บข้อมูลที่ทนทานและ API ไฟล์ Linux

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

คุณสมบัติของการใช้ฟังก์ชั่นเขียน ()

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

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

ฟังก์ชัน fsync() และ fdatasync()

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

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

กลไกนี้สามารถนำไปใช้แตกต่างกันในระบบไฟล์ที่แตกต่างกัน ฉันใช้ ติดตาม เพื่อเรียนรู้เกี่ยวกับการดำเนินการของดิสก์ที่ใช้ในระบบไฟล์ ext4 และ XFS ทั้งคู่ออกคำสั่งเขียนตามปกติไปยังดิสก์สำหรับทั้งเนื้อหาของไฟล์และเจอร์นัลระบบไฟล์ ล้างแคชและออกโดยดำเนินการ FUA (Force Unit Access, การเขียนข้อมูลโดยตรงไปยังดิสก์, ข้ามแคช) เขียนไปยังเจอร์นัล พวกเขาอาจทำเช่นนั้นเพื่อยืนยันข้อเท็จจริงของการทำธุรกรรม ในไดรฟ์ที่ไม่รองรับ FUA จะทำให้แคชล้างข้อมูลสองครั้ง การทดลองของฉันแสดงให้เห็นว่า fdatasync() เร็วขึ้นเล็กน้อย fsync(). คุณประโยชน์ blktrace แสดงว่า fdatasync() มักจะเขียนข้อมูลลงดิสก์น้อยลง (ใน ext4 fsync() เขียน 20 KiB และ fdatasync() - 16 กิโลไบต์). นอกจากนี้ ฉันยังพบว่า XFS นั้นเร็วกว่า ext4 เล็กน้อย และที่นี่ด้วยความช่วยเหลือ blktrace สามารถค้นพบว่า fdatasync() ล้างข้อมูลลงดิสก์น้อยลง (4 KiB ใน XFS)

สถานการณ์ที่ไม่ชัดเจนเมื่อใช้ fsync()

ฉันสามารถคิดถึงสถานการณ์ที่คลุมเครือสามประการเกี่ยวกับ fsync()ที่ข้าพเจ้าได้ประสบมาในทางปฏิบัติ

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

ปัญหาที่สองเกิดขึ้นในปี 2009 จากนั้น หลังจากระบบหยุดทำงาน ผู้ใช้ระบบไฟล์ ext4 ใหม่พบว่าไฟล์ที่สร้างขึ้นใหม่จำนวนมากมีความยาวเป็นศูนย์ แต่สิ่งนี้ไม่ได้เกิดขึ้นกับระบบไฟล์ ext3 รุ่นเก่า ในย่อหน้าที่แล้ว ฉันได้พูดถึงวิธีที่ ext3 ถ่ายโอนข้อมูลมากเกินไปบนดิสก์ ซึ่งทำให้สิ่งต่างๆ ช้าลงอย่างมาก fsync(). เพื่อปรับปรุงสถานการณ์ ext4 จะล้างเฉพาะหน้าที่ "สกปรก" ที่เกี่ยวข้องกับไฟล์เฉพาะ และข้อมูลของไฟล์อื่นยังคงอยู่ในหน่วยความจำเป็นเวลานานกว่า ext3 สิ่งนี้ทำเพื่อปรับปรุงประสิทธิภาพ (โดยค่าเริ่มต้น ข้อมูลจะอยู่ในสถานะนี้เป็นเวลา 30 วินาที คุณสามารถกำหนดค่าได้โดยใช้ Dirty_expire_centisecs; ที่นี่ คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้) ซึ่งหมายความว่าข้อมูลจำนวนมากอาจสูญหายโดยไม่สามารถเรียกคืนได้หลังจากเกิดความผิดพลาด วิธีแก้ไขปัญหานี้คือการใช้ fsync() ในแอปพลิเคชันที่ต้องการให้การจัดเก็บข้อมูลที่เสถียรและปกป้องข้อมูลเหล่านั้นจากผลที่ตามมาจากความล้มเหลวให้ได้มากที่สุด การทำงาน fsync() ทำงานได้อย่างมีประสิทธิภาพด้วย ext4 มากกว่า ext3 ข้อเสียของแนวทางนี้คือการใช้งานเหมือนเมื่อก่อนทำให้การดำเนินการบางอย่างช้าลง เช่น การติดตั้งโปรแกรม ดูรายละเอียดเรื่องนี้ ที่นี่ и ที่นี่.

ปัญหาที่สามเกี่ยวกับ fsync()ถือกำเนิดขึ้นในปี 2018 จากนั้นภายในกรอบของโครงการ PostgreSQL พบว่าถ้าฟังก์ชัน fsync() พบข้อผิดพลาด จะทำเครื่องหมายหน้า "สกปรก" เป็น "สะอาด" เป็นผลให้การโทรต่อไปนี้ fsync() ไม่ทำอะไรกับหน้าดังกล่าว ด้วยเหตุนี้ เพจที่แก้ไขจะถูกจัดเก็บไว้ในหน่วยความจำและไม่เคยเขียนลงดิสก์ นี่เป็นหายนะที่แท้จริงเนื่องจากแอปพลิเคชันจะคิดว่าข้อมูลบางส่วนถูกเขียนลงดิสก์ แต่ในความเป็นจริงแล้วจะไม่เป็นเช่นนั้น ความล้มเหลวดังกล่าว fsync() หายาก แอปพลิเคชันในสถานการณ์ดังกล่าวแทบจะทำอะไรไม่ได้เลยเพื่อต่อสู้กับปัญหา เมื่อสิ่งนี้เกิดขึ้น ทุกวันนี้ PostgreSQL และแอปพลิเคชันอื่นๆ หยุดทำงาน ที่นี่ในบทความ "แอปพลิเคชันสามารถกู้คืนจากความล้มเหลวของ fsync ได้หรือไม่" ปัญหานี้ได้รับการสำรวจโดยละเอียด ขณะนี้ ทางออกที่ดีที่สุดสำหรับปัญหานี้คือการใช้ Direct I/O กับแฟล็ก O_SYNC หรือมีธง O_DSYNC. ด้วยวิธีการนี้ ระบบจะรายงานข้อผิดพลาดที่อาจเกิดขึ้นเมื่อดำเนินการเขียนข้อมูลเฉพาะ แต่วิธีการนี้ต้องการให้แอปพลิเคชันจัดการบัฟเฟอร์เอง อ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ ที่นี่ и ที่นี่.

การเปิดไฟล์โดยใช้แฟล็ก O_SYNC และ O_DSYNC

กลับไปที่การสนทนาเกี่ยวกับกลไกของ Linux ที่ให้การจัดเก็บข้อมูลแบบถาวร กล่าวคือเรากำลังพูดถึงการใช้ธง O_SYNC หรือธง O_DSYNC เมื่อเปิดไฟล์โดยใช้การเรียกระบบ เปิด(). ด้วยวิธีการนี้ การดำเนินการเขียนข้อมูลแต่ละครั้งจะดำเนินการราวกับว่าหลังจากแต่ละคำสั่ง write() ระบบจะได้รับคำสั่งตามลำดับ fsync() и fdatasync(). ใน ข้อมูลจำเพาะของ POSIX สิ่งนี้เรียกว่า "การทำให้สมบูรณ์ของไฟล์ I/O ที่ซิงโครไนซ์" และ "ความสมบูรณ์ของข้อมูล" ข้อได้เปรียบหลักของวิธีนี้คือการเรียกระบบเพียงครั้งเดียวเท่านั้นที่ต้องดำเนินการเพื่อให้แน่ใจว่าข้อมูลมีความสมบูรณ์ ไม่ใช่สองครั้ง (ตัวอย่างเช่น - write() и fdatasync()). ข้อเสียเปรียบหลักของแนวทางนี้คือการดำเนินการเขียนทั้งหมดโดยใช้ตัวอธิบายไฟล์ที่เกี่ยวข้องจะถูกซิงโครไนซ์ ซึ่งอาจจำกัดความสามารถในการจัดโครงสร้างรหัสแอปพลิเคชัน

การใช้ Direct I/O กับแฟล็ก O_DIRECT

ระบบเรียก open() รองรับธง O_DIRECTซึ่งออกแบบมาเพื่อข้ามแคชของระบบปฏิบัติการ ดำเนินการ I / O โต้ตอบโดยตรงกับดิสก์ ในหลายกรณี หมายความว่าคำสั่งเขียนที่ออกโดยโปรแกรมจะถูกแปลโดยตรงเป็นคำสั่งที่มุ่งทำงานกับดิสก์ แต่โดยทั่วไปแล้ว กลไกนี้ใช้แทนฟังก์ชันต่างๆ ไม่ได้ fsync() หรือ fdatasync(). ความจริงก็คือดิสก์สามารถ ความล่าช้าหรือแคช คำสั่งที่เหมาะสมในการเขียนข้อมูล และที่แย่ไปกว่านั้น ในบางกรณี การดำเนินการ I/O ดำเนินการเมื่อใช้แฟล็ก O_DIRECT, ออกอากาศ ในการดำเนินการบัฟเฟอร์แบบดั้งเดิม วิธีที่ง่ายที่สุดในการแก้ปัญหานี้คือการใช้แฟล็กเพื่อเปิดไฟล์ O_DSYNCซึ่งจะหมายความว่าการดำเนินการเขียนแต่ละครั้งจะตามด้วยการเรียก fdatasync().

ปรากฎว่าระบบไฟล์ XFS เพิ่งเพิ่ม "เส้นทางด่วน" สำหรับ O_DIRECT|O_DSYNCบันทึกข้อมูล หากบล็อกถูกเขียนทับโดยใช้ O_DIRECT|O_DSYNCจากนั้น XFS แทนที่จะล้างแคช จะดำเนินการคำสั่งเขียน FUA หากอุปกรณ์รองรับ ฉันยืนยันสิ่งนี้โดยใช้ยูทิลิตี blktrace บนระบบ Linux 5.4/Ubuntu 20.04 วิธีการนี้ควรมีประสิทธิภาพมากกว่า เนื่องจากเขียนจำนวนข้อมูลขั้นต่ำลงในดิสก์และใช้การดำเนินการเพียงครั้งเดียว ไม่ใช่สองรายการ (เขียนและล้างแคช) ฉันพบลิงค์ไปยัง แก้ไข เคอร์เนล 2018 ที่ใช้กลไกนี้ มีการพูดคุยกันเกี่ยวกับการใช้การปรับให้เหมาะสมนี้กับระบบไฟล์อื่นๆ แต่เท่าที่ฉันทราบ XFS เป็นระบบไฟล์เดียวที่รองรับจนถึงตอนนี้

ฟังก์ชัน sync_file_range()

Linux มีการเรียกระบบ sync_file_range()ซึ่งทำให้คุณสามารถล้างไฟล์เพียงบางส่วนไปยังดิสก์ ไม่ใช่ทั้งไฟล์ การโทรนี้เริ่มต้นการล้างข้อมูลแบบอะซิงโครนัสและไม่รอให้เสร็จสิ้น แต่ในการอ้างอิงถึง sync_file_range() คำสั่งนี้กล่าวกันว่า "อันตรายมาก" ไม่แนะนำให้ใช้ คุณสมบัติและอันตราย sync_file_range() อธิบายได้ดีมากใน นี้ วัสดุ. โดยเฉพาะอย่างยิ่ง ดูเหมือนว่าการโทรนี้จะใช้ RocksDB เพื่อควบคุมเมื่อเคอร์เนลล้างข้อมูล "สกปรก" ลงดิสก์ แต่ในขณะเดียวกันก็มีการใช้เพื่อให้แน่ใจว่ามีการจัดเก็บข้อมูลที่เสถียร fdatasync(). ใน รหัส RocksDB มีความคิดเห็นที่น่าสนใจในเรื่องนี้ ตัวอย่างเช่นดูเหมือนว่าการโทร sync_file_range() เมื่อใช้ ZFS จะไม่ล้างข้อมูลลงดิสก์ ประสบการณ์บอกฉันว่าโค้ดที่ไม่ค่อยได้ใช้อาจมีข้อบกพร่อง ดังนั้น ฉันไม่แนะนำให้ใช้การเรียกระบบนี้ เว้นแต่จะมีความจำเป็นจริงๆ

การเรียกระบบเพื่อช่วยให้มั่นใจถึงการคงอยู่ของข้อมูล

ฉันได้ข้อสรุปว่ามีสามวิธีที่สามารถใช้เพื่อดำเนินการ I/O แบบถาวร พวกเขาทั้งหมดต้องการการเรียกใช้ฟังก์ชัน fsync() สำหรับไดเร็กทอรีที่สร้างไฟล์ นี่คือแนวทาง:

  1. การเรียกใช้ฟังก์ชัน fdatasync() หรือ fsync() หลังจากฟังก์ชั่น write() (ใช้ดีกว่า. fdatasync()).
  2. การทำงานกับตัวอธิบายไฟล์ที่เปิดด้วยแฟล็ก O_DSYNC หรือ O_SYNC (ดีกว่า - ด้วยธง O_DSYNC).
  3. การใช้คำสั่ง pwritev2() ด้วยธง RWF_DSYNC หรือ RWF_SYNC (โดยเฉพาะอย่างยิ่งกับธง RWF_DSYNC).

หมายเหตุประสิทธิภาพ

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

  1. การเขียนทับข้อมูลไฟล์นั้นเร็วกว่าการผนวกข้อมูลเข้ากับไฟล์ (ประสิทธิภาพที่เพิ่มขึ้นอาจอยู่ที่ 2-100%) การแนบข้อมูลกับไฟล์จำเป็นต้องเปลี่ยนแปลงข้อมูลเมตาของไฟล์เพิ่มเติม แม้หลังจากการเรียกระบบ fallocate()แต่ขนาดของผลกระทบนี้อาจแตกต่างกันไป ฉันแนะนำให้โทรเพื่อประสิทธิภาพที่ดีที่สุด fallocate() เพื่อจัดสรรพื้นที่ที่ต้องการไว้ล่วงหน้า จากนั้นช่องว่างนี้จะต้องเต็มไปด้วยศูนย์อย่างชัดเจนและถูกเรียก fsync(). ซึ่งจะทำให้บล็อกที่เกี่ยวข้องในระบบไฟล์ถูกทำเครื่องหมายเป็น "จัดสรร" แทน "ไม่ได้จัดสรร" สิ่งนี้ช่วยปรับปรุงประสิทธิภาพเล็กน้อย (ประมาณ 2%) นอกจากนี้ ดิสก์บางตัวอาจมีการดำเนินการเข้าถึงบล็อกแรกช้ากว่าดิสก์อื่นๆ ซึ่งหมายความว่าการเติมช่องว่างด้วยศูนย์สามารถนำไปสู่การปรับปรุงประสิทธิภาพที่สำคัญ (ประมาณ 100%) โดยเฉพาะอย่างยิ่งสิ่งนี้สามารถเกิดขึ้นได้กับดิสก์ AWS EBS (นี่เป็นข้อมูลที่ไม่เป็นทางการ ฉันไม่สามารถยืนยันได้) เช่นเดียวกับการจัดเก็บ ดิสก์ถาวร GCP (และนี่เป็นข้อมูลอย่างเป็นทางการที่ได้รับการยืนยันจากการทดสอบ) ผู้เชี่ยวชาญคนอื่น ๆ ได้ทำเช่นเดียวกัน การสังเกตที่เกี่ยวข้องกับดิสก์ต่างๆ
  2. ยิ่งการเรียกระบบน้อยลง ประสิทธิภาพก็จะยิ่งสูงขึ้น (สามารถรับได้ประมาณ 5%) ดูเหมือนว่าการโทร open() ด้วยธง O_DSYNC หรือโทร pwritev2() ด้วยธง RWF_SYNC โทรเร็วขึ้น fdatasync(). ฉันสงสัยว่าประเด็นคือด้วยวิธีนี้ ข้อเท็จจริงที่ต้องมีการเรียกระบบน้อยลงเพื่อแก้ไขงานเดียวกัน (การโทรหนึ่งครั้งแทนที่จะเป็นสองครั้ง) มีบทบาท แต่ความแตกต่างของประสิทธิภาพนั้นน้อยมาก ดังนั้นคุณจึงสามารถเพิกเฉยและใช้บางอย่างในแอปพลิเคชันที่ไม่ทำให้เกิดความซับซ้อนของตรรกะ

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

  • วิธีการเข้าถึง I/O — ภาพรวมของพื้นฐานของกลไกอินพุต / เอาท์พุต
  • ทำให้มั่นใจได้ว่าข้อมูลจะไปถึงดิสก์ - เรื่องราวเกี่ยวกับสิ่งที่เกิดขึ้นกับข้อมูลระหว่างทางจากแอปพลิเคชันไปยังดิสก์
  • เมื่อใดที่คุณควร fsync ไดเร็กทอรีที่มี - คำตอบสำหรับคำถามที่ว่าจะสมัครเมื่อใด fsync() สำหรับไดเร็กทอรี สรุปก็คือ คุณต้องทำสิ่งนี้เมื่อสร้างไฟล์ใหม่ และเหตุผลสำหรับคำแนะนำนี้คือใน Linux สามารถมีการอ้างอิงถึงไฟล์เดียวกันได้มากมาย
  • SQL Server บน Linux: FUA Internals - ต่อไปนี้คือคำอธิบายวิธีการใช้ที่จัดเก็บข้อมูลถาวรใน SQL Server บนแพลตฟอร์ม Linux มีการเปรียบเทียบที่น่าสนใจระหว่างการเรียกระบบ Windows และ Linux ที่นี่ ฉันเกือบจะแน่ใจว่าต้องขอบคุณเนื้อหานี้ที่ฉันได้เรียนรู้เกี่ยวกับการเพิ่มประสิทธิภาพ FUA ของ XFS

คุณเคยสูญเสียข้อมูลที่คุณคิดว่าจัดเก็บอย่างปลอดภัยบนดิสก์หรือไม่?

ที่เก็บข้อมูลที่ทนทานและ API ไฟล์ Linux

ที่เก็บข้อมูลที่ทนทานและ API ไฟล์ Linux

ที่มา: will.com