О bcache
2015-01-10
Решил я переустановить Убунту. Да. Иногда случается так, что линуксы тоже надо переустанавливать. Причин для этого было у меня две.
Во-первых, пришла пора переходить на 64-битную систему. 32-битная у меня жила и обновлялась (на этом железе) года два. Потому что всякая проприетарная фигня, например для организации митингов, если и существует под Линукс, то только в 32-битном варианте. Ну а теперь оказалось, что и Docker, который пришла пора потыкать, существует только в 64-битном варианте. И Android Emulator в 32-битном варианте объявлен устаревшим.
Ну а последние Убунты, вслед за Дебианом, наконец-то стали multiarch. Каким давным давно являются Редхаты да Центосы. Теперь в системе спокойно могут сосуществовать 64-битные и 32-битные библиотеки и приложения. Значит, можно ставить 64-битную систему и иметь полную поддержку 32-бит. Кстати, это наш Скайп остается 32-битным, и прекрасно работает в 64-битной Убунте (впрочем, чуток подшаманить ради красоты нужно).
Во-вторых,
у моего любимого ультрабука
очень интересная ситуация с дисками.
Есть 24 гига SSD.
И есть 500 гигов HDD.
В случае Windows все понятно,
SSD диск используется как кэш и все хорошо.
В случае Убунты два года назад я решил поступить проще:
засунуть на SSD систему и свап,
а на HDD поместить /home
.
Такой простейший подход себя не оправдал.
Система-то грузится махом.
Но вот вход в иксы,
да запуск какого-нибудь браузера —
не быстры.
Совсем не быстры.
Ибо нужно читать кучу мелких файлов с HDD.
Самый радикальный способ, конечно, — это выкинуть HDD и воткнуть на его место SSD. Но это сильно дорого получается, чтобы остаться с пятьюстами гигами. К тому же эти 24 гига встроенного SSD все-равно никуда не выкинешь, они на плате распаяны.
В общем, нужен кэш на SSD для кэширования доступа к HDD.
В Линуксе для этого есть два с половиной способа
(из поддерживаемых Ядром из коробки).
Но ни один из них не настраивается из коробки штатными инсталляторами (Убунты).
А еще захотелось расстаться с, внезапно, устаревшим
MBR.
И поиграться с более современным и надежным
GPT.
Где нет дурацких веселий про четыре основных раздела плюс логические разделы :)
И где-то рядом стоит UEFI,
который новая майкро молодежная замена BIOS.
Но он скорее мешался, чем что-то дал.
Итак, кэши.
Самый старый — dm-cache. В составе Ядра с версии 3.9, с апреля 2013. Является модулем device mapper, т.е. довольно штатным способом расширения функционала Ядра. В dm-cache пугает сложность настройки: кроме самого диска, который кэшируем, нужно еще два отдельных устройства для самого кэша и метаданных кэша. Причем размер метаданных нужно еще заранее правильно подсчитать.
Для любителей LVM dm-cache впилили в него. Возможно, это самый правильный способ нарисовать нужный мне кэш. Но я не хотел заморачиваться еще и с LVM. Все же это ноутбук, и шанс добавить в систему новый диск с тем, чтобы расширить имеющиеся разделы на него, для чего, в моем понимании, и нужен LVM, стремится к нулю. А если уж менять диск, то от наличия LVM профита нет.
И, наконец, есть bcache.
Он вошел в Ядро версии 3.10, в июле 2013.
Его проще настраивать: нет нужды в отдельном разделе для метаданных.
Он точно умеет кэшировать несколько HDD в один SSD,
а именно такого мне хотелось:
иметь один кэш для двух разделов — корня ФС и /home
.
Кто быстрее, dm-cache, bcache или их еще не вошедшие в Ядро аналоги вроде Flashcache и EnhanceIO — непонятно. Каждый тянет одеяло на себя. Но bcache вроде более явно высказывается об особенностях своих алгоритмов и бережном отношении к SSD.
В общем, решил попробовать поднять bcache. И, если заведется, на нем и остановиться.
У bcache есть не очень приятная багофича. Его нельзя поднять поверх существующих разделов. Он требует явного переформатирования разделов с потерей содержащихся на них данных. Он создает свой суперблок. Делается это для того, чтобы нельзя было получить доступ к этим разделам, минуя bcache. Чтобы избежать возможного нарушения целостности кэша. Ничего особо страшного тут нет, ибо bcache уже есть в ядре, а работоспособность он сохраняет и при отсутствии доступа к собственно кэшу, тупо переходит в режим прямой работы с кэшируемым устройством.
Так что пришлось два дня аккуратно упаковывать родной /home
в стопочку архивов
и складывать на внешний диск.
Оказалось, несколько десятков гигабайт бесценного барахла накопилось.
Самая сложная часть операции :)
Есть, конечно, способ сконвертировать раздел в bcache. Но не так-то просто оказалось эти скрипты запустить в Убунте 14.04, давно они не обновлялись. К тому же тут нет никаких гарантий, а значит, бэкапы все равно нужны.
А еще GRUB не умеет bcache,
поэтому нужно создавать отдельный раздел для /boot
.
И вообще, установщики ОС тоже не умеют bcache.
Поэтому пришлось сделать финт ушами.
Сначала поставить Убунту в раздел, который потом станет свапом.
Затем в установленной системе настроить bcache и перенести систему (и /home
) на bcache разделы.
И напоследок, после второй перезагрузки,
засунуть свап в тот самый раздел, где он должен быть.
С загрузкой пришлось дополнительно помучаться.
С одной стороны, я собрался делать GPT разметку дисков.
С другой стороны, у нас имеется два варианта загрузки:
классический BIOS и новый UEFI.
Тестировал я установку bcache в VirtualBox, где поддержка UEFI экспериментальна и не сработала.
Поэтому пришлось грузиться в GPT раздел из BIOS.
GRUBу в этом случае нужен
дополнительный раздел с флагом bios_grub
,
куда он помещает свое тельце.
(В случае MBR он размещается в первых секторах, которые по стандарту вроде как не заняты,
а в GPT такой роскоши нет).
Однако ультрабук отказался грузить GPT диск в BIOS режиме.
Пришлось грузиться в UEFI.
GRUBу тогда нужен fat32(!) раздел для EFI.
Получилась кучка вспомогательных разделов,
которые я разместил на SSD,
но также создал их и на HDD,
чтобы в случае извлечения этого HDD из ультрабука,
его тоже можно было бы сделать потом загрузочным.
Итак, бэкапы мы сделали. Теперь берем загрузочную флешку с Ubuntu 14.04 LTS 64bit и грузимся с нее в режиме UEFI. Инсталлятор пока не запускаем, а балуемся с GParted. Создаем на каждом диске новую GPT таблицу разделов. Как-то так:
- sdb, SSD диск
- sdb1, BIOS boot раздел, 1MB, без файловой системы, поставить флаг
bios_grub
- sdb2, UEFI boot раздел, 200MB, fat32, поставить флаг
boot
- sdb3,
/boot
, 250MB, ext4 - sdb4, будет свап, но сначала сюда поставим систему, 6GB, отформатировать в ext4
- sdb5, кэш bcache, оставшиеся 17GB SSD диска, без файловой системы
- sdb1, BIOS boot раздел, 1MB, без файловой системы, поставить флаг
- sda, HDD диск
- sda1, BIOS boot раздел, 1MB, без файловой системы, резерв на случай изъятия диска
- sda2, UEFI boot раздел, 200MB, fat32, не форматировать, резерв на случай изъятия диска
- sda3, резерв для
/boot
, 250 MB, не форматировать, резерв на случай изъятия диска - sda4,
/
, 20GB, ext4, сейчас оставить без форматирования - sda5,
/home
, оставшиеся 478GB HDD диска, ext4, сейчас оставить без форматирования
Ставим Убунту в тот самый раздел, который потом сделаем свапом.
- sdb3 —
/boot
- sdb4 —
/
Загрузчик поставить в sdb
.
Проигнорировать предупреждения об отсутствии свапа и наличия файловой системы в /boot
.
Перезагружаемся, работаем в установленной системе (которая сейчас занимает один раздел на SSD диске).
Ставим bcache-tools
(далее все команды — из-под рута):
# add-apt-repository ppa:g2p/storage
# apt-get update
# apt-get install bcache-tools
Создать bcache не просто, а очень просто:
# make-bcache -C /dev/sdb5 -B /dev/sda4 /dev/sda5
Флагом -C
указывается устройство-кэш.
Флагом -B
указываются кэшируемые (backed) устройства.
Если все сделать одной командой,
то сразу получится то, что нам нужно:
два раздела на HDD и один кэш для них на SSD.
Если на этих разделах имеется какая-то файловая система
(ну например, вы все же отформатировали что-то лишнее при разметке диска),
make-bcache
не будет её удалять.
Придется почистить как-то так: wipefs -a /dev/sda4
.
А потом связывать устройства-кэши с кэшируемыми устройствами,
как описано в документации.
Главное тут понять,
что на каждое кэшируемое устройство (раздел HDD),
появляется свое устройство /dev/bcacheX
.
И, так называемый CSET-UUID
кэша нужно приаттачить к каждому из них.
Как-то так:
# ls /sys/fs/bcache/
4ed92e55-683a-49b2-8043-39d5bde433f9 register register_quiet
# echo 4ed92e55-683a-49b2-8043-39d5bde433f9 > /sys/block/bcache0/bcache/attach
# echo 4ed92e55-683a-49b2-8043-39d5bde433f9 > /sys/block/bcache1/bcache/attach
Создаем файловые системы:
# mkfs.ext4 /dev/bcache0
# mkfs.ext4 /dev/bcache1
Копируем /home
и /
на новые места на bcache устройствах.
Тут главное не запутаться с номерами этих устройств.
Порядок нумерации может быть произвольным (но постоянным).
Смотрите на размер устройств, или же смотрите, например, ls /sys/block/bcache0/slaves
.
# mkdir OLD NEW HOME
# mount /dev/sdb4 OLD
# mount /dev/bcache0 NEW #должен быть новый кэшированный рут
# rsync -a OLD/ NEW/
# mount /dev/bcache1 HOME
# rsync -a /home/ HOME/
Готовимся обновлять GRUB:
# mount /dev/sdb3 NEW/boot
# mount /dev/sdb2 NEW/boot/efi
# mount -o bind /dev NEW/dev
# mount -t proc none NEW/proc
# mount -t sysfs none NEW/sys
# chroot NEW
Нужно найти UUIDы наших bcache устройств, а также UUID старого корня (который станет свапом):
# ls -l /dev/disk/by-uuid/ | grep bcache
lrwxrwxrwx 1 root root 13 Jan 5 21:48 6538fd23-8f53-4651-adc7-43c494e75f67 -> ../../bcache1
lrwxrwxrwx 1 root root 13 Jan 5 21:48 dfc55722-a89c-4026-b1d2-758ec336017a -> ../../bcache0
# ls -l /dev/disk/by-uuid/ | grep sdb4
lrwxrwxrwx 1 root root 10 Jan 5 21:48 b0b3a280-329e-42a9-91fd-09fde7e8977f -> ../../sdb4
Любимым текстовым редактором правим /etc/fstab
:
- меняем UUID корневого раздела, со старого sdb4 на новый bcache0 (вот для чего мы их находили)
- добавляем запись для
/home
Получается что-то вроде:
UUID=dfc55722-a89c-4026-b1d2-758ec336017a / ext4 errors=remount-ro 0 1
UUID=6538fd23-8f53-4651-adc7-43c494e75f67 /home ext4 defaults 0 1
Любимым текстовым редактором правим /boot/grub/grub.cfg
.
Нужно тщательно и аккуратно заменить вхождения UUID старого корня (на sdb4) на UUID нового корня (на bcache0).
Ставим GRUB:
# grub-install /dev/sdb
Если все ок, то все ок. Перезагружаемся. Превращаем старый рут в свап:
# mkswap /dev/sdb4
# swapon /dev/sdb4
И добавляем свап в /etc/fstab
:
UUID=b0b3a280-329e-42a9-91fd-09fde7e8977f none swap defaults 0 0
Ну и все. Можно восстанавливать бэкапы взад.
Проследить за работой bcache можно через sysfs:
% cat /sys/block/bcache*/bcache/state
clean
clean
% ls /sys/block/bcache0/bcache/stats* -d -1
/sys/block/bcache0/bcache/stats_day
/sys/block/bcache0/bcache/stats_five_minute
/sys/block/bcache0/bcache/stats_hour
/sys/block/bcache0/bcache/stats_total
% ls /sys/block/bcache0/bcache/stats_day/ -1
bypassed
cache_bypass_hits
cache_bypass_misses
cache_hit_ratio
cache_hits
cache_miss_collisions
cache_misses
cache_readaheads
% cat /sys/block/bcache*/bcache/stats_day/cache_hit_ratio
78
68
Если, кроме оптимизации чтения, хочется покэшировать и запись, можно поиграть с режимами:
% cat /sys/block/bcache0/bcache/cache_mode
[writethrough] writeback writearound none
Итак,
раньше на SSD был корень, а /home
был на HDD.
Теперь и то и другое — на HDD,
но кэшировано через SSD.
Причем кэшируются только операции чтения,
а запись идет сразу и в кэш и на жесткий (writethrough).
По субъективным ощущениям система грузится с прежней скоростью,
а вот иксы, браузер, Идея стартуют быстрее.
Пакеты ставятся медленнее (потому что запись в корень стала медленнее).
Прошла неделя, полет нормальный.
P.S. А еще есть btier.