Как стать автором
Обновить
2464.57
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

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

Время на прочтение 7 мин
Количество просмотров 38K


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

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


Предыстория


  • 21 июля 2001 года — Namesys публикует анонс Reiser4. DARPA спонсирует разработку.
  • 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.
  • май 2019 — Btrfs удалена из RHEL 8 (подозревается скрытые политические причины, так как Btrfs продвигается Oracle)

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


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

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

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

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

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

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

После этого я не торопился использовать 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-файловой системы не используется по умолчанию. Ведь для этого она и создавалась!

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

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


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

Вы можете сказать — я не использую cp. Однако под капотом у Linux он используется практически везде. Многие программы, когда им нужно что-то скопировать, используют cp, а не свои «велосипеды».

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

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

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

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

Текст ответа Pádraig Brady на английском
It's not the default since for robustness reasons one may want a copy to take place to protect against data corruption. 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. Note that from coreutils v8.24 mv will reflink by default, since it doesn't have the above constraints.

В плане скорости для 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, то алиас не сработает и копирование будет происходить по старинке.

Дистрибутивы Linux c поддержкой reflink


Состояние на 18 января 2021 года:

Файловые менеджеры и reflink


Состояние на 31 октября 2019 года:

  • Midnight Commander — поддерживает.
  • Krusader — не поддерживает.
  • Dolphin — не поддерживает.
  • Nautilus — не поддерживает.
  • Nemo — поддерживает.

По слухам на 18 января 2021 года:

  • Dolphin и Nautilus уже поддерживают копирование с reflink. Точные минимальные версии с поддержкой reflink автору не известны.

Языки программирования, системные вызовы и reflink


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

Системный вызов sendfile не использует reflink.
cp использует системный вызов ioctl с флагом FICLONE.

Я думаю, если нужно в коде что-то скопировать, то желательно делать это как делает cp или просто вызвать cp --reflink=auto.

Выводы


С наступлением эпохи повсеместной виртуализации и 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"

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

Дополнения из комментариев


XFS и CoW


constb (источник): На XFS тоже не всегда поддерживается CoW. Нужно создавать файловую систему c mkfs.xfs -m reflink=1.
Уже на созданной ФС «включить» поддержку CoW нельзя. плюс, на ядрах до 4.11 включение этой опции вызывает красные варнинги в dmesg о том что фича – экспериментальная.

MacOS и CoW


MMik (источник): В OS X подобная опция команды cp – это -c.

Она включает использование атомарного системного вызова clonefile(), который создаёт запись в файловой системе о новом файле, в котором ссылки на блоки данных идентичны оригиналу. Копируются атрибуты и расширенные атрибуты файла, записи списков контроля доступа (ACL), за исключением информации о владельце файла и со сбросом setuid/setgid битов. Работает в пределах одной файловой системы, требует поддержки файловой системой (атрибут ATTR_VOL_CAPABILITIES, флаг VOL_CAP_INT_CLONE).

Поддерживается начиная с OS X 10.12 (Sierra) и только в файловой системе APFS.


Благодарности:

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

P.P.S. Замеченные ошибки направляйте в личку. Повышаю за это карму.



Вы можете поэкспериментировать с CoW-файловыми системами, заказав виртуальную машину у RUVDS по купону ниже.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+75
Комментарии 113
Комментарии Комментарии 113

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds