четверг, 18 июля 2013 г.

История спасения данных с "умирающего" жесткого диска

Очередное утро началось с чтения письма от smartd. Один из дисков сервера, который используется для резервного копирования всех остальных серверов, начал свой путь в лучший мир. В письме говорилось о появлении одного pending sector, но пока я ехал в офис от smartd пришло второе письмо, в котором говорилось, что этот сектор уже перешел в разряд offline uncorrectable. А вот это уже плохо, значит с большой долей вероятности считать данные из этого сектора уже не удастся.

Забегая вперед скажу, что я не сторонник "прятать" проблемные сектора на дисках и использовать их дальше. Если на диске появились проблемы с чтением секторов, то доверия к такому диску уже нет никакого. Его нужно скорее выводить из эксплуатации и более не использовать (во всяком случае в серверах). Сейчас стоимость новых дисков достаточно низка чтобы менять их на новые.

Приехав в офис первым делом связываюсь с саппортом хостинга и прошу новый аналогичный диск для миграции данных. Нужного диска в наличии не оказалось и пришлось ждать доставки на склад (4 июля в штатах как никак).

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

# screen -S data_migration

На сервере используется виртуализация OpenVZ и сервер резервного копирования является одним из контейнеров. Для начала его нужно остановить и запретить автозапуск на случай нештатной перезагрузки физического сервера.

# vzctl set backups --onboot no --save
# vzctl stop backups

На умирающем диске было занято более 50% пространства, причем мелкими файлами, и я решил переносить данные на блочном уровне. Для этого нужно отмонтировать раздел и запретить его автомонтирование (опять же на случай нештатной перезагрузки)

# umount /backup
# sed -i -e 's,^\(LABEL=/backup\),#\1,' /etc/fstab

Поскольку у меня уже был опыт копирования данных с проблемных носителей, то я сразу отправился искать ddrescue под CentOS. В отличие от классического dd, ddrescue читает данные большими блоками, но при появлении ошибок уменьшает размер блока и перечитывает сбойный участок. Это приводит к значительному снижению скорости копирования, но после прохождения проблемного участка, размер блока вновь увеличивается и скорость вновь возрастает. Нужный пакет нашелся в репозитории EPEL

# rpm -ivh http://dl.fedoraproject.org/pub/epel/5/i386/ddrescue-1.16-1.el5.i386.rpm

Тут стоит упомянуть, что есть две различные версии ddrescue. Первоначальная версия1 была написана Kurt Garloff. Позже фондом GNU была выпущена улучшенная версия2, которая вобрала в себя все самые сильные стороны.

Сейчас все готово и можно начинать копирование данных

# ddrescue --force --direct --synchronous /dev/sdc /dev/sdd /root/ddrescue.log

В надежде, что нечитаемых данных будет немного, я отправился домой.

На следующий день меня ждал отчет ddrescue

GNU ddrescue 1.16
Press Ctrl-C to interrupt
rescued: 2000 GB, errsize: 6656 B, current rate: 153 B/s
ipos: 279789 MB, errors: 6, average rate: 73473 kB/s
opos: 279789 MB, time since last successful read: 0 s
Finished

При запуске ddrescue я указал сохранить лог результата в /root/ddrescue.log и сейчас можно узнать подробности о неправильно прочитанных секторах.

# ddrescuelog -l- /root/ddrescue.log 
546463412
546463421
546463423
546463425
546463426
546463427
546463428
546463429
546463430
546463432
546463433
546463438
546463439

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

В отчете ddrescue указаны абсолютные номера секторов диска (начиная с сектора номер 0) и это значит, что для дальнейшей работу мне нужно узнать с какого и по какой сектор расположен раздел с данными на диске.

# fdisk -lu /dev/sdd

Disk /dev/sdd: 2000.3 GB, 2000398934016 bytes
255 heads, 63 sectors/track, 243201 cylinders, total 3907029168 sectors
Units = sectors of 1 * 512 = 512 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdd1              64  3907029167  1953514552   83  Linux

Поскольку раздел начинается с сектора 64, то нужно пересчитать номера секторов относительно начала раздела и перевести номера секторов в номера блоков. Сначала узнаем размер блока файловой системы в секторах.

# tune2fs -l /dev/sdd1 | grep Block\ size
Block size:               4096

Поскольку размер блока 4096 байт и размер физического сектора 512 байт, то размер блока равен 8 физическим секторам. Следовательно формула пересчета будет (LBAN - 64) / 8

# ddrescuelog -l- ddrescue.log | awk '{printf "%d\n", ($1-64)/8}'
68307918
68307919
68307919
68307920
68307920
68307920
68307920
68307920
68307920
68307921
68307921
68307921
68307921

Часть испорченных секторов принадлежит одним и тем же блокам, определим уникальные номера блоков

# ddrescuelog -l- ddrescue.log | awk '{printf "%d\n", ($1-64)/8}' | sort | uniq
68307918
68307919
68307920
68307921

Тут мне немного полегчало, номера блоков идут подряд и высока вероятность, что все они принадлежат только одному файлу. Осталось это проверить - зная номера блоков можно определить заняты ли они и если заняты, то какой файл был поврежден. На разделе с данными используется файловая система ext3 и для низкоуровневой работы с ней предназначена утилита debugfs. После запуска нужно открыть раздел /dev/sdd1. Открытие раздела на 2TB заняло больше времени, чем я ожидал и пришлось дожидаться.

# debugfs
debugfs 1.39 (29-May-2006)
debugfs:  open /dev/sdd1

Проверяю, заняты ли блоки 68307918, 68307919, 68307920 и 68307921 данными (блоки идут подряд и вместо перечисления я указал начальный и количество)

debugfs:  testb 68307918 4
Block 68307918 marked in use
Block 68307919 marked in use
Block 68307920 marked in use
Block 68307921 marked in use

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

debugfs:  icheck 68307918 68307919 68307920 68307921
Block   Inode number
68307918        7004516
68307919        7004516
68307920        7004518
68307921        7004520

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

debugfs:  ncheck 7004516 7004518 7004520
Inode   Pathname
7004516 /servers/staging/daily/rdiff-backup-data/increments/files/vz/private/900/var/www/lib/Zend/Validate/Hostname.php.2013-07-02T09:00:01-05:00.snapshot.gz
7004518 /servers/staging/daily/rdiff-backup-data/increments/files/vz/private/900/var/www/lib/Zend/Validate/Iban.php.2013-07-02T09:00:01-05:00.snapshot.gz
7004520 /servers/staging/daily/rdiff-backup-data/increments/files/vz/private/900/var/www/lib/Zend/Validate/Identical.php.2013-07-02T09:00:01-05:00.snapshot.gz

Зацепило файлы инкрементов одного из тестовых сайтов. Этот сайт не представляет большой ценности и бэкапится "до кучи". Теперь можно выдохнуть и выйти из debugfs.

debugfs:  close
debugfs:  quit

Позже решил сделать небольшой эксперимент, который показывает, что fsck для ext3 не может обнаружить повреждения в области данных.

# fsck -C -f -n /dev/sdd1

fsck 1.39 (29-May-2006)
e2fsck 1.39 (29-May-2006)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/backup: 29596527/50080800 files (0.6% non-contiguous), 232652379/488378638 blocks

Как и ожидалось проверка файловой системы не выявила повреждения данных. Поскольку часть данных может годами не читаться, то подобные сбои будут обнаружены в самый неподходящий момент. Одним из вариантов защиты от такого сценария является регулярной тестирование дисков через S.M.A.R.T. и файловые системы, поддерживающие контрольные суммы для данных (ZFS, Btrfs).

Ссылки:
  1. http://www.garloff.de/kurt/linux/ddrescue/
  2. http://www.gnu.org/software/ddrescue/ddrescue.html
  3. http://lwn.net/Articles/430000/
  4. http://askubuntu.com/questions/211578/whats-the-difference-between-ddrescue-gddrescue-and-dd-rescue
  5. http://www.toad.com/gnu/sysadmin/index.html#ddrescue
  6. http://smartmontools.sourceforge.net/badblockhowto.html
  7. http://serverfault.com/questions/311270/from-bad-sector-to-damaged-file-did-it-for-linux-ext3-can-i-do-it-for-windo
  8. http://serverfault.com/questions/510895/find-file-by-block-number-on-ext3-fs-on-lvm

Комментариев нет:

Отправить комментарий