Jutaan file teks (kecil) dalam satu folder

15

Kami ingin menyimpan jutaan file teks dalam sistem file Linux, dengan tujuan dapat melakukan zip up dan melayani koleksi sewenang-wenang sebagai layanan. Kami telah mencoba solusi lain, seperti database kunci / nilai, tetapi persyaratan kami untuk konkurensi dan paralelisme menjadikan penggunaan sistem file asli sebagai pilihan terbaik.

Cara paling mudah adalah dengan menyimpan semua file dalam folder:

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

yang seharusnya dimungkinkan pada sistem file EXT4 , yang tidak memiliki batasan jumlah file dalam folder.

Dua proses FS adalah:

  1. Tulis file teks dari goresan web (tidak boleh dipengaruhi oleh jumlah file di folder).
  2. Zip file yang dipilih, diberikan oleh daftar nama file.

Pertanyaan saya adalah, apakah menyimpan hingga sepuluh juta file dalam folder memengaruhi kinerja operasi di atas, atau kinerja sistem umum, berbeda dari membuat pohon subfolder untuk file yang akan ditinggali?

pengguna1717828
sumber
4
Terkait: Cara memperbaiki kesalahan “Tidak ada ruang yang tersisa di perangkat” intermiten selama mv saat perangkat memiliki banyak ruang . Menggunakan dir_index, yang sering diaktifkan secara default, akan mempercepat pencarian tetapi dapat membatasi jumlah file per direktori.
Mark Plotnick
Mengapa tidak mencobanya dengan cepat di mesin virtual dan lihat seperti apa rasanya? Dengan bash itu sepele untuk mengisi folder dengan sejuta file teks dengan karakter acak di dalamnya. Saya merasa Anda akan mendapatkan informasi yang sangat berguna dengan cara itu, selain apa yang akan Anda pelajari di sini.
YosuaD
2
@ JoshuaD: Jika Anda mengisi semuanya sekaligus pada FS baru, Anda cenderung memiliki semua inode yang berdekatan pada disk, jadi ls -latau apa pun yang statsetiap inode dalam direktori (misalnya bashglobbing / penyelesaian tab) akan secara artifisial lebih cepat daripada setelah beberapa keausan (hapus beberapa file, tulis beberapa yang baru). ext4 mungkin lebih baik dengan ini daripada XFS, karena XFS secara dinamis mengalokasikan ruang untuk inode vs data, sehingga Anda dapat berakhir dengan inode yang lebih tersebar, saya pikir. (Tapi itu dugaan murni berdasarkan sedikit pengetahuan rinci; Saya baru saja menggunakan ext4). Pergi dengan abc/def/subdirs.
Peter Cordes
Ya, saya tidak berpikir tes yang saya sarankan akan dapat memberi tahu OP "ini akan berhasil", tetapi pasti bisa dengan cepat mengatakan kepadanya "ini tidak akan berhasil", yang berguna.
JoshuaD
1
tetapi persyaratan kami untuk konkurensi dan paralelisme menjadikan penggunaan filesystem asli pilihan terbaik Apa yang Anda coba? Begitu saja, saya akan berpikir bahkan RDBMS kelas bawah seperti MySQL dan servlet Java membuat file zip dengan cepatZipOutputStream akan mengalahkan hampir semua sistem file asli Linux gratis - Saya ragu Anda ingin membayar untuk GPFS IBM. Loop untuk memproses set hasil JDBC dan membuat aliran zip mungkin hanya 6-8 baris kode Java.
Andrew Henle

Jawaban:

10

The lsperintah, atau bahkan TAB-selesai atau perluasan wildcard oleh shell, biasanya akan mempresentasikan hasil mereka dalam rangka alfanumerik. Ini membutuhkan membaca seluruh daftar direktori dan menyortirnya. Dengan sepuluh juta file dalam satu direktori, operasi penyortiran ini akan memakan banyak waktu.

Jika Anda dapat menahan keinginan untuk menyelesaikan TAB dan misalnya menulis nama file yang akan dizip secara penuh, seharusnya tidak ada masalah.

Masalah lain dengan wildcard mungkin ekspansi wildcard yang mungkin menghasilkan lebih banyak nama file daripada yang sesuai pada baris perintah dengan panjang maksimum. Panjang baris perintah maksimum tipikal akan lebih dari cukup untuk sebagian besar situasi, tetapi ketika kita berbicara tentang jutaan file dalam satu direktori, ini bukan lagi asumsi yang aman. Ketika panjang baris perintah maksimum terlampaui dalam ekspansi wildcard, sebagian besar shell hanya akan gagal seluruh baris perintah tanpa mengeksekusi itu.

Ini dapat diatasi dengan melakukan operasi wildcard Anda menggunakan findperintah:

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

atau sintaksis yang serupa bila memungkinkan. Ini find ... -exec ... \+akan secara otomatis memperhitungkan panjang baris perintah maksimum, dan akan mengeksekusi perintah sebanyak yang diperlukan sambil menyesuaikan jumlah maksimal nama file untuk setiap baris perintah.

telcoM
sumber
Sistem file modern menggunakan B, B + atau pohon serupa untuk menyimpan entri direktori. en.wikipedia.org/wiki/HTree
dimm
4
Ya ... tetapi jika shell atau lsperintah tidak akan mengetahui bahwa daftar direktori sudah diurutkan, mereka akan mengambil waktu untuk menjalankan algoritma penyortiran. Dan selain itu, userspace mungkin menggunakan urutan penyortiran lokal (LC_COLLATE) yang mungkin berbeda dari apa yang mungkin dilakukan sistem file secara internal.
telcoM
17

Ini sangat dekat dengan pertanyaan / jawaban berdasarkan pendapat tetapi saya akan mencoba untuk memberikan beberapa fakta dengan pendapat saya.

  1. Jika Anda memiliki jumlah file yang sangat besar di folder, setiap operasi berbasis shell yang mencoba menghitungnya (mis. mv * /somewhere/else) Mungkin gagal untuk memperluas wildcard berhasil, atau hasilnya mungkin terlalu besar untuk digunakan.
  2. ls akan membutuhkan waktu lebih lama untuk menghitung jumlah file yang sangat besar daripada sejumlah kecil file.
  3. Sistem file akan dapat menangani jutaan file dalam satu direktori, tetapi orang mungkin akan kesulitan.

Satu rekomendasi adalah untuk membagi nama file menjadi dua, tiga atau empat potongan karakter dan menggunakannya sebagai subdirektori. Misalnya, somefilename.txtdapat disimpan sebagai som/efi/somefilename.txt. Jika Anda menggunakan nama numerik maka pisah dari kanan ke kiri alih-alih kiri ke kanan sehingga ada distribusi yang lebih merata. Misalnya 12345.txtdapat disimpan sebagai 345/12/12345.txt.

Anda dapat menggunakan yang setara dengan zip -j zipfile.zip path1/file1 path2/file2 ...untuk menghindari termasuk jalur subdirektori antara dalam file ZIP.

Jika Anda menyajikan file-file ini dari server web (saya tidak sepenuhnya yakin apakah itu relevan) itu sepele untuk menyembunyikan struktur ini demi direktori virtual dengan aturan penulisan ulang di Apache2. Saya akan menganggap hal yang sama berlaku untuk Nginx.

roaima
sumber
The *ekspansi akan berhasil kecuali jika Anda kehabisan memori, tetapi jika Anda menaikkan batas stacksize (di Linux) atau menggunakan shell mana mvadalah builtin atau dapat builtin (ksh93, zsh), yang execve()system call mungkin gagal dengan kesalahan E2BIG.
Stéphane Chazelas
@ StéphaneChazelas ya ok, pilihan kata-kata saya mungkin lebih baik, tetapi efek bersih untuk pengguna hampir sama. Saya akan melihat apakah saya dapat sedikit mengubah kata-kata tanpa terjebak dalam kompleksitas.
roaima
Hanya ingin tahu bagaimana Anda akan mengompres file zip itu jika Anda menghindari menyertakan jalur subdirektori perantara di dalamnya, tanpa mengalami masalah yang Anda diskusikan?
Octopus
1
@Octopus OP menyatakan bahwa file zip akan berisi " file yang dipilih, diberikan oleh daftar nama file ".
roaima
Saya akan merekomendasikan penggunaan zip -j - ...dan pemipaan aliran output langsung ke koneksi jaringan klien zip -j zipfile.zip .... Menulis zipfile aktual ke disk berarti jalur data dibaca dari disk-> kompres-> tulis ke disk-> baca dari disk-> kirim ke klien. Itu bisa tiga kali lipat persyaratan IO disk Anda setelah dibaca dari disk-> kirim-> kirim ke klien.
Andrew Henle
5

Saya menjalankan situs web yang menangani basis data untuk film, TV, dan permainan video. Untuk masing-masing ini ada beberapa gambar dengan TV yang berisi lusinan gambar per pertunjukan (yaitu foto snapshot dll).

Akhirnya ada banyak file gambar. Di suatu tempat di kisaran 250.000+. Ini semua disimpan dalam perangkat penyimpanan blok yang terpasang di mana waktu akses masuk akal.

Upaya pertama saya menyimpan gambar adalah dalam satu folder sebagai /mnt/images/UUID.jpg

Saya mengalami tantangan berikut.

  • lsmelalui terminal jarak jauh hanya akan menggantung. Prosesnya akan menjadi zombie dan CTRL+Ctidak akan merusaknya.
  • sebelum saya mencapai titik itu lsperintah apa pun akan dengan cepat mengisi buffer output dan CTRL+Ctidak akan menghentikan pengguliran tanpa akhir.
  • Membuat zip 250.000 file dari satu folder membutuhkan waktu sekitar 2 jam. Anda harus menjalankan perintah zip terlepas dari terminal jika tidak ada gangguan dalam koneksi berarti Anda harus memulai dari awal lagi.
  • Saya tidak akan mengambil risiko mencoba menggunakan file zip di Windows.
  • Folder dengan cepat menjadi zona tidak diizinkan manusia .

Saya akhirnya harus menyimpan file dalam subfolder menggunakan waktu pembuatan untuk membuat path. Seperti /mnt/images/YYYY/MM/DD/UUID.jpg. Ini menyelesaikan semua masalah di atas, dan memungkinkan saya untuk membuat file zip yang menargetkan tanggal.

Jika satu-satunya pengidentifikasi untuk file yang Anda miliki adalah angka numerik, dan angka-angka ini cenderung berjalan berurutan. Mengapa tidak mengelompokkan mereka berdasarkan 100000, 10000dan 1000.

Misalnya, jika Anda memiliki file dengan nama 384295.txtpath akan menjadi:

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

Jika Anda tahu Anda akan mencapai beberapa juta. Gunakan 0awalan untuk 1.000.000

/mnt/file/000000/300000/80000/4000/295.txt
Reactgular
sumber
1

Tulis file teks dari goresan web (tidak boleh dipengaruhi oleh jumlah file di folder).

Untuk membuat file baru diperlukan pemindaian file direktori mencari ruang kosong yang cukup untuk entri direktori baru. Jika tidak ada ruang yang cukup besar untuk menyimpan entri direktori baru, itu akan ditempatkan di akhir file direktori. Ketika jumlah file dalam direktori meningkat, waktu untuk memindai direktori juga meningkat.

Selama file direktori tetap di cache sistem, kinerja yang dihasilkan dari ini tidak akan buruk, tetapi jika data dirilis, membaca file direktori (biasanya sangat terfragmentasi) dari disk dapat menghabiskan waktu yang cukup lama. SSD meningkatkan ini, tetapi untuk direktori dengan jutaan file, masih ada hit kinerja yang terlihat.

Zip file yang dipilih, diberikan oleh daftar nama file.

Ini juga membutuhkan waktu tambahan dalam direktori dengan jutaan file. Dalam sistem file dengan entri direktori hash (seperti EXT4), perbedaan ini minimal.

akankah menyimpan hingga sepuluh juta file dalam folder memengaruhi kinerja operasi di atas, atau kinerja sistem umum, berbeda dengan membuat pohon subfolder untuk file yang akan ditinggali?

Pohon subfolder tidak memiliki kekurangan kinerja di atas. Selain itu, jika sistem file yang mendasarinya diubah menjadi tidak memiliki nama file hash, metodologi pohon akan tetap bekerja dengan baik.

Peter
sumber
1

Pertama: mencegah 'ls' dari pengurutan dengan 'ls -U', mungkin perbarui ~ / bashrc Anda untuk memiliki 'alias ls = "ls -U"' atau serupa.

Untuk kumpulan file besar Anda, Anda dapat mencobanya seperti ini:

  • buat satu set file uji

  • lihat apakah banyak nama file yang menyebabkan masalah

  • gunakan xargs parmeter-batching dan perilaku zip (standar) untuk menambahkan file ke zip untuk menghindari masalah.

Ini bekerja dengan baik:

# 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
selamat tinggal
sumber