จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง

จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง

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

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

แนวคิดคือ:

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

จะพยายามเขียนให้สั้นนะครับ ขออภัยล่วงหน้าหากกระทู้ยาว

ทุกอย่างเริ่มต้นด้วยความจริงที่ว่าฉันไม่สามารถหาเซิร์ฟเวอร์ที่เหมาะสมในโลกที่สามารถบันทึกข้อมูลที่ได้รับผ่านโปรโตคอล HTTP ลงในไฟล์เก็บถาวรได้โดยตรง โดยไม่มีข้อเสียที่มีอยู่ในไฟล์เก็บถาวรทั่วไปและการจัดเก็บอ็อบเจ็กต์ และเหตุผลในการค้นหาคือคลัสเตอร์ Origin ของเซิร์ฟเวอร์ 10 เครื่องที่เติบโตเป็นขนาดใหญ่ โดยมีไฟล์ขนาดเล็กถึง 250,000,000 ไฟล์สะสมไว้แล้ว และแนวโน้มการเติบโตจะไม่หยุดลง

สำหรับผู้ที่ไม่ชอบอ่านบทความ เอกสารเล็กๆ น้อยๆ จะง่ายกว่า:

ที่นี่ и ที่นี่.

และนักเทียบท่าในเวลาเดียวกัน ตอนนี้มีตัวเลือกเฉพาะกับ nginx ภายในในกรณี:

docker run -d --restart=always -e host=localhost -e root=/var/storage 
-v /var/storage:/var/storage --name wzd -p 80:80 eltaline/wzd

ถัดไป:

หากมีไฟล์จำนวนมาก จำเป็นต้องใช้ทรัพยากรจำนวนมาก และส่วนที่แย่ที่สุดคือบางไฟล์สูญเปล่า ตัวอย่างเช่น เมื่อใช้ระบบไฟล์แบบคลัสเตอร์ (ในกรณีนี้คือ MooseFS) ไฟล์นั้นจะใช้พื้นที่อย่างน้อย 64 KB เสมอ โดยไม่คำนึงถึงขนาดจริง นั่นคือสำหรับไฟล์ขนาด 3, 10 หรือ 30 KB จำเป็นต้องมี 64 KB บนดิสก์ หากมีหนึ่งในสี่ของพันล้านไฟล์ เราจะสูญเสียจาก 2 ถึง 10 เทราไบต์ จะไม่สามารถสร้างไฟล์ใหม่ได้อย่างไม่มีกำหนด เนื่องจาก MooseFS มีข้อจำกัด: ไม่เกิน 1 พันล้านไฟล์ต่อหนึ่งแบบจำลองของแต่ละไฟล์

เมื่อจำนวนไฟล์เพิ่มขึ้น จึงจำเป็นต้องมี RAM จำนวนมากสำหรับข้อมูลเมตา การเทข้อมูลเมตาขนาดใหญ่บ่อยครั้งยังส่งผลให้ไดรฟ์ SSD สึกหรออีกด้วย

เซิร์ฟเวอร์ WZD เราวางสิ่งต่าง ๆ ตามลำดับบนดิสก์

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

โดยรวมแล้ว แทนที่จะเป็นหนึ่งในสี่ของพันล้านไฟล์ ในกรณีของฉัน เหลือไฟล์เก็บถาวร Bolt เพียง 10 ล้านไฟล์เท่านั้น หากฉันมีโอกาสเปลี่ยนโครงสร้างไฟล์ไดเร็กทอรีปัจจุบัน จะสามารถลดเหลือประมาณ 1 ล้านไฟล์ได้

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

สถาปัตยกรรมและคุณสมบัติของเซิร์ฟเวอร์ wZD

จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง

เซิร์ฟเวอร์ทำงานภายใต้ระบบปฏิบัติการ Linux, BSD, Solaris และ OSX ฉันทดสอบเฉพาะสถาปัตยกรรม AMD64 ภายใต้ Linux แต่ควรจะใช้ได้กับ ARM64, PPC64, MIPS64

คุณสมบัติหลัก:

  • มัลติเธรด;
  • Multiserver ให้ความทนทานต่อข้อผิดพลาดและการปรับสมดุลโหลด
  • ความโปร่งใสสูงสุดสำหรับผู้ใช้หรือนักพัฒนา
  • วิธีการ HTTP ที่รองรับ: GET, HEAD, PUT และ DELETE;
  • การควบคุมพฤติกรรมการอ่านและการเขียนผ่านส่วนหัวของไคลเอ็นต์
  • รองรับโฮสต์เสมือนที่ยืดหยุ่น
  • สนับสนุนความสมบูรณ์ของข้อมูล CRC เมื่อเขียน/อ่าน
  • บัฟเฟอร์กึ่งไดนามิกสำหรับการใช้หน่วยความจำน้อยที่สุดและการปรับแต่งประสิทธิภาพเครือข่ายที่เหมาะสมที่สุด
  • การบดอัดข้อมูลที่เลื่อนออกไป
  • นอกจากนี้ยังมีการเสนอ wZA โปรแกรมเก็บถาวรแบบมัลติเธรดสำหรับการย้ายไฟล์โดยไม่ต้องหยุดบริการ

ประสบการณ์จริง:

ฉันพัฒนาและทดสอบเซิร์ฟเวอร์และผู้จัดเก็บข้อมูลสดมาเป็นเวลานานแล้ว ตอนนี้มันประสบความสำเร็จในการทำงานบนคลัสเตอร์ที่มีไฟล์ขนาดเล็ก (รูปภาพ) จำนวน 250,000,000 ไฟล์ ซึ่งอยู่ในไดเร็กทอรี 15,000,000 ไดเร็กทอรีบนไดรฟ์ SATA แยกกัน คลัสเตอร์ของเซิร์ฟเวอร์ 10 เครื่องคือเซิร์ฟเวอร์ Origin ที่ติดตั้งอยู่หลังเครือข่าย CDN ในการให้บริการ จะใช้เซิร์ฟเวอร์ Nginx 2 เครื่อง + เซิร์ฟเวอร์ wZD 2 เครื่อง

สำหรับผู้ที่ตัดสินใจใช้เซิร์ฟเวอร์นี้ ควรวางแผนโครงสร้างไดเร็กทอรีก่อนใช้งาน (หากมี) ผมขอจองทันทีว่าเซิร์ฟเวอร์ไม่ได้ตั้งใจจะอัดทุกอย่างลงในไฟล์ 1 Bolt

การทดสอบประสิทธิภาพ:

ยิ่งไฟล์ซิปมีขนาดเล็กลงเท่าใด การดำเนินการ GET และ PUT ก็จะเร็วขึ้นเท่านั้น มาเปรียบเทียบเวลารวมสำหรับการเขียนไคลเอ็นต์ HTTP ไปยังไฟล์ปกติและไฟล์เก็บถาวร Bolt รวมถึงการอ่าน เปรียบเทียบการทำงานกับไฟล์ขนาด 32 KB, 256 KB, 1024 KB, 4096 KB และ 32768 KB

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

ฉันทำการทดสอบประสิทธิภาพของไดรฟ์ SSD เนื่องจากการทดสอบไดรฟ์ SATA ไม่ได้แสดงความแตกต่างที่ชัดเจน

กราฟตามผลการทดสอบ:

จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง
จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง

อย่างที่คุณเห็น สำหรับไฟล์ขนาดเล็ก เวลาในการอ่านและเขียนระหว่างไฟล์ที่เก็บถาวรและไฟล์ที่ไม่ได้เก็บถาวรแตกต่างกันเล็กน้อย

เราได้ภาพที่แตกต่างไปจากเดิมอย่างสิ้นเชิงเมื่อทดสอบการอ่านและเขียนไฟล์ขนาด 32 MB:

จัดเก็บไฟล์ขนาดเล็กหลายร้อยล้านไฟล์อย่างมีประสิทธิภาพ โซลูชันที่โฮสต์ด้วยตนเอง

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

*ในทางเทคนิค คุณสามารถใช้เซิร์ฟเวอร์นี้สำหรับงานที่ต้องใช้ NoSQL

วิธีการพื้นฐานในการทำงานกับเซิร์ฟเวอร์ wZD:

กำลังโหลดไฟล์ปกติ:

curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg

การอัปโหลดไฟล์ไปยังไฟล์เก็บถาวร Bolt (หากพารามิเตอร์เซิร์ฟเวอร์ fmaxsize ซึ่งกำหนดขนาดไฟล์สูงสุดที่สามารถรวมไว้ในไฟล์เก็บถาวรนั้นจะต้องไม่เกิน หากเกิน ไฟล์จะถูกอัปโหลดตามปกติถัดจากไฟล์เก็บถาวร):

curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg

การดาวน์โหลดไฟล์ (หากมีไฟล์ที่มีชื่อเดียวกันบนดิสก์และในไฟล์เก็บถาวร จากนั้นเมื่อดาวน์โหลด ลำดับความสำคัญจะได้รับตามค่าเริ่มต้นสำหรับไฟล์ที่ไม่ได้เก็บถาวร):

curl -o test.jpg http://localhost/test/test.jpg

การดาวน์โหลดไฟล์จากไฟล์เก็บถาวร Bolt (บังคับ):

curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg

คำอธิบายของวิธีการอื่น ๆ อยู่ในเอกสารประกอบ

เอกสาร WZD
เอกสาร WZA

ขณะนี้เซิร์ฟเวอร์รองรับเฉพาะโปรโตคอล HTTP เท่านั้น แต่ยังใช้งานไม่ได้กับ HTTPS ไม่รองรับวิธี POST เช่นกัน (ยังไม่ได้ตัดสินใจว่าจำเป็นหรือไม่)

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

สิ่งที่ต้องทำ:

  • การพัฒนาตัวจำลองและผู้จัดจำหน่าย + ภูมิศาสตร์ของคุณเองเพื่อความเป็นไปได้ในการใช้งานในระบบขนาดใหญ่ที่ไม่มีระบบไฟล์คลัสเตอร์ (ทุกอย่างสำหรับผู้ใหญ่)
  • ความเป็นไปได้ในการกู้คืนข้อมูลเมตาแบบย้อนกลับโดยสมบูรณ์หากข้อมูลสูญหายโดยสิ้นเชิง (หากใช้ผู้จัดจำหน่าย)
  • โปรโตคอลดั้งเดิมสำหรับความสามารถในการใช้การเชื่อมต่อเครือข่ายแบบถาวรและไดรเวอร์สำหรับภาษาการเขียนโปรแกรมที่แตกต่างกัน
  • ความเป็นไปได้ขั้นสูงสำหรับการใช้ส่วนประกอบ NoSQL
  • การบีบอัดประเภทต่าง ๆ (gzip, zstd, snappy) สำหรับไฟล์หรือค่าภายในไฟล์เก็บถาวร Bolt และสำหรับไฟล์ปกติ
  • การเข้ารหัสประเภทต่างๆ สำหรับไฟล์หรือค่าภายในไฟล์เก็บถาวร Bolt และสำหรับไฟล์ปกติ
  • การแปลงวิดีโอฝั่งเซิร์ฟเวอร์ล่าช้า รวมถึงบน GPU

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

ที่มา: will.com

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