ไฟล์ข้อความนับล้าน (เล็ก) ในโฟลเดอร์


15

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

วิธีที่ตรงไปตรงมาที่สุดคือการจัดเก็บไฟล์ทั้งหมดในโฟลเดอร์:

$ ls text_files/
1.txt
2.txt
3.txt

ซึ่งควรจะเป็นไปได้ในระบบไฟล์ EXT4ซึ่งไม่ จำกัด จำนวนไฟล์ในโฟลเดอร์

กระบวนการ FS ทั้งสองจะเป็น:

  1. เขียนไฟล์ข้อความจากเว็บขูด (ไม่ควรได้รับผลกระทบจากจำนวนไฟล์ในโฟลเดอร์)
  2. ซิปไฟล์ที่เลือกกำหนดโดยรายการชื่อไฟล์

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


4
ที่เกี่ยวข้อง: วิธีการแก้ไข intermittant“ไม่มีพื้นที่ว่างเหลือบนอุปกรณ์” ข้อผิดพลาดระหว่าง mv เมื่ออุปกรณ์มีความอุดมสมบูรณ์ของพื้นที่ การใช้dir_indexซึ่งโดยปกติจะเปิดใช้งานตามค่าเริ่มต้นจะช่วยเพิ่มความเร็วในการค้นหา แต่อาจ จำกัด จำนวนไฟล์ต่อไดเรกทอรี
Mark Plotnick

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

2
@JoshuaD: หากคุณเติมข้อมูลทั้งหมดในครั้งเดียวบน FS สดคุณมีแนวโน้มที่จะมี inodes ทั้งหมดที่ต่อเนื่องกันบนดิสก์ดังนั้นls -lหรือสิ่งอื่นใดที่statinode ในไดเรกทอรี (เช่นการทำให้bashกลม / แท็บเสร็จ) จะเร็วขึ้น กว่าหลังจากการสึกหรอ (ลบไฟล์บางไฟล์เขียนไฟล์ใหม่) ext4 อาจทำได้ดีกว่าด้วย XFS เนื่องจาก XFS จัดสรรพื้นที่สำหรับ inodes เทียบกับข้อมูลแบบไดนามิกดังนั้นคุณจึงสามารถจบลงด้วย inodes ที่กระจัดกระจายมากขึ้นฉันคิดว่า (แต่นั่นเป็นการคาดเดาที่บริสุทธิ์โดยอาศัยความรู้ที่ละเอียดน้อยมากฉันแทบจะไม่เคยใช้ ext4) ไปกับabc/def/ตำบล
Peter Cordes

ใช่ฉันไม่คิดว่าการทดสอบที่ฉันแนะนำจะสามารถบอก OP ได้ "สิ่งนี้จะได้ผล" แต่มันสามารถบอกเขาได้อย่างรวดเร็วว่า "สิ่งนี้จะไม่ทำงาน" ซึ่งมีประโยชน์
JoshuaD

1
แต่ความต้องการของเราสำหรับการทำงานพร้อมกันและความเท่าเทียมทำให้การใช้ระบบไฟล์ดั้งเดิมเป็นตัวเลือกที่ดีที่สุด คุณลองทำอะไร? ด้วยมือของฉันฉันคิดว่าแม้แต่ RDBMS ที่ต่ำกว่าเช่น MySQL และ Java servlet ที่สร้างไฟล์ zip ได้ทันทีZipOutputStreamจะเอาชนะระบบไฟล์ Linux ได้ฟรีฉันสงสัยว่าคุณต้องการจ่ายสำหรับ GPFS ของ IBM การวนซ้ำเพื่อประมวลผลชุดผลลัพธ์ JDBC และทำให้กระแสซิปนั้นน่าจะเป็นเพียงโค้ด 6-8 บรรทัดของโค้ด Java
Andrew Henle

คำตอบ:


10

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

หากคุณสามารถต้านทานการกระตุ้นให้เสร็จสิ้น TAB และเช่นเขียนชื่อไฟล์ที่จะซิปเต็มจะไม่มีปัญหา

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

สิ่งนี้สามารถแก้ไขได้โดยการใช้สัญลักษณ์แทนfindคำสั่งของคุณ:

find <directory> -name '<wildcard expression>' -exec <command> {} \+

หรือไวยากรณ์ที่คล้ายกันเมื่อใดก็ตามที่เป็นไปได้ find ... -exec ... \+จะใช้เวลาโดยอัตโนมัติเข้าบัญชีความยาวบรรทัดคำสั่งสูงสุดและจะดำเนินการคำสั่งหลาย ๆ ครั้งตามที่ต้องการในขณะที่เหมาะสมจำนวนเงินสูงสุดของชื่อไฟล์เพื่อแต่ละบรรทัดคำสั่ง


ระบบไฟล์ที่ทันสมัยใช้ B, B + หรือต้นไม้ที่คล้ายกันเพื่อเก็บรายการไดเรกทอรี en.wikipedia.org/wiki/HTree
dimm

4
ใช่ ... แต่ถ้าเชลล์หรือlsคำสั่งจะไม่ได้รับรู้ว่ารายชื่อไดเรกทอรีเรียงแล้วพวกเขาจะต้องใช้เวลาในการรันอัลกอริทึมการเรียงลำดับอย่างไรก็ตาม และนอกจากนี้ userspace อาจใช้ลำดับการจัดเรียงแบบโลคัล (LC_COLLATE) ที่อาจแตกต่างจากสิ่งที่ระบบไฟล์อาจทำภายใน
telcoM

17

นี่ใกล้กับคำถาม / คำตอบที่เป็นอันตราย แต่ฉันจะพยายามให้ข้อเท็จจริงบางอย่างกับความคิดเห็นของฉัน

  1. หากคุณมีไฟล์จำนวนมากในโฟลเดอร์การดำเนินการบนเชลล์ที่พยายามระบุไฟล์เหล่านั้น (เช่นmv * /somewhere/else) อาจล้มเหลวในการขยายสัญลักษณ์แทนได้สำเร็จหรือผลลัพธ์อาจมีขนาดใหญ่เกินไปที่จะใช้
  2. ls จะใช้เวลานานกว่าในการระบุจำนวนไฟล์ที่มีขนาดใหญ่กว่าไฟล์จำนวนเล็กน้อย
  3. ระบบไฟล์จะสามารถจัดการไฟล์ได้นับล้านไฟล์ในไดเรกทอรีเดียว แต่ผู้คนอาจต้องดิ้นรน

คำแนะนำอย่างหนึ่งคือการแยกชื่อไฟล์ออกเป็นสองตัวอักษรสามหรือสี่ชิ้นและใช้สิ่งเหล่านั้นเป็นไดเรกทอรีย่อย ยกตัวอย่างเช่นอาจจะมีการเก็บไว้เป็นsomefilename.txt som/efi/somefilename.txtหากคุณใช้ชื่อที่เป็นตัวเลขให้แยกจากขวาไปซ้ายแทนซ้ายไปขวาเพื่อให้มีการแจกแจงที่สม่ำเสมอยิ่งขึ้น ยกตัวอย่างเช่นอาจจะมีการเก็บไว้เป็น12345.txt345/12/12345.txt

คุณสามารถใช้เทียบเท่าzip -j zipfile.zip path1/file1 path2/file2 ...เพื่อหลีกเลี่ยงการรวมเส้นทางย่อยไดเรกทอรีกลางในไฟล์ ZIP

หากคุณกำลังแสดงไฟล์เหล่านี้จากเว็บเซิร์ฟเวอร์ (ฉันไม่แน่ใจว่าเกี่ยวข้องหรือไม่) เป็นเรื่องเล็กน้อยที่จะซ่อนโครงสร้างนี้ไว้ในไดเรกทอรีเสมือนพร้อมกฎการเขียนซ้ำใน Apache2 ฉันจะถือว่าเหมือนกันเป็นจริงสำหรับ Nginx


การ*ขยายจะประสบความสำเร็จเว้นแต่คุณจะมีหน่วยความจำไม่เพียงพอ แต่ถ้าคุณเพิ่มขีด จำกัด สแต็ก (บน Linux) หรือใช้เชลล์ที่mvมีอยู่แล้วภายในหรือสามารถสร้างได้ภายใน (ksh93, zsh) การexecve()เรียกระบบอาจล้มเหลวด้วยข้อผิดพลาด E2BIG
Stéphane Chazelas

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

แค่อยากรู้ว่าคุณจะคลายการบีบอัดไฟล์ zip อย่างไรถ้าคุณหลีกเลี่ยงการรวมพา ธ ไดเรกทอรีย่อยระดับกลางในไฟล์โดยไม่ต้องเจอกับปัญหาที่คุณพูดถึง?
Octopus

1
@ Octopus the OP ระบุว่าไฟล์ zip จะมี " ไฟล์ที่เลือกซึ่งกำหนดโดยรายชื่อไฟล์ "
roaima

ผมขอแนะนำให้ใช้และท่อกระแสออกโดยตรงผ่านการเชื่อมต่อเครือข่ายของลูกค้าzip -j - ... zip -j zipfile.zip ...การเขียนไฟล์ zipfile จริงไปยังดิสก์หมายถึงเส้นทางข้อมูลถูกอ่านจาก disk-> compress-> write to disk-> read จาก disk-> send to client ที่สามารถเพิ่มความต้องการ IO ของดิสก์ได้ถึงสามเท่าเมื่ออ่านจาก disk-> compress-> send to client
Andrew Henle

5

ฉันใช้เว็บไซต์ที่จัดการฐานข้อมูลสำหรับภาพยนตร์โทรทัศน์และวิดีโอเกม สำหรับแต่ละภาพมีโทรทัศน์หลายภาพที่มีภาพหลายสิบรายการต่อการแสดง (เช่นภาพรวมตอน ฯลฯ )

ในที่สุดก็มีไฟล์รูปภาพมากมาย อยู่ในช่วง 250,000+ แห่ง สิ่งเหล่านี้จะถูกเก็บไว้ในอุปกรณ์จัดเก็บข้อมูลแบบต่อพ่วงซึ่งเวลาในการเข้าถึงเหมาะสม

ความพยายามครั้งแรกของฉันในการจัดเก็บภาพคือในโฟลเดอร์เดียวเป็น /mnt/images/UUID.jpg

ฉันวิ่งเข้าไปในความท้าทายต่อไปนี้

  • lsผ่านทางเทอร์มินัลระยะไกลก็จะแขวน กระบวนการนี้จะเป็นซอมบี้และCTRL+Cจะไม่ทำลายมัน
  • ก่อนที่ฉันจะไปถึงจุดนั้นlsคำสั่งใด ๆก็จะเติมบัฟเฟอร์เอาต์พุตอย่างรวดเร็วและCTRL+Cจะไม่หยุดการเลื่อนที่ไม่มีที่สิ้นสุด
  • การซิปไฟล์ 250,000 ไฟล์จากโฟลเดอร์เดียวใช้เวลาประมาณ 2 ชั่วโมง คุณต้องรันคำสั่ง zip ที่แยกออกจากเทอร์มินัลมิฉะนั้นการหยุดชะงักใด ๆ ในการเชื่อมต่อหมายความว่าคุณต้องเริ่มต้นใหม่อีกครั้ง
  • ฉันจะไม่เสี่ยงที่จะลองใช้ไฟล์ zip บน Windows
  • โฟลเดอร์กลายเป็นโซนที่ไม่มีมนุษย์อนุญาตอย่างรวดเร็ว

ฉันต้องเก็บไฟล์ไว้ในโฟลเดอร์ย่อยโดยใช้เวลาในการสร้างเพื่อสร้างพา ธ /mnt/images/YYYY/MM/DD/UUID.jpgเช่น ทั้งหมดนี้แก้ไขปัญหาข้างต้นและอนุญาตให้ฉันสร้างไฟล์ zip ที่กำหนดเป้าหมายวันที่

หากตัวระบุเดียวสำหรับไฟล์ที่คุณมีคือตัวเลขและตัวเลขเหล่านี้มักจะทำงานตามลำดับ ทำไมไม่กลุ่มพวกเขาโดย100000, และ100001000

ตัวอย่างเช่นหากคุณมีไฟล์ชื่อ384295.txtพา ธ จะเป็น:

/mnt/file/300000/80000/4000/295.txt

ถ้าคุณรู้ว่าคุณจะไปถึงไม่กี่ล้าน ใช้0คำนำหน้า 1,000,000

/mnt/file/000000/300000/80000/4000/295.txt

1

เขียนไฟล์ข้อความจากเว็บขูด (ไม่ควรได้รับผลกระทบจากจำนวนไฟล์ในโฟลเดอร์)

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

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

ซิปไฟล์ที่เลือกกำหนดโดยรายการชื่อไฟล์

นี่เป็นโอกาสที่จะต้องใช้เวลาเพิ่มเติมในไดเรกทอรีที่มีไฟล์นับล้าน ในระบบไฟล์ที่มีรายการไดเรกทอรีที่แฮช (เช่น EXT4) ความแตกต่างนี้มีเพียงเล็กน้อย

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

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


1

ประการแรก: ป้องกัน 'ls' จากการเรียงลำดับด้วย 'ls -U' อาจอัพเดต ~ / bashrc ของคุณให้มี 'alias ls = "ls -U"' หรือที่คล้ายกัน

สำหรับชุดไฟล์ขนาดใหญ่ของคุณคุณสามารถลองได้ดังนี้:

  • สร้างชุดทดสอบไฟล์

  • ดูว่าชื่อไฟล์จำนวนมากทำให้เกิดปัญหา

  • ใช้ xargs parmeter-batching และพฤติกรรมของ zip (ค่าเริ่มต้น) ของการเพิ่มไฟล์ลงใน zip เพื่อหลีกเลี่ยงปัญหา

สิ่งนี้ทำงานได้ดี:

# create ~ 100k files
seq 1 99999 | sed "s/\(.*\)/a_somewhat_long_filename_as_a_prefix_to_exercise_zip_parameter_processing_\1.txt/" | xargs touch
# see if zip can handle such a list of names
zip -q /tmp/bar.zip ./*
    bash: /usr/bin/zip: Argument list too long
# use xargs to batch sets of filenames to zip
find . -type f | xargs zip -q /tmp/foo.zip
l /tmp/foo.zip
    28692 -rw-r--r-- 1 jmullee jmullee 29377592 2017-12-16 20:12 /tmp/foo.zip
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.