Перенос данных между серверами с помощью LVM и iSCSI

    aquarium-PR-332-4

    Вопрос масштабирования ресурсов выделенных серверов сопряжен с целым рядом сложностей: добавление памяти или дисков невозможно без простоев, а апгрейд дисковой подсистемы зачастую предполагает полный перенос всех данных (объем которых может быть очень большим) со старого сервера на новый. Простое перемещение дисков из одного сервера в другой очень часто тоже оказывается невозможным: причиной этого может быть несовместимость интерфейсов, использование разных RAID-контроллеров, географическая удаленность серверов друг от друга и т.п. Копирование же данных по сети может занимать очень много времени, в течение которого сервис простаивает. Как можно перенести данные на новый сервер, минимизировав время простоя сервисов?

    Мы долго думали над этим вопросом и сегодня представляем вниманию широкой аудитории решение, которое кажется нам наиболее удачным.

    LVM_v3
    Процедура переноса данных с помощью рассматриваемого в этой статье способа состоит из следующих шагов:
    1. новый сервер загружается с внешнего носителя, подготавливаются блочные устройства: размечаются диски, создаются RAID-массивы;
    2. блочные устройства нового сервера экспортируются через iSCSI — создаются iSCSI таргеты;
    3. на старом сервере запускается iSCSI инициатор и подключается к таргетам на новом сервере. На старом сервере появляются и становятся доступны блочные устройства нового сервера;
    4. на старом сервере блочное устройство нового сервера добавляется в LVM группу;
    5. данные копируются на блочное устройство нового сервера с помощью зеркалирования данных в LVM;
    6. старый сервер выключается;
    7. на новом сервере, все еще загруженном с внешнего носителя, монтируется перенесенная на него ФС, в настройки вносятся необходимые правки;
    8. новый сервер перезагружается с дисков, после чего запускаются все сервисы.

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

    Предлагаемая нами методика подходит для всех ОС, где используется LVM для логических разделов и возможна установка iSCSI таргета и инициатора. На сервере, на котором мы осуществляли опытную проверку предлагаемой методики, была установлена ОС Debian Wheezy. В других ОС могут использоваться другие программы и команды, но порядок действий будет аналогичным.

    Все операции осуществлялись на сервере с разметкой дисков, стандартной для наших серверов при автоматической установке ОС. Если на вашем сервере используется другая разметка дисков, параметры некоторых команд потребуется изменить.

    Наш способ переноса данных рассчитан на опытных пользователей, хорошо знающих, что такое LVM, mdraid, iSCSI. Предупреждаем, что ошибки в командах могут привести к полной или частичной потере данных. Прежде чем приступать к переносу данных, необходимо сохранить резервные копии важной информации на внешнем носителе или хранилище.

    Готовим новый сервер


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

    Затем загрузите новый сервер с внешнего носителя. Нашим клиентам мы рекомендуем загрузиться в Selectel Rescue, используя меню управления загрузкой сервера.
    По завершении загрузки подключитесь к новому серверу по SSH. Задайте для нового сервера его будущий hostname. Это необходимо в случае, если вы собираетесь использовать на новом сервере mdraid: при создании RAID-массива hostname будет сохранен в метаданных RAID-массива на всех входящих в него дисках.

    # hostname cs940
    

    Далее следует разметить диски. В нашем случае на каждом сервере будет создано по два основных раздела на каждом диске. Первые разделы будут использованы для сборки RAID1 для /boot, вторые — для сборки RAID10 под LVM Physical Volume, на котором и будут размещены основные данные.

    # fdisk /dev/sda
    Command (m for help): p
    ...
    Device     Boot     Start         End          Blocks      Id  System
    /dev/sda1    *       2048         2099199      1048576     fd  Linux raid autodetect
    /dev/sda2         2099200      1953525167    975712984     fd  Linux raid autodetect
    Command (m for help): w
    

    Чтобы все было проще и быстрее, можно разметить только первый диск, а на остальные скопировать его разметку. Затем создайте RAID-массивы при помощи утилиты mdadm.

    # sfdisk -d /dev/sda | sfdisk /dev/sdb -f
    # mdadm --create /dev/md0 --level=1  --raid-devices=4 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1
    # mdadm --create /dev/md1 --level=10 --raid-devices=4 /dev/sda2 /dev/sdb2 /dev/sdc2 /dev/sdd2
    # mdadm --examine --scan
     ARRAY /dev/md/0 metadata=1.2 UUID=e9b2b8e0:205c12f0:2124cd91:35a3b4c8 name=cs940:0
     ARRAY /dev/md/1 metadata=1.2 UUID=4be6fb41:ab4ce516:0ba4ca4d:e30ad60b name=cs940:1
    

    Затем установите и настройте iSCSI-таргет для копирования RAID-массивов по сети. Мы использовали tgt.

    # aptitude update
    # aptitude install tgt
    

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

    # tgtd
    librdmacm: couldn't read ABI version.
    librdmacm: assuming: 4
    CMA: unable to get RDMA device list
    (null): iser_ib_init(3263) Failed to initialize RDMA; load kernel modules?
    (null): fcoe_init(214) (null)
    (null): fcoe_create_interface(171) no interface specified.
    

    Следующий этап — настройка LUN’ов. При создании LUN нужно указать IP старого сервера, с которого будет разрешено подключение к таргету.

    # tgt-setup-lun -n tgt0 -d /dev/md0 10.0.0.1
    # tgt-setup-lun -n tgt1 -d /dev/md1 10.0.0.1
    # tgt-admin -s
    

    Новый сервер готов, перейдем к подготовке старого сервера.

    Подготовка старого сервера и копирование данных


    Теперь подключимся к старому серверу по SSH. Установим и настроим iSCSI-инициатор, а затем подключим к нему экспортированные с нового сервера блочные устройства:

    # apt-get install open-iscsi
    

    Добавим в конфигурационный файл данные авторизации: без них инициатор не будет работать.

    # nano /etc/iscsi/iscsid.conf
    node.startup = automatic
    node.session.auth.username = MY-ISCSI-USER
    node.session.auth.password = MY-ISCSI-PASSWORD
    discovery.sendtargets.auth.username = MY-ISCSI-USER
    discovery.sendtargets.auth.password = MY-ISCSI-PASSWORD
    

    Дальнейшие операции занимают довольно много времени; чтобы избежать неприятных последствий в случае их прерывания при закрытии SSH, воспользуемся утилитой screen. С ее помощью мы создадим виртуальный терминал, к которому можно будет подключаться по SSH и отключаться без завершения запущенных команд:

    # apt-get install screen
    # screen
    

    Затем подключаемся к порталу и получаем список доступных таргетов; указываем при этом текущий IP-адрес нового сервера:

    # iscsiadm --mode discovery --type sendtargets --portal 10.0.0.2
    10.0.0.2:3260,1 iqn.2001-04.com.cs940-tgt0
    10.0.0.2:3260,1 iqn.2001-04.com.cs940-tgt1
    

    Затем подключаем все доступные таргеты и LUN’ы; в результате выполнения этой команды мы увидим список новых блочных устройств:

    # iscsiadm --mode node --login
    Logging in to [iface: default, target: iqn.2001-04.com.cs940-tgt0, portal: 10.0.0.2,3260] (multiple)
    Logging in to [iface: default, target: iqn.2001-04.com.cs940-tgt1, portal: 10.0.0.2,3260] (multiple)
    Login to [iface: default, target: iqn.2001-04.com.cs940-tgt0, portal: 10.0.0.2,3260] successful.
    Login to [iface: default, target: iqn.2001-04.com.cs940-tgt1, portal: 10.0.0.2,3260] successful.
    

    iSCSI-устройства в системе имеют те же имена, что и обычные SATA/SAS. Но при этом у двух типов устройств различается имя производителя: для iSCSI-устройств оно указано как IET.

    # cat /sys/block/sdc/device/vendor
    IET
    

    Теперь можно приступить к переносу данных. Сначала отмонтируем boot и скопируем его на новый сервер:

     
    # umount /boot
    # cat /sys/block/sdc/size
    1999744
    # cat /sys/block/md0/size
    1999744
    # dd if=/dev/md0 of=/dev/sdc bs=1M
    976+1 records in
    976+1 records out
    1023868928 bytes (1.0 GB) copied, 19.6404 s, 52.1 MB/s
    

    Внимание! С этого момента не активируйте VG и не запускайте никаких LVM-утилит на новом сервере. Одновременная работа двух LVM с одним и тем же блочным устройством может вызвать порчу или потерю данных.

    Теперь приступаем к переносу данных. Добавляем в VG экспортированный с нового сервера RAID10-массив:

    # vgextend vg0 /dev/sdd
    # pvs
     PV             VG   Fmt      Attr     PSize       PFree
     /dev/md1       vg0  lvm2     a--      464.68g    0
     /dev/sdd       vg0  lvm2     a--      1.82t      1.82t
    

    Не забываем о том, что /dev/sdd представляет собой /dev/md1, экспортированный с нового сервера, загруженного в Rescue:

    # lvs
     LV         VG     Attr          LSize       Pool Origin Data%  Move Log Copy%  Convert
     root       vg0   -wi-ao--       47.68g
     swap_1     vg0   -wi-ao--       11.44g
     var        vg0   -wi-ao--       405.55g
    

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

    # lvconvert -m1 vg0/root --corelog /dev/sdd
     vg0/root: Converted: 0.0%
     vg0/root: Converted: 1.4%
     …
     vg0/root: Converted: 100.0% 
    

    Так как при создании зеркальной копии LVM все операции записи осуществляются синхронно, на скорость записи будет влияет скорость канала между серверами, производительность open-iSCSI (500 мБ/с), а также задержка сети. После создания копий всех логических томов убедимся в том, что все они синхронизированы:

    # lvs
     LV         VG    Attr          LSize    Pool Origin Data%  Move Log     Copy%   Convert
     root       vg0   mwi-aom-      47.68g                                  100.00
     swap_1     vg0   mwi-aom-      11.44g                                  100.00
     var        vg0   mwi-aom-      405.55g                                 100.00
    

    На данном этапе все данные скопированы и идет синхронизация данных старого сервера с новым удаленным сервером. Чтобы минимизировать изменения в файловой системе, нужно остановить все сервисы приложений (сервис БД, веб-сервер и т.п.).

    Остановив все важные сервисы, отключаем iSCSI-устройства и исключаем ставшую недоступной копию LVM. После отключения iSCSI-устройств на старом сервере будут выдаваться многочисленные сообщения об ошибках ввода-вывода, но это не должно быть причиной для беспокойства: все данные сохраняются на LVM, лежащий выше блочных устройств.

    # iscsiadm --mode session -u
    # vgreduce vg0 --removemissing --force
    # lvs
     LV         VG   Attr         LSize   Pool Origin Data%  Move Log Copy%  Convert
     root       vg0  -wi-ao--     47.68g
     swap_1     vg0  -wi-ao--     11.44g
     var        vg0  -wi-ao--     405.55g
    

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

    # poweroff
    


    Запуск нового сервера


    После переноса данных новый сервер нужно подготовить к самостоятельной загрузке и запустить.
    Подключаемся по ssh, останавливаем iSCSI-таргет и активируем копию LVM:

    # tgtadm --lld iscsi --mode target --op delete --tid 1
    # tgtadm --lld iscsi --mode target --op delete --tid 2
    
    # pvscan
    

    Теперь исключаем из LVM копию со старого сервера; на сообщения об отсутствии второй половины не обращаем внимания.

    # vgreduce vg0 --removemissing --force
     Couldn't find device with uuid 1nLg01-fAuF-VW6B-xSKu-Crn3-RDJ6-cJgIax.
     Unable to determine mirror sync status of vg0/swap_1.
     Unable to determine mirror sync status of vg0/root.
     Unable to determine mirror sync status of vg0/var.
     Wrote out consistent volume group vg0
    

    Убедившись, что все логические тома на месте, активируем их:

    # lvs
     LV         VG    Attr         LSize   Pool Origin Data%  Move Log Copy%  Convert
     root       vg0   -wi-----      47.68g
     swap_1     vg0   -wi-----      11.44g
     var        vg0   -wi-----      405.55g
    
    # vgchange -ay
     3 logical volume(s) in volume group "vg0" now active
    

    Желательно также проверить файловые системы на всех логических томах:

    # fsck /dev/mapper/vg0-root
    

    Далее выполним chroot в скопированную систему и внесем финальные изменения. Это можно сделать с помощью скрипта infiltrate-root, доступного в Selectel Rescue:

    # infiltrate-root /dev/mapper/vg0-root
    

    Далее все действия на сервере выполняем из chroot. Выполним монтирование всех файловых систем из fstab (по умолчанию chroot монтирует только корневую файловую систему):

    Chroot:/# mount -a
    

    Теперь обновим информацию о RAID-массивах на новом сервере в файле настроек mdadm. Удалим оттуда все данные о старых RAID-массивах (строки, начинающиеся с «ARRAY») и добавим новые:

    Chroot:/# nano /etc/mdadm/mdadm.conf
    Chroot:/# mdadm --examine --scan >> /etc/mdadm/mdadm.conf
    

    Пример валидного mdadm.conf:

    Chroot:/# cat /etc/mdadm/mdadm.conf
    DEVICE partitions
    
    # auto-create devices with Debian standard permissions
    CREATE owner=root group=disk mode=0660 auto=yes
    
    # automatically tag new arrays as belonging to the local system
    HOMEHOST 
    
    # instruct the monitoring daemon where to send mail alerts
    MAILADDR root
    
    # definitions of existing MD arrays
    ARRAY /dev/md/0 metadata=1.2 UUID=2521ca82:2a52a408:565fab6c:43ba944e name=cs940:0
    ARRAY /dev/md/1 metadata=1.2 UUID=6240c2db:b4854bd7:4c4e1510:d37e5010 name=cs940:1
    

    После этого нужно обновить initramfs, чтобы он мог найти и загрузиться с новых RAID-массивов. Также установим на диски загрузчик GRUB и обновим его конфигурацию:

    Chroot:/# update-initramfs -u
    Chroot:/# grub-install /dev/sda --recheck
    Installation finished. No error reported.
    Chroot:/# grub-install /dev/sdb --recheck
    Installation finished. No error reported.
    Chroot:/# update-grub
    Generating grub.cfg ...
    Found linux image: /boot/vmlinuz-3.2.0-4-amd64
    Found initrd image: /boot/initrd.img-3.2.0-4-amd64
    done
    

    Удалим файл udev c cоответствиями названий сетевых интерфейсов и MAC-адресов (при следующей загрузке он будет создан заново):

    Chroot:/# rm /etc/udev/rules.d/70-persistent-net.rules
    

    Теперь новый сервер готов к загрузке:

    Chroot:/# umount -a
    Chroot:/# exit
    

    Изменим порядок загрузки на загрузку с первого жесткого диска в меню управления сервером и перезагрузим его:

    # reboot
    

    Теперь проверим с помощью KVM-консоли, что сервер загрузился, и проверим доступ к серверу по IP-адресу. Если с новым сервером возникают какие-то проблемы, вы можете вернуться к старому серверу.

    Не загружайте старый и новый серверы в рабочую ОС одновременно: они будут загружены с одним и тем же IP, что может привести к потере доступа и другим проблемам.

    Адаптация файловой системы после миграции


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

    # pvresize /dev/md1
    # pvs
     PV         VG   Fmt  Attr PSize PFree
     /dev/md1   vg0  lvm2 a--  1.82t 1.36t
    # vgs
     VG   #PV #LV #SN Attr   VSize VFree
     vg0    1   3   0 wz--n- 1.82t 1.36t
    # lvextend /dev/vg0/var /dev/md1
     Extending logical volume var to 1.76 TiB
     Logical volume var successfully resized
    # lvs
     LV     VG   Attr     LSize  Pool Origin Data%  Move Log Copy%  Convert
     root   vg0  -wi-ao-- 47.68g
     swap_1 vg0  -wi-ao-- 11.44g
     var    vg0  -wi-ao--  1.76t
    
    # xfs_growfs /var
    meta-data=/dev/mapper/vg0-var    isize=256    agcount=4, agsize=26578176 blks
             =                       sectsz=512   attr=2
    data     =                       bsize=4096   blocks=106312704, imaxpct=25
             =                       sunit=0      swidth=0 blks
    naming   =version 2              bsize=4096   ascii-ci=0
    log      =internal               bsize=4096   blocks=51910, version=2
             =                       sectsz=512   sunit=0 blks, lazy-count=1
    realtime =none                   extsz=4096   blocks=0, rtextents=0
    data blocks changed from 106312704 to 472291328
    
    # df -h
    Filesystem            Size        Used      Avail    Use%     Mounted on
    rootfs                 47G        660M        44G      2%     /
    udev                   10M           0        10M      0%     /dev
    tmpfs                 1.6G        280K       1.6G      1%     /run
    /dev/mapper/vg0-root   47G        660M        44G      2%     /
    tmpfs                 5.0M           0       5.0M      0%     /run/lock
    tmpfs                 3.2G           0       3.2G      0%     /run/shm
    /dev/md0              962M         36M       877M      4%     /boot
    /dev/mapper/vg0-var   1.8T        199M       1.8T      1%     /var
    


    Заключение


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

    Аналогичным способом можно осуществлять миграцию и под другими операционными системами — CentOS, OpenSUSE и др. Естественно, в этом случае возможны различия в некоторых нюансах (подготовка ОС для старта на новом сервере, настройка загрузчика, initrd и т.п.).

    Мы прекрасно понимаем, что предлагаемую нами методику вряд ли можно считать идеальной. Будем благодарны за любые замечания и предложения по ее усовершенствованию. Если кто-то из наших читателей может предложить собственный вариант решения проблемы переноса данных без остановки серверов, будем рады с ним ознакомиться.

    Читателей, не имеющих возможности комментировать посты на Хабре, приглашаем к нам в блог.

    Selectel

    116,77

    ИТ-инфраструктура для бизнеса

    Поделиться публикацией
    Комментарии 11
      +1
      Интересно. Хоть и выглядит сложновато для такой задачи. Напрягает только fsck, который выполняется когда уже все сервисы не работают. Какой в итоге получается средний простой для Вашего случая (500Гб данных)?

      PS: Сам для подобных переносов использую схему на уровне ФС (а не блочных устройств):
      1. создаю базовую копию старого сервера на новом (любым способом)
      2. непосредственно перед началом переноса делаю rsync
      3. останавливаю сервисы на старом сервере
      4. еще раз rsync
      5. дальше мероприятия по адаптации ФС

      Время простоя тут, конечно, сильно зависит от содержания самой ФС.

        +1
        Старый добрый rsync хорош до тех пор, пока у вас между итерациями не накапливается большой объем данных. И очевидно, rsync неприменим в случае если нет доступа к ФС, например, если вы отдаете LV тома напрямую в виртуальные машины.

        По поводу fsck, думаю можно немного изменить алгоритм после копирования LVM:
        — гасим «старый» сервер не отключая предварительно таргеты и не исключая копию из LVM
        — ФС при этом будет размонтирована штатно
        В этом случае минус в том, что в случае проблем с «новым» сервером, «старый» может не загрузиться сразу из-за ругани на отсутствующую копию, хотя это несложно исправить.
          0
          rsync по сути не работает когда у вас очень много мелких файлов.
          Он будет работать днями, в то время как переброс вообще всех возможных данных — максимум час.
            0
            Все верно. Это очевидно, об этом я написал, что содержание ФС в этом случае играет роль. Однако, лично на моей практике решение с rsync будет обладать меньшим временем простоя в большинстве случаев
          +3
          Хабр — торт!
            +1
            Очень круто!
              +1
              А ещё в LVM можно делать перенос логических томов «на живую» (без отмонтирования) с одного физического тома на другой. Даже если на этом томе расположена корневая ФС загруженной системы. Команда называется «pvmove».

              Причем, сделано так, что если в процессе переноса «что-то пойдет не так», то мало того, что система сможет нормально загрузиться с частично перенесенного тома, но и сможет продолжить процесс переноса после запуска «pvmove» без аругментов.

              Очень удобно таким способом переезжать с одного жесткого диска на другой. Но этот сценарий скорее ортогональный тому, который описан в статье.
                0
                pvmove действительно удобен при перемещении данных внутри сервера. Но в отличии от pvmove зеркалирование средствами LVM оставляет копию на старом севере, что дает возможность загрузить его при неполадках с новым сервером.
                +1
                Лучше бы не использовать TGT в качестве целевого устройства. Во-первых, TGT — полностью user-mode решение, во вторых, на загрузочном диске его может и не быть (на Selectel Rescue он есть, надеюсь). Поскольку мы грузимся со стороннего носителя, мы можем использовать любое ядро по желанию. Kernel-mode LIO-target, который включен во все ядра, начиная, кажется, с 3.2 — вот наш выбор.
                  0
                  Спасибо за комментарий. Во время изучения вопроса (это было достаточно давно) единственный таргет, который заработал с наименьшим количеством телодвижений, был TGT, проверю вариант с LIO.
                    +2
                    У LIO есть хороший конфигуратор с пчевдографическим интерфейсом — targetcli

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

                Самое читаемое