Zfs проверка на ошибки

Неспешно прикидывая таблицу функциональности NAS обнаружил в своих инструкциях досадный пробел. Данные надо не просто хранить. Хорошо бы время от времени проверять, что всё в порядке. Ведь холодные данные на дисках имеют свойство незаметно портиться, «протухать». К счастью, у нас на NAS zfs, умеющий адресовать эту проблему.Сегодня обсудим как.

Немного теории
Перевод из Вики по ссылке выше

Проведённое NetApp исследование в реальной жизни на более чем 1,5 млн жестких дисков в течение 41 месяцев выявило более 400 000 примеров протухших данных, из которых более 30 000 не были обнаружены контроллерами аппаратных RAID. Еще одно исследование, проведенное ЦЕРН в течение шести месяцев и с участием около 97 петабайт данных, показало, что около 128 мегабайт данных были необратимо повреждены.

Но это на RAID контроллерах и дисках корпоративного класса. Ваши и мои данные на десктопном железе протухают несколько быстрее.
Традиционное решение проблемы проверки целостности данных — хранение вместе с ними контрольной суммы. Считываем данные, сверяем суммы, если OK — считаем данные не повреждёнными.
А традиционное решение проблемы восстановления повреждённых данных — избыточность. Хранение 2 и более копий (зеркало, как пример RAID1) и расчёт, хранение и сличение кодов чётности ( как пример — RAID5).

Одно из важнейших положительных свойств ZFS состоит в том, что и проверка целостности и восстановление повреждений (если есть избыточность — mirror или raidz) производится автоматически на уровне файловой системы при любом чтении данных. Но читать все данные не всегда удобно. Есть команда scrub (от англ. чистить, мыть, скрести)

ВАЖНО. Во время скраба пул доступен, но его производительность уменьшается. Хотя приоритет — за другими задачами. Поэтому, к примеру, качать с-на пул торренты и одновременно делать ему скраб идея так себе. Работать будет, но долго и с избыточной нагрузкой на диски.

На практике
Из командной строки вызывается
zpool scrub Pool
— для пула по имени Pool
Если дать ключ -s текущий скраб будет остановлен
zpool scrub -s Pool

В nas4free вызов команды zpool scrub выведен и в вебгуй
Через Disks|ZFS|Pools|Tools скраб можно запустить (и остановить при необходимости)

После запуска результат можно посмотреть через
zpool status
в командной строке
Или в Disks|ZFS|Pools|Information в вебгуе

На картинке выше где scan: сказано, что идёт scrub, но так как он только начался, оставшееся время определить нельзя, надо подождать. Со временем скорость растёт, но для больших пулов полная проверка запросто может продлиться порядка суток. Скорость зависит от
— производительности процессора
— заполненности пула (в отличие от аппаратных RAID пустое место НЕ читается)
— скорости дисков. Особенно если диск при смерти, скраб может затянуться очень надолго.

Я рекомендую после запуска скраба взглянуть на статус сразу и ещё раз минут через пять. В норме все три правых столбца должны быть нулями. Но нередко там появляются небольшие цифры — это как раз сообщение о том, что скраб проверяет и по возможности исправляет данные (и метаданные).

Если на одном из дисков лезет несколько десятков (и более) ошибок — у вас проблема. Скорее всего (в этом порядке) SATA кабель, сам диск, порт контроллера подыхает и нуждается в замене. Либо диску не хватает питания.
Советую остановить скраб и взглянуть в логи, на смарт этого диска и поискать корень проблемы.

Если десятки (и более) ошибок лезут на ВСЕХ дисках — НЕМЕДЛЕННО ВЫКЛЮЧАЙТЕ СКРАБ, а затем и весь NAS. Хорошие шансы, что у вас битая память. Проверяйте, гоняйте мемтест. Хотя по некоторым практическим примерам ZFS удаётся отработать львиную долю, более 99%, ошибок вызванных сбоями в памяти, всё же битая память без контроля чётности — годный способ загубить всю информацию на пуле при скрабе. Именно поэтому в идеальном мире (и в корпоративной практике) ZFS используют на ECC (то есть с аппаратным контролем чётности) памяти. Впрочем, как и остальные файловые системы. Но Intel решила, что домашний пользователь рылом не вышел для ECC. А AMD стала слишком слаба, чтобы спорить хотя было время…

Кстати, скраб можно запускать по крону. Но именно из-за возможности вляпаться в битую память я этого делать НЕ советую, если память у вас не ECC. Да, это крайне маловероятная ситуация. Битая память должна почти работать. Шалить самую малость, не вешать систему. Но всё же гадить. Поэтому у сотен камрадов, которые общаются в профильной ветке на хоботе, такого не было, чтоб битая память именно и только на zfs повлияла. Но в Сети я выловил пару сообщений. Так что хоть и крайне маловероятно — но бережёного…

И, наконец, как часто делать скраб? IMHO в домашней практике не чаще раза в месяц и не реже раза в год на каждом из пулов.

Неспешно прикидывая таблицу функциональности NAS обнаружил в своих инструкциях досадный пробел. Данные надо не просто хранить. Хорошо бы время от времени проверять, что всё в порядке. Ведь холодные данные на дисках имеют свойство незаметно портиться, «протухать». К счастью, у нас на NAS zfs, умеющий адресовать эту проблему.Сегодня обсудим как.

Немного теории
Перевод из Вики по ссылке выше

Проведённое NetApp исследование в реальной жизни на более чем 1,5 млн жестких дисков в течение 41 месяцев выявило более 400 000 примеров протухших данных, из которых более 30 000 не были обнаружены контроллерами аппаратных RAID. Еще одно исследование, проведенное ЦЕРН в течение шести месяцев и с участием около 97 петабайт данных, показало, что около 128 мегабайт данных были необратимо повреждены.

Но это на RAID контроллерах и дисках корпоративного класса. Ваши и мои данные на десктопном железе протухают несколько быстрее.
Традиционное решение проблемы проверки целостности данных — хранение вместе с ними контрольной суммы. Считываем данные, сверяем суммы, если OK — считаем данные не повреждёнными.
А традиционное решение проблемы восстановления повреждённых данных — избыточность. Хранение 2 и более копий (зеркало, как пример RAID1) и расчёт, хранение и сличение кодов чётности ( как пример — RAID5).

Одно из важнейших положительных свойств ZFS состоит в том, что и проверка целостности и восстановление повреждений (если есть избыточность — mirror или raidz) производится автоматически на уровне файловой системы при любом чтении данных. Но читать все данные не всегда удобно. Есть команда scrub (от англ. чистить, мыть, скрести)

ВАЖНО. Во время скраба пул доступен, но его производительность уменьшается. Хотя приоритет — за другими задачами. Поэтому, к примеру, качать с-на пул торренты и одновременно делать ему скраб идея так себе. Работать будет, но долго и с избыточной нагрузкой на диски.

На практике
Из командной строки вызывается
zpool scrub Pool
— для пула по имени Pool
Если дать ключ -s текущий скраб будет остановлен
zpool scrub -s Pool

В nas4free вызов команды zpool scrub выведен и в вебгуй
Через Disks|ZFS|Pools|Tools скраб можно запустить (и остановить при необходимости)

После запуска результат можно посмотреть через
zpool status
в командной строке
Или в Disks|ZFS|Pools|Information в вебгуе

На картинке выше где scan: сказано, что идёт scrub, но так как он только начался, оставшееся время определить нельзя, надо подождать. Со временем скорость растёт, но для больших пулов полная проверка запросто может продлиться порядка суток. Скорость зависит от
— производительности процессора
— заполненности пула (в отличие от аппаратных RAID пустое место НЕ читается)
— скорости дисков. Особенно если диск при смерти, скраб может затянуться очень надолго.

Я рекомендую после запуска скраба взглянуть на статус сразу и ещё раз минут через пять. В норме все три правых столбца должны быть нулями. Но нередко там появляются небольшие цифры — это как раз сообщение о том, что скраб проверяет и по возможности исправляет данные (и метаданные).

Если на одном из дисков лезет несколько десятков (и более) ошибок — у вас проблема. Скорее всего (в этом порядке) SATA кабель, сам диск, порт контроллера подыхает и нуждается в замене. Либо диску не хватает питания.
Советую остановить скраб и взглянуть в логи, на смарт этого диска и поискать корень проблемы.

Если десятки (и более) ошибок лезут на ВСЕХ дисках — НЕМЕДЛЕННО ВЫКЛЮЧАЙТЕ СКРАБ, а затем и весь NAS. Хорошие шансы, что у вас битая память. Проверяйте, гоняйте мемтест. Хотя по некоторым практическим примерам ZFS удаётся отработать львиную долю, более 99%, ошибок вызванных сбоями в памяти, всё же битая память без контроля чётности — годный способ загубить всю информацию на пуле при скрабе. Именно поэтому в идеальном мире (и в корпоративной практике) ZFS используют на ECC (то есть с аппаратным контролем чётности) памяти. Впрочем, как и остальные файловые системы. Но Intel решила, что домашний пользователь рылом не вышел для ECC. А AMD стала слишком слаба, чтобы спорить хотя было время…

Кстати, скраб можно запускать по крону. Но именно из-за возможности вляпаться в битую память я этого делать НЕ советую, если память у вас не ECC. Да, это крайне маловероятная ситуация. Битая память должна почти работать. Шалить самую малость, не вешать систему. Но всё же гадить. Поэтому у сотен камрадов, которые общаются в профильной ветке на хоботе, такого не было, чтоб битая память именно и только на zfs повлияла. Но в Сети я выловил пару сообщений. Так что хоть и крайне маловероятно — но бережёного…

И, наконец, как часто делать скраб? IMHO в домашней практике не чаще раза в месяц и не реже раза в год на каждом из пулов.

Данный справочник является переводом данной статьи. Авторы перевода: Евгений Ратников и Сгибнев Михаил. Огромное им спасибо за проделанную работу!

Данная информация представлена в интернете на множестве ресурсов. Оригинальная статья оформлена в виде таблицы, я же оформлю ее в привычном для моего блога формате — в формате пошагового обучения.

В любом случае не забывайте про страницы справки по командам работы с ZFS.

man zpool
man zfs

Так как включить в пул (zpool) можно любые сущности файловой системы, автор приводит примеры построения пулов и работы с ними с использованием простых файлов. Итак, создадим несколько файлов, с которыми будем работать подобно дискам.

cd /
mkfile 100m disk1 disk2 disk3 disk5
mkfile 50m disk4

Мы создали 5 «виртуальных дисков». Четыре имею размер по 100 Мб, а один — 50 Мб. Это пригодится для демонстрации работы с устройствами (разделами) разной ёмкости.

Теперь создадим простой пул без избыточности, затем проверим его размер и использование.

zpool create myzfs /disk1 /disk2
zpool list

NAME          SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
myzfs         191M     94K    191M     0%  ONLINE     -

Созданы пул автоматически монтируется в каталог /myzfs. Посмотрим более детальную информацию о нашем хранилище.

zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          /disk1    ONLINE       0     0     0
          /disk2    ONLINE       0     0     0

errors: No known data errors

Из вывода видно, что в пул включены два диска. Пул без избыточности (не mirror и не RAIDZ).

Теперь попробуем удалить только что созданный пул. Должны же мы это уметь.

zpool destroy myzfs
zpool list

no pools available

Попробуем снова создать пул типа MIRROR (зеркало), но на этот раз попытаемся включить в него диски разного размера. Zpool не даст нам этого сделать. Чтобы безоговорочно создать такой пул, используйте опцию -f, но в этом случае помните — размер зеркала будет равен объему наименьшего диска.

zpool create myzfs mirror /disk1 /disk4

invalid vdev specification
use '-f' to override the following errors:
mirror contains devices of different sizes

Создать зеркалируемое (MIRROR) хранилище можно на двух и более устройствах. Сколько устройств в пуле типа MIRROR — столько у нас есть одинаковых копий данных.

zpool create myzfs mirror /disk1 /disk2 /disk3
zpool list
NAME          SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
myzfs        95.5M    112K   95.4M     0%  ONLINE     -

zpool status -v
  pool: myzfs
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0
            /disk3  ONLINE       0     0     0

errors: No known data errors

Вместо зеркалирования можно использовать массивы RAID. Для этого необходимо создавать пул типа raidz вместо mirror. Подробнее в хендбуке.

Давайте теперь исключим один из дисков из пула. Так как этот диск относится к зеркалу (MIRROR), то при его исключении никаких проблем не возникает.

zpool detach myzfs /disk3
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0

errors: No known data errors

Теперь давайте добавим к пулу новый диск. Если пул не был зеркальным, то он им станет после добавления нового диска.

zpool attach myzfs /disk1 /disk3
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: resilver completed with 0 errors on Tue Sep 11 13:31:49 2007
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0
            /disk3  ONLINE       0     0     0

errors: No known data errors

А что будет, если попытаемся удалить, а не исключить устройство из пула? Zpool сообщит нам о том, что устройство не может быть удалено. Для начала его нужно отключить.

zpool remove myzfs /disk3

cannot remove /disk3: only inactive hot spares can be removed

zpool detach myzfs /disk3

Теперь давайте попробуем добавить диск горячей замены (hot spare) к нашему пулу.

zpool add myzfs spare /disk3
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0
        spares
          /disk3    AVAIL   

errors: No known data errors

А теперь удалим его из пула.

zpool remove myzfs /disk3
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0

errors: No known data errors

Теперь попробуем отключить один из дисков. Пока диск отключен, на него не будет производиться запись и с него не будет производиться чтение. Если использовать параметр -t, то при перезагрузке сервера диск вернется в состояние онлайн автоматически.

zpool offline myzfs /disk1
zpool status -v

  pool: myzfs
 state: DEGRADED
status: One or more devices has been taken offline by the administrator.
        Sufficient replicas exist for the pool to continue functioning 
        in a degraded state.
action: Online the device using 'zpool online' or replace the device 
        with 'zpool replace'.
 scrub: resilver completed with 0 errors on Tue Sep 11 13:39:25 2007
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       DEGRADED     0     0     0
          mirror    DEGRADED     0     0     0
            /disk1  OFFLINE      0     0     0
            /disk2  ONLINE       0     0     0

errors: No known data errors

Обратите внимание на состояние пула: DEGRADED

Теперь включим этот диск.

zpool online myzfs /disk1
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: resilver completed with 0 errors on Tue Sep 11 13:47:14 2007
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk1  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0

errors: No known data errors

Состояние пула снова ONLINE.

В данный момент в нашем пуле два диска: disc1 и disc2. Также в системе имеется диск disc3, но он не подключен к пулу. Предположим, что disc1 вышел из строя и его нужно заменить на disc3.

zpool replace myzfs /disk1 /disk3
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: resilver completed with 0 errors on Tue Sep 11 13:25:48 2007
config:

        NAME        STATE     READ WRITE CKSUM
        myzfs       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            /disk3  ONLINE       0     0     0
            /disk2  ONLINE       0     0     0

errors: No known data errors

Периодически для исправления ошибок необходимо выполнять процедуру чистки (scrubbing) для пулов типа MIRROR или RAID-Z. Данная процедура находит ошибки в контрольных суммах и исправляет их. Также восстанавливаются сбойные блоки.

Данная операция слишком ресурсоемка! Следует выполнять ее только во время наименьшей нагрузки на пул.

zpool scrub myzfs

Если необходимо перенести пул в другую систему, то его необходимо сначала экспортировать.

zpool export myzfs
pool list

no pools available

А затем импортировать в новой системе.

Если ключ -d не указать, то команда ищет /dev/dsk. Так как в данном примере мы используем файлы, необходимо указать директорию с файлами используемыми хранилищем.

zpool import -d / myzfs
zpool list

NAME          SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
myzfs        95.5M    114K   95.4M     0%  ONLINE     -

Обновление версии пула. Показать версию используемого пула. Флаг -v показывает возможности, поддерживаемые данным пулом. Используйте флаг -a, чтобы обновить все доступные пулы до новейшей из них версии. Обновленные пулы больше не будут доступны из систем, на которых работают более старые версии.

zpool upgrade
This system is currently running ZFS pool version 8.

All pools are formatted using this version.


zpool upgrade -v

This system is currently running ZFS pool version 8.

The following versions are supported:

VER  DESCRIPTION
---  --------------------------------------------------------
 1   Initial ZFS version
 2   Ditto blocks (replicated metadata)
 3   Hot spares and double parity RAID-Z
 4   zpool history
 5   Compression using the gzip algorithm
 6   pool properties
 7   Separate intent log devices
 8   Delegated administration
For more information on a particular version, including supported 
releases, see:

http://www.opensolaris.org/os/community/zfs/version/N

Where 'N' is the version number.

Если нужно получить статистику по операциям ввода/вывода пулов, выполняем команду.

zpool iostat 5
               capacity     operations    bandwidth 
pool         used  avail   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
myzfs        112K  95.4M      0      4     26  11.4K
myzfs        112K  95.4M      0      0      0      0
myzfs        112K  95.4M      0      0      0      0

Работа с файловой и другими системами ZFS
#

Файловая система
#

Создадим файловую систему в нашем пуле. Затем проверим автомонтирование новой файловой системы.

zfs create myzfs/colin
df -h

Filesystem   kbytes    used   avail capacity  Mounted on
...
myzfs/colin  64M        18K     63M       1%  /myzfs/colin

Получить список файловых систем ZFS можно следующей командой.

zfs list

NAME          USED  AVAIL  REFER  MOUNTPOINT
myzfs         139K  63.4M    19K  /myzfs
myzfs/colin    18K  63.4M    18K  /myzfs/colin

В данный момент в нашем пуле имеется одно зеркало, в которое входят два диска: disc2 и disc3.

Давайте попробуем расширить наш пул. Попытаемся добавить к нему disc1

zpool add myzfs /disk1

invalid vdev specification
use '-f' to override the following errors:
mismatched replication level: pool uses mirror and new vdev is file

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

Добавим к пулу новое зеркало, состоящее из дисков: disc1 и disc5

zpool add myzfs mirror /disk1 /disk5
zpool status -v

  pool: myzfs
 state: ONLINE
 scrub: none requested
config:

        NAME         STATE     READ WRITE CKSUM
        myzfs        ONLINE       0     0     0
          mirror     ONLINE       0     0     0
            /disk3   ONLINE       0     0     0
            /disk2   ONLINE       0     0     0
          mirror     ONLINE       0     0     0
            /disk1   ONLINE       0     0     0
            /disk5   ONLINE       0     0     0

errors: No known data errors

Добавим теперь к пулу еще одну файловую систему и посмотрим, как это отразится на размере файловых систем, входящих в пул.

zfs create myzfs/colin2
zfs list

NAME           USED  AVAIL  REFER  MOUNTPOINT
myzfs          172K   159M    21K  /myzfs
myzfs/colin     18K   159M    18K  /myzfs/colin
myzfs/colin2    18K   159M    18K  /myzfs/colin2

Обе файловые системы, входящие в пул, по объему равны всему пулу. В этом заключается одно из преимуществ системы ZFS — по умолчанию нет никакого ограничения на файловые системы.

Чтобы явно управлять объемом файловых систем, можно прибегнуть к резервированию — выделению гарантированного объема для файловой системы, либо квотированию — ограничению файловой системы по максимальному объему.

Давайте зарезервируем для файловой системы /myzfs/colin место в пуле, равное 20 Мб. Остальные файловые системы, заполняя пул, в любом случае оставят для этой файловой системы 20 Мб места.

zfs set reservation=20m myzfs/colin
zfs list -o reservation

RESERV
  none
   20M
  none

Теперь для файловой системы /myzfs/colin2 установим квоту в 20 Мб. Это означает, что данная файловая система не сможет занять в пуле более 20 Мб, даже если пул будет полностью свободным.

zfs set quota=20m myzfs/colin2
zfs list -o quota myzfs/colin myzfs/colin2

QUOTA
 none
  20M

Также для файловой системы /myzfs/colin2 включим сжатие. Сжатие достаточно эффективно работает на уровне ZFS практически без потерь производительности (конечно же, при условии, что производительности сервера достаточно). Вместо compression=on можно использовать compression=gzip.

zfs set compression=on myzfs/colin2
zfs list -o compression

COMPRESS
     off
     off
      on

Чтобы сделать файловую систему доступной по протоколу NFS, достаточно выполнить одну команду. Причем после перезагрузки сервера доступ к файловой системе утерян не будет. Никаких дополнительных настроек операционной системы производить не нужно.

zfs set sharenfs=on myzfs/colin2
zfs get sharenfs myzfs/colin2 

NAME           PROPERTY  VALUE     SOURCE
myzfs/colin2   sharenfs  on        local

Точно так же в одну команду ресурс можно сделать доступным по протоколу SMB. Что пользователям ОС Windows наверняка пригодится.

zfs set sharesmb=on myzfs/colin2
zfs get sharesmb myzfs/colin2

NAME           PROPERTY  VALUE     SOURCE
myzfs/colin2   sharesmb  on        local

Для повышения надежности (если у вас обычный пул, без избыточности), можно использовать следующую опцию файловой системы.

zfs set copies=2 myzfs/colin2

Теперь в файловой системе будет храниться по две копии каждого блока. Это имеет смысл, если пул без избыточности (mirror / raidz).

Snapshots (снепшоты или снимки состояния)
#

Создать снепшот файловой системы очень просто. Давайте создадим снепшот для файловой системы myzfs/colin и назовем его test.

zfs snapshot myzfs/colin@test
zfs list

NAME               USED  AVAIL  REFER  MOUNTPOINT
myzfs             20.2M   139M    21K  /myzfs
myzfs/colin         18K   159M    18K  /myzfs/colin
myzfs/colin@test      0      -    18K  -
myzfs/colin2        18K  20.0M    18K  /myzfs/colin2

Если появится необходимость отката к снепшоту, достаточно выполнить одну команду.

zfs rollback myzfs/colin@test

Снэпшот можно подмониторовать, как обычно. Например так.

mount -t zfs myzfs/colin@test /mnt

Даже можно клонировать файловую системы из снепшота в новую файловую систему.

zfs clone myzfs/colin@test myzfs/colin3
zfs list

NAME               USED  AVAIL  REFER  MOUNTPOINT
myzfs             20.2M   139M    21K  /myzfs
myzfs/colin         18K   159M    18K  /myzfs/colin
myzfs/colin@test      0      -    18K  -
myzfs/colin2        18K  20.0M    18K  /myzfs/colin2
myzfs/colin3          0   139M    18K  /myzfs/colin3

Теперь давайте удалим наши файловые системы /myzfs/colin и /myzfs/colin2

Сперва удалим пустую файловую систему /myzfs/colin2

zfs destroy myzfs/colin2
zfs list

NAME               USED  AVAIL  REFER  MOUNTPOINT
myzfs             20.1M   139M    22K  /myzfs
myzfs/colin         18K   159M    18K  /myzfs/colin
myzfs/colin@test      0      -    18K  -
myzfs/colin3          0   139M    18K  /myzfs/colin3

Файловая система удалилась без проблем. Теперь удалим файловую систему, для которой существует снепшот.

zfs destroy myzfs/colin 

cannot destroy 'myzfs/colin': filesystem has children
use '-r' to destroy the following datasets:
myzfs/colin@test

Удаление невозможно, т.к. у файловой системы имеется дочерний объект. Можно воспользоваться параметром -r чтобы удалить файловую систему вместе со всеми дочерними объектами рекурсивно.

Мы можем отключить снепшот от /myzfs/colin и оставить его дочерним только для /myzfs/colin3

zfs promote myzfs/colin3
zfs list

NAME                USED  AVAIL  REFER  MOUNTPOINT
myzfs              20.1M   139M    21K  /myzfs
myzfs/colin            0   159M    18K  /myzfs/colin
myzfs/colin3         18K   139M    18K  /myzfs/colin3
myzfs/colin3@test      0      -    18K  -


zfs destroy myzfs/colin 
zfs list

NAME                USED  AVAIL  REFER  MOUNTPOINT
myzfs               147K   159M    21K  /myzfs
myzfs/colin3         18K   159M    18K  /myzfs/colin3
myzfs/colin3@test      0      -    18K  -

Теперь сделанный ранее снепшот для /myzfs/colin стал дочерним объектом /myzfs/colin3. Таким образом у файловой системы /myzfs/colin больше нет дочерних объектов и ее можно без труда разобрать (удалить).

Если вдруг понадобиться переименовать ранее созданную файловую систему или снепшот, то можно воспользоваться следующими командами.

zfs rename myzfs/colin3 myzfs/bob
zfs list

NAME             USED  AVAIL  REFER  MOUNTPOINT
myzfs            153K   159M    21K  /myzfs
myzfs/bob         18K   159M    18K  /myzfs/bob
myzfs/bob@test      0      -    18K  -

zfs rename myzfs/bob@test myzfs/bob@newtest
zfs list

NAME                USED  AVAIL  REFER  MOUNTPOINT
myzfs               146K   159M    20K  /myzfs
myzfs/bob            18K   159M    18K  /myzfs/bob
myzfs/bob@newtest      0      -    18K  -

Снова вернемся к пулам
#

Получить полную информацию о пулах можно следующим образом.

zfs get all

NAME               PROPERTY       VALUE                  SOURCE
myzfs              type           filesystem             -
myzfs              creation       Tue Sep 11 14:21 2007  -
myzfs              used           146K                   -
myzfs              available      159M                   -
myzfs              referenced     20K                    -
[...]

Если пул нам более не нужен, можем его удалить. Однако, нельзя удалить пул, в котором имеются активные файловые системы.

zpool destroy myzfs

cannot destroy 'myzfs': pool is not empty
use '-f' to force destruction anyway

Чтобы принудительно удалить пул, используйте параметр -f (не выполняйте это сейчас. Пул нам еще понадобится далее)

zpool destroy -f myzfs
zpool status -v

no pools available

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

zfs unmount myzfs/bob
df -h

myzfs                  159M    20K   159M     1%    /myzfs

Подключить файловую систему к пулу вот так.

zfs mount myzfs/bob
df -h

myzfs                  159M    20K   159M     1%    /myzfs
myzfs/bob              159M    18K   159M     1%    /myzfs/bob

Снепшот можно сделать и на удаленный ресурс (или другое место в локальной системе).

zfs send myzfs/bob@newtest | ssh localhost zfs receive myzfs/backup
zfs list

NAME                   USED  AVAIL  REFER  MOUNTPOINT
myzfs                  172K   159M    20K  /myzfs
myzfs/backup            18K   159M    18K  /myzfs/backup
myzfs/backup@newtest      0      -    18K  -
myzfs/bob               18K   159M    18K  /myzfs/bob
myzfs/bob@newtest         0      -    18K  -

В данном случае снепшот передан zfs receive на локальном узле (в демонстрационных целях). В реальной ситуации таким образом можно сделать снепшот на другой узел сети.

Zpool ведет собственную историю всех команд. Посмотреть историю можно следующим образом.

zpool history

History for 'myzfs':
2007-09-11.15:35:50 zpool create myzfs mirror /disk1 /disk2 /disk3
2007-09-11.15:36:00 zpool detach myzfs /disk3
2007-09-11.15:36:10 zpool attach myzfs /disk1 /disk3
2007-09-11.15:36:53 zpool detach myzfs /disk3
2007-09-11.15:36:59 zpool add myzfs spare /disk3
2007-09-11.15:37:09 zpool remove myzfs /disk3
2007-09-11.15:37:18 zpool offline myzfs /disk1
2007-09-11.15:37:27 zpool online myzfs /disk1
2007-09-11.15:37:37 zpool replace myzfs /disk1 /disk3
2007-09-11.15:37:47 zpool scrub myzfs
2007-09-11.15:37:57 zpool export myzfs
2007-09-11.15:38:05 zpool import -d / myzfs
2007-09-11.15:38:52 zfs create myzfs/colin
2007-09-11.15:39:27 zpool add myzfs mirror /disk1 /disk5
2007-09-11.15:39:38 zfs create myzfs/colin2
2007-09-11.15:39:50 zfs set reservation=20m myzfs/colin
2007-09-11.15:40:18 zfs set quota=20m myzfs/colin2
2007-09-11.15:40:35 zfs set compression=on myzfs/colin2
2007-09-11.15:40:48 zfs snapshot myzfs/colin@test
2007-09-11.15:40:59 zfs rollback myzfs/colin@test
2007-09-11.15:41:11 zfs clone myzfs/colin@test myzfs/colin3
2007-09-11.15:41:25 zfs destroy myzfs/colin2
2007-09-11.15:42:12 zfs promote myzfs/colin3
2007-09-11.15:42:26 zfs rename myzfs/colin3 myzfs/bob
2007-09-11.15:42:57 zfs destroy myzfs/colin
2007-09-11.15:43:23 zfs rename myzfs/bob@test myzfs/bob@newtest
2007-09-11.15:44:30 zfs receive myzfs/backup

Ну вот. Основные команды для работы с пулами ZFS усвоены.

Теперь можно удалить сам пул и файлы. Они нам больше не пригодятся.

NAME

zpool-scrub
begin or resume scrub of ZFS storage pools

SYNOPSIS

zpool scrub
[-s|-p]
[-w] pool

DESCRIPTION

Begins a scrub or resumes a paused scrub. The scrub examines all
data in the specified pools to verify that it checksums correctly. For
replicated (mirror, raidz, or draid) devices, ZFS automatically repairs any
damage discovered during the scrub. The zpool
status command reports the progress of the scrub and
summarizes the results of the scrub upon completion.

Scrubbing and resilvering are very similar operations. The
difference is that resilvering only examines data that ZFS knows to be out
of date (for example, when attaching a new device to a mirror or replacing
an existing device), whereas scrubbing examines all data to discover silent
errors due to hardware faults or disk failure.

Because scrubbing and resilvering are I/O-intensive operations,
ZFS only allows one at a time.

A scrub is split into two parts: metadata scanning and block
scrubbing. The metadata scanning sorts blocks into large sequential ranges
which can then be read much more efficiently from disk when issuing the
scrub I/O.

If a scrub is paused, the zpool
scrub resumes it. If a resilver is in progress, ZFS
does not allow a scrub to be started until the resilver completes.

Note that, due to changes in pool data on a live system, it is
possible for scrubs to progress slightly beyond 100% completion. During this
period, no completion time estimate will be provided.

OPTIONS

-s
Stop scrubbing.
-p
Pause scrubbing. Scrub pause state and progress are periodically synced to
disk. If the system is restarted or pool is exported during a paused
scrub, even after import, scrub will remain paused until it is resumed.
Once resumed the scrub will pick up from the place where it was last
checkpointed to disk. To resume a paused scrub issue
zpool scrub again.
-w
Wait until scrub has completed before returning.

EXAMPLES

Example
1

Status of pool with ongoing scrub:

# zpool status
  ...
  scan: scrub in progress since Sun Jul 25 16:07:49 2021
        403M scanned at 100M/s, 68.4M issued at 10.0M/s, 405M total
        0B repaired, 16.91% done, 00:00:04 to go
  ...

Where metadata which references 403M of file data has been scanned
at 100M/s, and 68.4M of that file data has been scrubbed sequentially at
10.0M/s.

PERIODIC
SCRUB

On machines using systemd, scrub timers can be enabled on per-pool
basis. weekly and monthly
timer units are provided.

systemctl enable
zfs-scrub-weekly@rpool.timer
--now
systemctl
enable
zfs-scrub-monthly@otherpool.timer
--now

SEE
ALSO

systemd.timer(5),
zpool-iostat(8),
zpool-resilver(8),
zpool-status(8)

1. Overview

ZFS is a combined file system and logical volume manager. ZFS includes protections against data corruption and built-in disk mirroring capabilities.

This guide will go through the process of installing ZFS on Ubuntu 20.04 LTS, setting up a storage pool with fake disks set up in a mirrored vdev configuration and then deliberately damaging the data on to test ZFS’s self-healing capabilities.

What you’ll learn

  • How to install ZFS
  • How to create a striped pool using image files and how this reacts to (fake) disk corruption
  • How to create a mirrored storage pool using image files
  • How ZFS automatically recovers a mirror from disk corruption
  • How to replace a failed disk (file) in a mirrored vdev

What you’ll need

  • Ubuntu Server or Desktop 20.04 LTS
  • 300MB free space

Disclaimer: while I work at Canonical, I do not have anything to do with ZFS in that capacity and I have authored this simply as an Ubuntu user interested in ZFS.


2. Installing ZFS

The main components of ZFS are maintained as a standard Ubuntu package, so to install simply run:

sudo apt install zfsutils-linux

After that, we can check if ZFS was installed correctly by running:

whereis zfs

You should see output similar to the following:

zfs: /sbin/zfs /etc/zfs /usr/share/man/man8/zfs.8.gz

Now that we’re done installing the required packages, let’s create a storage pool!


3. Create and test a ZFS Pool with a Striped vdev

Creating image files to use as fake disks

We are going to create image files to use as fake disks for ZFS, so that we can test them without worrying about our data.

First, let’s create a folder to work in:

mkdir test_zfs_healing
cd test_zfs_healing

Now let’s create two image files to use as our fake disks:

for FAKE_DISK in disk1.img disk2.img
do
	dd if=/dev/zero of=`pwd`/$FAKE_DISK bs=1M count=100
done

If you do an ls, you should now see two img files:

$ ls
disk1.img  disk2.img

Let’s save our working directory to a variable to make it easier to come back here later:

ZFS_TEST_DIR=`pwd`

Creating a Pool

We are going to create a striped vdev, like RAID-0, in which data is striped dynamically across the two “disks”. This is performant and lets us use most of our disk space, but has no resilience.

To create a pool with a striped vdev, we run:

sudo zpool create test_pool_striped 
  `pwd`/disk1.img 
  `pwd`/disk2.img

If we run zpool list, we should see the new pool:

$ zpool list
NAME                     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
test_pool_striped   160M   111K   160M        -         -     1%     0%  1.00x    ONLINE  -

Note that the size is 160M from our two 100MB raw disks (200MB total), so we have the use of most of the space.

If we run zpool status test_pool_striped, we should see the details of our fake disks:

$ zpool status test_pool_striped
  pool: test_pool_striped
 state: ONLINE
  scan: none requested
config:

	NAME                                      STATE     READ WRITE CKSUM
	test_pool_striped                         ONLINE       0     0     0
	  /home/user/test_zfs_healing/disk1.img  ONLINE       0     0     0
	  /home/user/test_zfs_healing/disk2.img  ONLINE       0     0     0

errors: No known data errors

Add text to the new pool

We can see where our pool has been mounted with:

zfs mount

and we should see something like:

$ zfs mount
test_pool_striped               /test_pool_striped

First we’ll change the mountpoint to be owned by the current user:

sudo chown $USER /test_pool_striped

Then let’s change into that mountpoint:

cd /test_pool_striped

Then we will create a text file with some text in it:

echo "We are playing with ZFS. It is an impressive filesystem that can self-heal, but even it has limits." > text.txt

We can show the text in the file with:

cat text.txt
$ cat text.txt
We are playing with ZFS. It is an impressive filesystem that can self-heal, but even it has limits.

And we can look at the hash of the file with:

sha1sum text.txt
$ sha1sum text.txt 
c1ca4def6dc5d82fa6de97d2f6d429045e4f4065  text.txt

Deliberately damage a disk

First we will go back to our directory with the disk images:

cd $ZFS_TEST_DIR

Now we are going to write zeros over one of the disks to simulate a data corruption or partial disk failure of one of the disks in our mirror.

WARNING!
This is a dangerous operation as you are writing random
data over something. Make sure you are writing over the
correct file!

dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100

and we should see output like:

$ dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.173905 s, 603 MB/s

Now change back to the mountpoint:

cd /test_pool_striped/

and read the file:

cat text.txt
cat text.txt 
We are playing with ZFS. It is an impressive filesystem that can self-heal, but even it has limits.

Oh. Let’s check the hash:

sha1sum text.txt
$ sha1sum text.txt 
c1ca4def6dc5d82fa6de97d2f6d429045e4f4065  text.txt

Everything seems fine…

Export the pool

I believe that, when the pool is online, it detects and prevents the corruption. That is great, but interferes with our testing! So we need to export the pool first:

cd $ZFS_TEST_DIR
sudo zpool export test_pool_striped

And if we run a zpool list, test_pool_striped should no longer appear.

Damage the disk again

So now let’s try damaging the “disk” again:

dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100

which gives:

$ dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.173001 s, 606 MB/s

We now try to re-import the pool with:

sudo zpool import -d $ZFS_TEST_DIR/disk2.img

And we are told that it could not do so because the pool has damaged devices or data:

$ sudo zpool import -d $ZFS_TEST_DIR/disk2.img
   pool: test_pool_striped
     id: 3823113642612529477
  state: FAULTED
 status: The pool metadata is corrupted.
 action: The pool cannot be imported due to damaged devices or data.
   see: http://zfsonlinux.org/msg/ZFS-8000-72
 config:

	test_pool_striped                         FAULTED  corrupted data
	  /home/user/test_zfs_healing/disk2.img  ONLINE

If you are lucky, you may instead see something more like:

$ sudo zpool import -d $ZFS_TEST_DIR/disk2.img
   pool: test_pool_striped
     id: 706836292853756916
  state: ONLINE
 status: One or more devices contains corrupted data.
 action: The pool can be imported using its name or numeric identifier.
   see: http://zfsonlinux.org/msg/ZFS-8000-4J
 config:

	test_pool_striped                         ONLINE
	  /home/user/test_zfs_healing/disk1.img  UNAVAIL  corrupted data
	  /home/user/test_zfs_healing/disk2.img  ONLINE

But in fact trying to import this with:

sudo zpool import test_pool_striped -d $ZFS_TEST_DIR/disk2.img

still does not import (on my system this runs for a very long time, never works and makes zpool commands not work in the meantime).

Clean up

Let’s delete our disk files:

cd $ZFS_TEST_DIR
rm disk1.img disk2.img

4. Create and test a ZFS Pool with a Mirrored vdev

Creating image files to use as fake disks

Let’s create two image files to use as our fake disks again:

for FAKE_DISK in disk1.img disk2.img
do
	dd if=/dev/zero of=`pwd`/$FAKE_DISK bs=1M count=100
done

Again, if you do an ls, you should now see two img files:

$ ls
disk1.img  disk2.img

Creating a Pool

This time, we are going to create a mirrored vdev , also called RAID-1 , in which a complete copy of all data is stored separately on each drive.

To create a mirrored pool, we run:

sudo zpool create test_pool_with_mirror mirror 
  `pwd`/disk1.img 
  `pwd`/disk2.img

Note the addition of the word mirror between the pool name and the disk names.

If we run zpool list, we should see the new pool:

$ zpool list
NAME                    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
test_pool_with_mirror    80M   111K  79.9M        -         -     3%     0%  1.00x    ONLINE  -

But note that this time the size is only 80M, half what it was before. This makes sense, as we are storing two copies of everything (one on each disk), so we have half as much space.

If we run zpool status test_pool_with_mirror, we should see that the disks have been put into a mirror vdev named mirror-0:

$ zpool status test_pool_with_mirror
  pool: test_pool_with_mirror
 state: ONLINE
  scan: none requested
config:

	NAME                                        STATE     READ WRITE CKSUM
	test_pool_with_mirror                       ONLINE       0     0     0
	  mirror-0                                  ONLINE       0     0     0
	    /home/user/test_zfs_healing/disk1.img  ONLINE       0     0     0
	    /home/user/test_zfs_healing/disk2.img  ONLINE       0     0     0

errors: No known data errors

Add some data

We can see where our pool has been mounted:

$ zfs mount
test_pool_with_mirror          /test_pool_with_mirror

First we’ll change the mountpoint to be owned by the current user:

sudo chown $USER /test_pool_with_mirror

Then let’s change into that mountpoint:

cd /test_pool_with_mirror

Again we will create a text file with some text in it:

echo "We are playing with ZFS. It is an impressive filesystem that can self-heal. Mirror, mirror, on the wall." > text.txt

We can show the text in the file with:

cat text.txt
$ cat text.txt
We are playing with ZFS. It is an impressive filesystem that can self-heal. Mirror, mirror, on the wall.

And we can look at the hash of the file with:

sha1sum text.txt
$ sha1sum text.txt 
aad0d383cad5fc6146b717f2a9e6c465a8966a81  text.txt

Export the pool

As we learnt earlier, we first need to export the pool.

cd $ZFS_TEST_DIR
sudo zpool export test_pool_with_mirror

And, again, if we run a zpool list, test_pool_with_mirror should no longer appear.

Deliberately damage a disk

First we will go back to our directory with the disk images:

cd $ZFS_TEST_DIR

Now again we are going to write zeros over a disk to simulate a disk failure or corruption:

dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100

We see something like the following output:

$ dd if=/dev/zero of=$ZFS_TEST_DIR/disk1.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.172324 s, 608 MB/s

Re-import the pool

Now we are going to re-import our pool:

sudo zpool import -d $ZFS_TEST_DIR/disk2.img

And we see something like the following output:

$ sudo zpool import -d $ZFS_TEST_DIR/disk2.img
   pool: test_pool_with_mirror
     id: 5340127000101774671
  state: ONLINE
 status: One or more devices contains corrupted data.
 action: The pool can be imported using its name or numeric identifier.
   see: http://zfsonlinux.org/msg/ZFS-8000-4J
 config:

	test_pool_with_mirror                       ONLINE
	  mirror-0                                  ONLINE
	    /home/user/test_zfs_healing/disk1.img  UNAVAIL  corrupted data
	    /home/user/test_zfs_healing/disk2.img  ONLINE

As expected, disk1.img is showing as corrupted, as we wrote over it with zeros, but, in contrast to the pool with the striped vdev earlier, instead of failing to import as FAULTED, the pool is instead showing ONLINE, with disk2.img showing as ONLINE and only the disk1.img that we overwrote showing as UNAVAIL because of its corrupted data.

The output tells us that we can import the pool by using its name or ID, so let’s do that:

sudo zpool import test_pool_with_mirror -d $ZFS_TEST_DIR/disk2.img

Checking Pool Status

We can check the pool status with:

zpool status test_pool_with_mirror

And the output should look something like:

$ zpool status test_pool_with_mirror
  pool: test_pool_with_mirror
 state: ONLINE
status: One or more devices could not be used because the label is missing or
	invalid.  Sufficient replicas exist for the pool to continue
	functioning in a degraded state.
action: Replace the device using 'zpool replace'.
   see: http://zfsonlinux.org/msg/ZFS-8000-4J
  scan: none requested
config:

	NAME                                        STATE     READ WRITE CKSUM
	test_pool_with_mirror                       ONLINE       0     0     0
	  mirror-0                                  ONLINE       0     0     0
	    4497234452516491230                     UNAVAIL      0     0     0  was /home/user/test_zfs_healing/disk1.img
	    /home/user/test_zfs_healing/disk2.img  ONLINE       0     0     0

errors: No known data errors

So the pool is online and working, albeit in a degraded state. We can look at the file we wrote earlier:

$ cat /test_pool_with_mirror/text.txt 
We are playing with ZFS. It is an impressive filesystem that can self-heal. Mirror, mirror, on the wall.

Replacing the failed device

The status is telling us that we are missing a device and the pool is degraded, so let’s fix that.

Let’s create a new “disk” in our working directory:

cd $ZFS_TEST_DIR
dd if=/dev/zero of=`pwd`/disk3.img bs=1M count=100

Then, let’s follow the instructions from the zpool status and replace the disk:

sudo zpool replace test_pool_with_mirror $ZFS_TEST_DIR/disk1.img $ZFS_TEST_DIR/disk3.img

Check the zpool status again

We can see how this disk replacement has affected things by checking zpool status test_pool_with_mirror:

$ zpool status test_pool_with_mirror
  pool: test_pool_with_mirror
 state: ONLINE
  scan: resilvered 274K in 0 days 00:00:00 with 0 errors on Sat Nov 27 22:43:37 2021
config:

	NAME                                        STATE     READ WRITE CKSUM
	test_pool_with_mirror                       ONLINE       0     0     0
	  mirror-0                                  ONLINE       0     0     0
	    /home/user/test_zfs_healing/disk3.img  ONLINE       0     0     0
	    /home/user/test_zfs_healing/disk2.img  ONLINE       0     0     0

errors: No known data errors

disk1.img has been replaced by disk3.img and it tells us that it has “resilvered” the data from the mirror (disk2.img) to the new disk (disk3.img).

Removing the pool and cleaning up

We can now remove the test pool:

sudo zpool destroy test_pool_with_mirror

and it should no longer show in a zpool list.

Then we can remove the fake “disks” we created:

cd $ZFS_TEST_DIR
rm disk1.img disk2.img disk3.img
cd ..
rmdir $ZFS_TEST_DIR

5. That’s all!

Congratulations! We have covered:

  • How to install ZFS
  • How to create a striped pool using image files and how this reacts to (fake) disk corruption
  • How to create a mirrored storage pool using image files
  • How ZFS automatically recovers a mirror from disk corruption
  • How to replace a failed disk (file) in a mirrored vdev

Further reading

  • For detailed operations check out the Oracle ZFS Administration Guide
  • For an excellent background reference on ZFS, see FreeBSD Mastery: ZFS – while this is focused on BSD, nearly all of the content will be helpful for OpenZFS Linux users
  • Similarly, the FreeBSD handbook has an excellent chapter on ZFS, much of which will be applicable to Linux.
  • For a quick ‘cheat-sheet’ guide, try the Ubuntu Wiki ZFS reference
  • There is also a lengthy 101 guide to ZFS on Arstechnica

Was this tutorial useful?

Thank you for your feedback.


Понравилась статья? Поделить с друзьями:

Не пропустите эти материалы по теме:

  • Яндекс еда ошибка привязки карты
  • Zf ecolife коды ошибок
  • Zet 9 ошибка 17
  • Zero messages received mdflasher ошибка
  • Zelmer ek1300 ошибка e0

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии