Во время разработки одного проекта возникла необходимость хранить множество файлов (более 4 млн. штук). И их количество продолжало расти. Когда файлов стало более 6 млн., работать с ними стало затруднительно. Даже если разложить их по каталогам и создать разветвлённое дерево, обход даже части этих каталогов занимал часы. Разумеется, вначале никто не задумывался над тем, как все это хранить, и мы использовали обычный винт и ext4. В какой-то момент скорость чтения с этого раздела снизилась до 9MB/sec. Это слишком медленно. Экспериментальный переход на btrfs поднял скорость до 13MB, но такие показатели тоже не впечатляют. SSD для этого никто не собирался использовать да и объём уже перевалил за 1TB. Т.е. всё шло к использованию RAID'ов. Поскольку коммерческий успех проекта был под сомнением, то стоимость нужно было свести к минимуму. Следовательно, реализация должна была быть программной.
Итак, нужно небольшое хранилище — на одном сервере или компьютере, т.е. не более четырех дисков. Хранить нужно небольшие файлы — по 1-3Mb каждый.
Btrfs в нашем случае оказалась быстрее ext4, поэтому мы решили использовать именно ее.
Кандидатами на управление хранилищем стали raid0 и raid10. Raid0 — объективно самый быстрый, хотя некоторые считают, что raid10 быстрее. Raid10 теоретически может сравняться по скорости с raid0 при чтении. Но вот для записи — очень сомнительно. Да и без особого труда можно найти различные тесты производительности аппаратных raid’ов.
Главное преимущество raid10 — надежность — не так уж и очевидно для не очень важных данных. Тем не менее, если надо хранить много, то используют либо raid, либо lvm. Можно и по старинке — вручную распределить данные по винтам. Надёжность везде одинаковая. Теряем винчестер — теряем данные. В raid0 размер strip’а (chunk) настраивается, поэтому при небольшом размере файлов большую часть данных можно будет восстановить.
В качестве подопытных были взяты 4 hdd Western Digital Caviar Blue 1TB — пожалуй, одни из самых быстрых среди имеющихся в свободном доступе без завышения цены.
raid0 создаем следующим образом:
mdadm -v —create /dev/md0 —level=raid0 —raid-devices=4 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1
Создание происходит мгновенно, так как копировать и переразмечать нечего.
Сохраняем конфиг, чтоб при перезагрузке массив остался:
mdadm —examine —scan —config=mdadm.conf >> /etc/mdadm.conf
Создаём файловую систему:
#mkfs.btrfs -Lraid0 /dev/md0
WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using
fs created label raid0 on /dev/md0
nodesize 4096 leafsize 4096 sectorsize 4096 size 3.64TB
Btrfs Btrfs v0.19
Интересно то, что FS всё еще экспериментальная. Впрочем это нисколько не помешало разработчикам Fedora 18 сделать btrfs файловой системой по умолчанию.
Проведём быстрый тест на скорость:
# hdparm -t /dev/md0
/dev/md0:
Timing buffered disk reads: 2008 MB in 3.00 seconds = 669.11 MB/sec
В среднем скорость линейного чтения колеблется от 650 до 690MB/sec.
Это, для сравнения, быстрее чем любой sata3 SSD.
Полезный объём устройства 3,7TB
Двухдневный тест показал устойчивую скорость произвольного чтения и произвольной записи при операциях с файлами в 202MB/sec и 220MB/sec соответственно. Если ограничиться только чтением или только записью, то получаем 560MB/sec. Это устойчивые средние значения.
Весьма неплохо. Кстати, многие домашние SSD до этого не дотягивают.
Скорость весьма приличная на текущий момент. Поэтому собственно на нём и остановились. В случае, если один из винтов начнёт сыпаться, придётся остановить весь raid, скопировать посекторно данные на новый винт и вернуть raid в активное состояние. Вполне допустимо для не очень важного хранилища. Если оно внезапно станет важным, то можно будет повысить его надежность и общую отказоустойчивость при помощи drbd.
В процессе тестирования нередко наблюдались пиковые скорости чтения и записи в 700MB/sec. Но поскольку файлы у нас маленькие, то такие пики возникали при параллельном чтении множества файлов. Видимо сказывается размер chunk’а.
Для очистки совести проведём те же тесты с raid10.
Создание raid10:
mdadm -v —create /dev/md0 —level=raid10 —raid-devices=4 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1
Но тут придётся подождать какое-то время. Пару-тройку часов.
В результате имеем следующее:
# hdparm -t /dev/md0
/dev/md0:
Timing buffered disk reads: 1080 MB in 3.01 seconds = 359.07 MB/sec
Мягко говоря, разочаровывает. Точно такие же результаты были на raid0 с двумя дисками. Теоретическая возможность чтения с 4-х винтов в данном случае не проявляется.
Но линейная скорость хоть и показательна, но не так важна для нас. Важнее произвольный доступ к файлам.
И он составил 190MB/sec на чтение и 125MB/sec на запись.
Полное разочарование с записью, хотя скорость чтения сравнима с raid0. Напомню, что при этом мы еще и половину объёма дисков потеряем.
Есть еще один вариант программной реализации raid0, но уже средствами самой btrfs. В документации есть два параметра, которые могут повлиять на быстродействие и надёжность. Data type — способ хранения данных. Влияет и на скорость доступа и на надёжность сохранения данных. Есть варианты: raid0, raid1, raid10 и single. И metadata profile — способ хранения метаданных. Он в большей степени влияет на возможность восстановления данных в случае мелких сбоев. Есть варианты: raid0, raid1, raid10, single и dup. Собственно, наблюдаем уже знакомые raid0 и raid10. Третий параметр, который скромно заявляет о возможном росте производительности при работе с файлами до 1GB — mixed. Для нас его влияние не очевидно.
Параметры задаются при создании файловой системы.
# mkfs.btrfs -d raid0 -m raid1 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1
WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using
adding device /dev/sdd1 id 2
adding device /dev/sde1 id 3
adding device /dev/sdf1 id 4
fs created label (null) on /dev/sdc1
nodesize 4096 leafsize 4096 sectorsize 4096 size 3.64TB
Btrfs Btrfs v0.19
Если надумаете использовать mixed, то учтите, что типы хранения данных и метаданных должны быть одинаковыми.
Обратите внимание, что единого устройства, как при использовании raid, здесь не получается. Монтировать можно любой раздел из использованных для файловой системы. Например, mount /dev/sdc1 /mnt/raid0
В результате цифры получились весьма похожие с raid0 в исполнении md. Чтение 198MB/sec и запись 216MB/sec. Пики чтения чуть меньше 700MB/sec. Средняя скорость только чтения или только записи 660MB/sec, что очень приятно удивило.
При создании раздела с -m raid0 скорости совместного доступа немного возрастают. Чтение 203MB/sec и запись 219MB/sec. А вот раздельные чтение/запись немного уменьшились: 654MB/sec.
В общем и целом можно рекомендовать использовать чистый btrfs без дополнительных прослоек, которые могут быть и точками отказа.
Еще существует возможность хранения данных в lvm в режиме striping. Это очень близкий аналог raid0. Однако, у автора с lvm не складываются отношения уже не первый год. Поэтому такой вариант повышения производительности не рассматривался чисто по субъективным причинам.
Ну и напоследок — неудачный эксперимент с raid10 в btrfs:
# mkfs.btrfs -L raid10 -d raid10 -m raid10 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/
sdf1
WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using
adding device /dev/sdd1 id 2
adding device /dev/sde1 id 3
adding device /dev/sdf1 id 4
fs created label raid10 on /dev/sdc1
nodesize 4096 leafsize 4096 sectorsize 4096 size 3.64TB
Btrfs Btrfs v0.19
Создание заняло пару секунд. Но это вызвало скорее вопросы, нежели радость.
Чтение — 122MB/sec и запись — 127MB/sec. Раздельные чтение/запись — 657MB/sec. Т.е. не годится для нашей задачи, хотя скорость раздельных операций и удивляет и радует.
Для душевного успокоения коллег был проведён тест с ext4 поверх raid0. Результаты ожидаемы.
# mkfs.ext4 /dev/md0 -L raid0
mke2fs 1.42.5 (29-Jul-2012)
Filesystem label=raid0
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=256 blocks, Stripe width=1024 blocks
244195328 inodes, 976760832 blocks
48838041 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
29809 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848, 512000000, 550731776, 644972544
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
Проведём небольшой тюнинг, который благоприятно влияет на производительность:
tune2fs -O extents,uninit_bg,dir_index /dev/md0
tune2fs -o journal_data_writeback
tune2fs -m 0 /dev/md0
mount /dev/md0 raid0 -o acl,user_xattr,noatime,nodiratime,barrier=0,commit=0
Результаты плачевные для нашей задачи. Чтение и запись — 60MB/sec и 86MB/sec. Только чтение или только запись — 535MB/sec.
Выводы очевидны. Btrfs намного выгоднее для нашей задачи чем ext4, а raid0 быстрее, чем raid10.
Осталось только добавить, что кроме рабочих обработчиков данных использовались и сторонние утилиты.
Для синтетических тестов использовались stress и bonnie++
Фактические данные о чтении/записи собирались при помощи sysstat.
Автор: webnames