Кажется, общеизвестно, что вы должны использовать глубокую (также называемую древовидной) структуру каталогов (например, files/00/01/123.data
) вместо плоского каталога (например, files/123.data
), когда вы хотите хранить миллионы файлов. Возможно, это было верно для старых файловых систем, таких как ext3
, но верно ли это для более современных файловых систем, таких как ext4
?
Давай проверим это.
Мы будем использовать Ruby для создания и тестирования обеих стратегий хранения. Сначала нам нужно найти способ создавать поддельные файлы. Мы хотим создать 10 миллионов из них. Для этого мы просто воспользуемся хешем со случайными ключами md5 и случайными значениями md5. Таким образом, мы уверены, что читаем то, что не может быть кэшировано системой:
hash = {} 10_000_000.times do key = Digest::MD5.hexdigest(rand.to_s) value = Digest::MD5.hexdigest(rand.to_s) hash[key] = value end
Затем нам понадобится код для записи, а не для чтения этих файлов с использованием стратегии хранения плоских каталогов:
puts Benchmark.measure { hash.each do |key,value| File.write "./dir_flat/#{key}", value end } puts Benchmark.measure { hash.each do |key,value| File.read "./dir_flat/#{key}" end }
И некоторый код для записи, чем для чтения этих файлов, с использованием стратегии хранения в глубоких каталогах. Мы выбрали два уровня каталогов с двумя шестнадцатеричными буквами. В среднем он должен содержать 152-153 файла на листовой каталог. (10 000 000 / (256 * 256)):
puts Benchmark.measure { hash.each do |key,value| dir_path = "./dir_deep/#{key[0..1]}/#{key[2..3]}/" FileUtils.mkdir_p dir_path File.write dir_path + key, value end } puts Benchmark.measure { hash.each do |key,value| dir_path = "./dir_deep/#{key[0..1]}/#{key[2..3]}/" File.read dir_path + key end }
Отметим, что на производительность записи, вероятно, влияет динамическое создание каталогов. Давайте предварительно отрендерим структуру каталогов:
hash.keys.each do |key| dir_path = "./dir_deep/#{key[0..1]}/#{key[2..3]}/" FileUtils.mkdir_p dir_path end puts Benchmark.measure { hash.each do |key,value| dir_path = "./dir_deep/#{key[0..1]}/#{key[2..3]}/" File.write dir_path + key, value end } puts Benchmark.measure { hash.each do |key,value| dir_path = "./dir_deep/#{key[0..1]}/#{key[2..3]}/" File.read dir_path + key end }
Вот окончательные результаты тестов:
Запись выполняется на 44% быстрее при использовании плоской структуры каталогов вместо глубокой / древовидной структуры каталогов. Чтение происходит даже в 7,8 раза быстрее.
В заключение, просто используйте плоскую структуру каталогов. Так проще в использовании. Быстрее писать. Гораздо быстрее читается. Экономьте на ионодах. И не нужно предварительно создавать или динамически создавать папки веток.
Ссылки: источник - сырые результаты
[Edit] Итак, после публикации этой статьи я обнаружил, что ограничения ext4 составляют около 10 118 651 (или ~ 10 233 706) файлов на каталог для длинного имени файла md5.
Я пытался запустить вышеуказанный тест с 20 миллионами файлов. Но я получал Errno::ENOSPC: No space left on device @ rb_sysopen
ошибку в Ruby. Это было странно, потому что и дисковое пространство, и inode были в порядке.
В журнале thedmesg
у меня действительно были ошибки полного индекса каталога inode:
ext4_dx_add_entry:2235: inode #258713: comm pry: Directory index full [1718.956797] EXT4-fs warning (device vda1): ext4_dx_add_entry:2184: Directory (ino: 384830) index full, reach max htree level :2 [1718.956798] EXT4-fs warning (device vda1): ext4_dx_add_entry:2188: Large directory feature is not enabled on this filesystem [10788.316073] EXT4-fs warning (device vda1): ext4_dx_add_entry:2184: Directory (ino: 384830) index full, reach max htree level :2 [10788.316075] EXT4-fs warning (device vda1): ext4_dx_add_entry:2188: Large directory feature is not enabled on this filesystem
Индексы каталогов в ext4 связаны с размером имени файла и количеством файлов. Таким образом, это ограничение может отличаться в вашей системе.
Следуя советам некоторых комментаторов, повторное выполнение теста 10M с реальными файлами JSON дает аналогичные результаты:
Чтение по-прежнему в 2 раза быстрее, а запись по-прежнему на 20%.
Ссылки: source v2 - raw results v2 - tune2fs -l output
DMke также сделал отличную вилку оригинального кода. Он добавил тесты того, как глубины каталогов работают друг с другом:
Вывод 2: придерживайтесь индивидуальной мудрости и используйте файловую систему с глубокими каталогами. Однако будьте осторожны с потерями производительности из-за слишком большого количества уровней каталогов.