Забегая вперед скажу, что я не сторонник "прятать" проблемные сектора на дисках и использовать их дальше. Если на диске появились проблемы с чтением секторов, то доверия к такому диску уже нет никакого. Его нужно скорее выводить из эксплуатации и более не использовать (во всяком случае в серверах). Сейчас стоимость новых дисков достаточно низка чтобы менять их на новые.
Приехав в офис первым делом связываюсь с саппортом хостинга и прошу новый аналогичный диск для миграции данных. Нужного диска в наличии не оказалось и пришлось ждать доставки на склад (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).
Ссылки:
- http://www.garloff.de/kurt/linux/ddrescue/
- http://www.gnu.org/software/ddrescue/ddrescue.html
- http://lwn.net/Articles/430000/
- http://askubuntu.com/questions/211578/whats-the-difference-between-ddrescue-gddrescue-and-dd-rescue
- http://www.toad.com/gnu/sysadmin/index.html#ddrescue
- http://smartmontools.sourceforge.net/badblockhowto.html
- http://serverfault.com/questions/311270/from-bad-sector-to-damaged-file-did-it-for-linux-ext3-can-i-do-it-for-windo
- http://serverfault.com/questions/510895/find-file-by-block-number-on-ext3-fs-on-lvm
Комментариев нет:
Отправить комментарий