Хабрахабр

Что не так с Copy-on-Write под Linux при копировании

В данный момент это: BTRFS, XFS и OCFS2. Предупреждение: эта статья относится ко всем CoW файловым системам в Linux, поддерживающим reflink при копировании.

Прошу воздержаться от холиваров о том какая ФС лучше: Btrfs, XFS, Reiser4, NILFS2, ZFS или какая-то неупомянутая.

Предыстория

  • 21 июля 2001 года — Namesys публикует анонс Reiser4.
  • 20 ноября 2003 — Namesys публикует некоторые бенчмарки Reiser4.
  • 24 августа 2004 — Namesys делает публичный релиз Reiser4.
  • 14 сентября 2004 — анонс ZFS.
  • 16 ноября 2005 — ZFS включена в 27 сборку OpenSolaris.
  • сентябрь 2006 — Ханс Райзер арестован за убийство жены, начало конца Namesys
  • 12 июня 2007 — анонс Btrfs Крисом Мейсоном (бывший сотрудник Namesys).
  • 22 сентября 2011 — В ZFSonLinux появился тикет с запросом на реализацию reflink.
  • 2012 — Btrfs признана стабильной Oracle Linux и SUSE Linux Enterprise
  • 21 января 2013 — метка экспериментальности была снята c Btrfs в исходных кодах ядра Linux.
  • May 2019 — Btrfs удалена из RHEL 8 (подозревается скрытые политические причины, так как Btrfs продвигается Oracle)

Ожидания от копирования в CoW-файловых системах

Когда в 2001 году анонсировалась Reiser4, я был вдохновлён и увлечён возможностями Copy-on-Write. Подумать только, мы можем легко и просто иметь сколько угодно копий разных проектов, а физически диск будет хранить только отличия между ними!

Это тогда выглядело панацеей для создания аккаунтов для shared-хостинга, а сейчас оптимальным решением для лёгких виртуальных машин и контейнеров. К тому же скорость копирования должна была неприлично вырасти. Ведь мы могли бы не тратить место на одинаковые файлы, вместе с тем позволяя пользователям их беспроблемно менять.

Может всё-таки история зависит от конкретной личности? Однако у Ханса Райзена поехала крыша и он убил жену, а его детище (скорее всего по политическим причинам) не включили в ядро.

Поэтому внедрение ZFS в Linux оказалось надолго заторможено. ZFS была опубликована под несовместимой с Linux лицензией, и потому не вошла в ядро.

И только через 6 лет после анонса она была признана разработчиками ядра Linux стабильной. После этого я стал ждать Btrfs.

После этого я не торопился использовать Cow-системы, так как сама парадигма Copy-on-Write предполагает повышенную фрагментацию, потому что изменения данных каждый раз записываются в новое место.

Для HDD фрагментация убивает производительность, так как процесс перепозиционирования блока считывающих головок — очень длительная операция.

Поэтому лично я откладывал внедрение btrfs на своих машинах, пока они не перешли на SSD.

Замечу, что SSD тоже не любят фрагментацию, всем известно что для SSD линейная запись/чтение могут быть в десятки раз быстрее, чем случайный доступ.

Но производительность фрагментированного SSD падает не так драматически, как у HDD.

Итак, что со скоростью копирования при CoW?

И вот, наконец, настал тот час. Когда SSD стали достаточно надёжны, я стал вовсю использовать CoW-файловые системы. А конкретнее — Btrfs и Nilfs2.

Осваивая захватывающие возможности снимков (снепшотов), на время я забыл о моих ожиданиях из 2000-х годов о сверхбыстром копировании файлов.

И к моему великому разочарованию не увидел никакого прироста скорости от CoW при копировании. Через некоторое время я решил провести тесты. Вот результат на SATA SSD:

time cp -a /usr /usr1
real 0m15,572s
user 0m0,240s
sys 0m4,739s

Оказалось, что для использования CoW нужно указывать специальный ключ.

time cp -a --reflink=auto /usr /usr2 real 0m3,166s
user 0m0,178s
sys 0m2,891s

Только в этом случае мы видим 5-кратное преимущество. К слову говоря, размер преимущества неограниченно растёт при увеличении длины файлов. В папке /usr, которую я копировал, в основном мелкие файлы.

Ведь для этого она и создавалась! Я был несказанно удивлён, почему ключевое преимущество CoW-файловой системы не используется по умолчанию.

Но подобный результат вы получите и с любой другой CoW-файловлй системой, поддерживающей reflink. В данном случае я тестировал копирование на Btrfs-разделе.

В чём проблема, Билли?

Проблема в cp. По умолчанию она не использует CoW при копировании. Хотя может.

Почему разработчики coreutils было принято столь неоднозначное решение, которое перечеркнуло половину преимуществ CoW файловых систем?

Оказывается, так решил Pádraig Brady, ответственный за развитие GNU coreutils.

Вот его логика:

  1. По умолчанию cp не использует CoW, так как кто-то может использовать копирование для того, чтобы повысить вероятность сохранения файла на диске после разрушения файловой системы.
  2. С точки зрения производительности, если есть некий чувствительный к задержкам процесс, вы можете захотеть, чтобы основная запись была сделана именно во время копирования, так если это произойдёт потом, то может возникнуть лаг при перепозиционировании головок жёсткого диска. Обратите внимание, начиная с версии 8.24 coreutils, mv по умолчанию использует опцию reflink.

Текст ответа Pádraig Brady на английском

Also for performance reasons you may want the writes to happen at copy time rather than some latency sensitive process working on a CoW file and being delayed by the writes possibly to a different part of a mechanical disk. It's not the default since for robustness reasons one may want a copy to take place to protect against data corruption. 24 mv will reflink by default, since it doesn't have the above constraints. Note that from coreutils v8.

В плане скорости для mv практически нет никакой пользы от CoW при перемещении файлов. В пределах одной файловой системы mv практически всегда работает очень быстро.

Поставив по-другому несколько буковок в исходном коде программы, можно замедлить копирование у десятков/сотен миллионов пользователей (тут нужно учесть, что сейчас большинство людей пользуются облачными сервисами в том или ином виде, даже если у них нет компьютера), уменьшить эффективность использования накопителей и повысить их продажи по всему миру. Опять возникает вопрос о влиянии личности на историю.

Разбор аргументов Pádraig

В первом аргументе есть кое-какой смысл. Неискушенные пользователи действительно могут делать бакапы ценных файлов на одной и той же файловой системе.

Если почитать дальнейшие комментарии насчёт лагов от Pádraig, то обнаружится, что он имел в виду ситуации с базами данных, когда при записи в существующий файл может возникнуть задержка из-за того, что файловая система будет искать свободное место. Второй аргумент. Поэтому, по моему мнению, второй аргумент несостоятелен. Но в случае CoW-файловой системы всегда будет искаться новые сектора для записи в силу природы CoW, как заметил Jan Kanis.

Для избежания этого нужно для базы изначально создавать пустой каталог с отключенным CoW. Однако на CoW системах действительно можно получить задержку или даже ошибку “Закончилось пространство” при записи в файл базы данных.

Отключается CoW на каталоге/файле так:

chattr +C /dir/file
chattr +C /dir/dir

Есть ещё опция монтирования nodatacow. Она будет применена ко всем новосоздаваемым файлам.

Как всё-таки быть, если мы хотим по умолчанию использовать CoW при копировании?

  1. Радикальный путь — это патчить coreutils. Возможно, создать свой пакет в своём частном репозитории.

    Патчим файл cp.c:

    -x->reflink_mode = REFLINK_NEVER;
    +x->reflink_mode = REFLINK_AUTO;

  2. Менее радикальное решение — это прописать алиас cp для вашей оболочки. Для bash, например:

    В папке /etc/profile.d создаём файлик cp_reflink.sh c содержимым:

    #!/bin/bash
    alias cp='cp --reflink=auto'

    Это решение будет работать почти во всех случаях, когда к cp идёт обращение из оболочки по имени. Но если в скриптах будет использоваться /bin/cp, то алиас не сработает и копирование будет происходить по-старинке.

Выводы

С наступление эпохи повсеместной виртуализации и SSD стало очень актуально использовать CoW-файловые системы. Они удобны для создания снимков, быстрого копирования. Фактически, при использовании CoW при копировании мы автоматически делаем дедупликацию данных.

Сейчас только 3 файловых системы поддерживают этот тип копирования: BTRFS, XFS и OCFS2.

Я искренне надеюсь, что поддержку reflink допилят в ZFS и NILFS2, так как по внутренним механизмам они и так поддерживают CoW.

Однако во всех дистрибутивах Linux CoW при копировании файлов отключена, и нам нужно или явно указывать соответвующие ключи, или использовать различные трюки типа алиасов или патчей.

С момента анонса Reiser4 прошло уже 18 лет, однако до сих пор лёгкое CoW копирование не вошло в нашу жизнь повсеместно.

P.S. Docker и CoW

А вы знаете что Docker поддерживает btrfs для своего хранилища? Эту опцию нужно включать. Она не выбрана по умолчанию.

CoW файловая система в теории является идеальным дополнением к лёгкой виртуализации, когда разные виртуальные машины используют одно и то же ядро.

На мой взгляд, гораздо более органично чем OverlayFS и Aufs, которые представляют из себя технологические костыли для имитации CoW.

Для использования Btrfs в Docker нужно:

  1. В свежей (без образов и виртуальных машин) инсталляции Docker примонтировать отдельный том Btrfs к /var/lib/docker
  2. Добавить опции в конфигурационный файл запуска Docker

Для Gentoo и Calculate Linux это /etc/conf.d/docker

DOCKER_OPTS="--storage-driver btrfs --data-root /var/lib/docker"

А вот полная инструкция для всех дистрибутивов.
Благодарности:

  • Компании RUVDS за поддержку и возможность публикации в своем блоге на Хабре.
  • За изображение TripletConcept.

P.P.S. Замеченные ошибки направляйте в личку. Повышаю за это карму.
Вы можете поэкспериментировать с CoW-файловыми системами заказав виртуальную машину у RUVDS по купону ниже.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»