Multipath I/O для программного iSCSI

Статья опубликована в журнале «Системный Администратор»

Немного терминологии

Multipath I/O — технология, позволяющая задействовать нескольких контроллеров или шин для доступа к одному устройству хранения данных. Например, один SCSI диск может быть подсоединён к двум SCSI контроллерам. В случае отказа одного из них, операционная система будет продолжать работать по другому.  Это дает возможность повысить производительность и отказоустойчивость среды передачи данных.
В случае с iSCSI, принципиальная схема не меняется т.к. подключенные по сети блочные устройства (iSCSI-Target) для операционной системы не чем не отличаются от локальных устройств хранения данных. Единственное, что вместо SCSI контроллеров и шлейфов, используются компоненты обычного Ethernet — сетевые карты, медные или оптические кабеля. В продуктах VMware и Citrix данную технологию можно встретить под именем Multipathing.

Device-Mapper Multipath (DM Multipath, множественное связывание устройств) — название реализации технологии Multipath I/O в Linux доступной во всех современных дистрибутивах. Реализован в виде модуля ядра. Прозрачно для приложений, представляет массив, доступный по нескольким путям, в виде одного мета-устройства.

Использование DM Multipath позволяет достичь следующего:

•    Отказоустойчивость  — в случае сбоя любого маршрута (кабеля, контроллера или коммутатора) DM-Multipath начнет использовать альтернативный путь из числа не активных.
•    Балансировка нагрузки – запросы ввода и вывода распределяюся между путями по очереди, что равномерно загружает все доступные сетевые контроллеры и каналы.


Рис №1. Типовая схема применения DM Multipath

Основные компоненты DM Multipath

Модули ядра

dm_multipath — перенаправляет ввод-вывод
dm_round_robin — обеспечивает отказоустойчивость маршрутов и их груп

Утилиты

mpathconf   — Используется для настройки возможностей DM-Multipath.
multipath   — Позволяет просмотреть топологию маршрутов, принудительно переключаться между режимами.

Служба

multipathd   — Следит за маршрутами, инициализирует переключение групп маршрутов при их сбое и восстановлении и позволяет изменять устройства интерактивно.

Как работает DM Multipath

Работу  Multipath I/O лучше всего проиллюстрировать на примере. Допустим есть сеть хранения данных (СХД) с двумя сетевыми контроллерами (хотя их может быть сколько угодно) eth0 — 192.168.0.10/24, eth1 — 192.168.1.10/24. Тип СХД не принципиален, возможно это Fibre Chanel (FC), Fibre Chanel over Ethernet (FCoE) или iSCSI — который мы и будем использовать в качестве примера. На СХД имеется дисковый массив доступный как iSCSI-Target на обоих сетевых интерфейсах. При подключении к нему на другом сервере, так же с двумя сетевыми интерфейсами eth0-192.168.0.130/24, eth1-192.168.1.130/24 получим два, как будто бы разных массива, но фактически, он один.

# iscsiadm -m discovery -t sendtargets -p 192.168.0.10:3260

192.168.0.10:3260,1 iqn.2003-12.test.ruden.org:disk01

# iscsiadm -m discovery -t sendtargets -p 192.168.1.10:3260

192.168.1.10:3260,1 iqn.2003-12.test.ruden.org:disk01

После выполнения этих команд и перезагрузки сервиса iscsi, мы обнаружим в выводе fdisk -l два новых блочных устройства. Убедиться в том, что оба диска являются одним и тем же массивом СХД, можно сравнив идентификаторы iSCSI ID.

# scsi_id -g /dev/sdb

210f6e58300000000

# scsi_id -g /dev/sdc

210f6e58300000000

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

Вот здесь на помощь и приходит DM Multipath, понимающий, что к разным маршрутам подключен один и тот же массив. При этом количество путей, может быть произвольным и даже не одинаковым на обеих сторонах. Например если у сервера на котором подключается iSCSI-Target больше сетевых контроллеров чем у самой СХД. Но они настроены на работу в одной подсети и через них так же доступен дисковый массив. Они будут сгруппированы DM Multipath и настроены в соответствии с выбранным режимом о которых пойдет речь ниже.

Исходные данные

В качестве СХД используется StarWind iSCSI SAN со свободной лицензией, установленный на Windows Server 2008 R2. В сервере имеются два контроллера Gigabit Ethernet (192.168.0.10/24, 192.168.1.10/24). Тестовый iSCSI-Traget, одинаково доступен по двум маршрутам.

В качестве сервера на котором будет задействован DM-Multipath при подключении iSCSI-Target’a используется CentOS 6.3 с двумя контроллерами Gigabit Ethernet (192.168.0.130/24, 192.168.1.130/24)
В ходе настройки понадобится ряд утилит установить которые не составит труда из стандартных репозиториев.

В CentOS для их установки вводим команду:

# yum –y install device-mapper-multipath iscsi-initiator-utils

Если Ubuntu:

# apt-get install open-iscsi open-iscsi-utils multipath-tools

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

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

Настройка

Первым делом, необходимо подключить iSCSI-Target доступный по нескольким маршрутам используя iscsiadm с параметрами указанными в примере выше.
Перезапускаем службу iscsi для того что бы обнаруженные iSCSI-Targets были подключены  как локальные диски.

# /etc/init.d/iscsi restart

Далее как и во вступительном примере, обнаруживаем два как будто бы разных диска (/dev/sdb, /dev/sdс).

# fdisk -l

Диск /dev/sda: 8589 МБ, 8589934592 байт

(листинг локальных дисков не приводится для сокращения объемов статьи)

Диск /dev/sdb: 536 МБ, 536870912 байт
17 heads, 61 sectors/track, 1011 cylinders
Units = цилиндры of 1037 * 512 = 530944 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Диск /dev/sdc: 536 МБ, 536870912 байт
17 heads, 61 sectors/track, 1011 cylinders
Units = цилиндры of 1037 * 512 = 530944 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Теперь, когда наш дисковый массив подключен, настроим для него Multipath I/O.
Все действия сводятся к правке конфигурационного файла multipathd.conf который после установки пакета device-mapper-multipath должен находиться в /etc, но в некоторых дистрибутивах может отсутствовать.
По этому, сами возьмем шаблон multipathd.conf с настройками по умолчанию и поместим его в нужный каталог.

# cp /usr/share/doc/device-mapper-multipath-0.4.9/multipath.conf /etc/multipath.conf

Предназначение секций конфигурационного файла, а так же исчерпывающие описание параметров можно найти по ссылке [1] в конце статьи. По умолчанию, все разделы файла закомментированы. Для нормальной работы DM  Multipath необходимо раскомментировать секцию defaults и для пункта path_grouping_policy указать предпочитаемую политику. Наиболее часто используемыми значениями являются:

failover = Режим активный/пассивный. В таком случае будет использоваться один из доступных маршрутов, а второй — является резервом на случай отказа первого. Данный режим используется по умолчанию.
multibus = Активный/активный. Все маршруты будут использоваться одновременно.

Так же, можно смело включить секцию blacklist с перечислением тех устройств для которых DM Multipath выключен. В этот список попадают локальные флопи и ide диски и другие не используемые в нашем случае устройства.

В результате, multipathd.conf должен принять примерно следующий вид. Остальные настройки сейчас не важны.

defaults {
udev_dir                /dev
polling_interval        10
path_selector           «round-robin 0»
path_grouping_policy    failover
getuid_callout          «/lib/udev/scsi_id —whitelisted —device=/dev/%n»
prio                    alua
path_checker            readsector0
rr_min_io               100
max_fds                 8192
rr_weight               priorities
failback                immediate
no_path_retry           fail
user_friendly_names     yes
}

blacklist {
wwid 26353900f02796769
devnode «^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*»
devnode «^hd[a-z]»

После внесения изменений в конфигурационный файл, запускаем сервис multipathd

# /etc/init.d/multipathd start

И добавляем службу multipathd в автозагрузку

# chkconfig multipathd on

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

# lsmod | grep dm_

dm_round_robin          2717  2
dm_multipath           17649  2 dm_round_robin

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

# modprobe dm_multipath
# modprobe dm_round_robin

Если все сделано правильно, то в списке дисков выводимых fdisk –l должно появиться новое устройство, с тем же идентификатором (Disk identifier: 0x00000000).

Диск /dev/mapper/mpathb: 536 МБ, 536870912 байт
255 heads, 63 sectors/track, 65 cylinders
Units = цилиндры of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Далее, как и на любом другом диске, на нем нужно создать разделы. Но делать это нужно на оригинальном устройстве /dev/sdb или /dev/sdc, а не на новом мета-устройстве /dev/mapper/mpathb появившемся после настройки DM Multipath!

Если реальный диск еще не размечен, это можно сделать любым удобным средством.
Разметки дисков в Linux, посвящено достаточно много статей. Как это сделать конкретно с помощью fdisk, можно посмотреть по ссылке [2]. В случае если на подключенном диске уже существуют разделы, их можно просто смонтировать с помощью утилиты mount как показано ниже и использовать по назначению.
После разметки можно выполнить команду partprobe, что бы таблица разделов была перечитана или перезагрузить сервер.
После синхронизации, разделы созданные на одном из реальных дисков, появятся и на новом мета-устройстве;

….
Устр-во Загр     Начало       Конец       Блоки   Id  Система
/dev/mapper/mpathbp1               1        1011      524173   83  Linux
….

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

# mkfs.ext3 /dev/mapper/mpathbp1
# mount /dev/mapper/mpathbp1 /test-dm

Тестирование

Тестирование работы DM Multipath проводилось в двух наиболее часто используемых режимах, применение которых мне кажется достаточным для решения большинства задач.

Режим failover

# multipath -ll

May 04 04:50:24 | sdb: alua not supported
May 04 04:50:24 | sdc: alua not supported
mpathb (210f6e58300000000) dm-2 ROCKET,RAM DISK 512 MB
size=512M features=’0′ hwhandler=’0′ wp=rw
|-+- policy=’round-robin 0′ prio=-1 status=active
| `- 4:0:0:0 sdb 8:16 active ready running
`-+- policy=’round-robin 0′ prio=-1 status=enabled
`- 3:0:0:0 sdc 8:32 active ready running

Утилита multipath с ключами -ll, отображает текущее состояние путей. Из данного листинга видно, что один из маршрутов находится в состоянии (status) active, а второй доступен, но не используется (status=enable).
В данном режиме, один из путей, автоматически выбирается активным. Оставшиеся маршруты, могут свободно использоваться при любом сетевом взаимодействии, но для multipathd они являются резервными и при доступе к блочному устройству не используются до выхода из строя основного маршрута.

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

Режим multibus

# multipath -ll

May 04 04:10:16 | sdc: alua not supported
May 04 04:10:16 | sdb: alua not supported
mpathb (210f6e58300000000) dm-2 ROCKET,RAM DISK 512 MB
size=512M features=’0′ hwhandler=’0′ wp=rw
`-+- policy=’round-robin 0′ prio=-1 status=active
|- 3:0:0:0 sdc 8:32 active ready running
`- 4:0:0:0 sdb 8:16 active ready running

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

Производительность

ВАЖНО: Если основной решаемой задачей является не отказоустойчивость а повышение производительности операций ввода\вывода. То применять Multipath I/O стоит только в том случае, если в вашем хранилище, достаточно быстрый массив, полностью загружающий один канал. В случае, если единственный маршрут ведущий к массиву не загружается полностью хотя бы под пиковыми нагрузками, добавление еще одного маршрута лишь приведет к потере производительности и увеличению задержек(latency)!

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

Результаты работы утилиты dd;

# time -p dd if=/dev/<массив> of=/dev/null bs=1024k

При одном канале, по стандартной схеме без Multipath I/O;

1073741824 bytes (1.1 GB) copied,
29.0323 s 37 Mb/s

А это уже dd с Multipath I/O поверх двух гигабитных каналов

1073741824 bytes (1.1 GB) copied,
23.4791 s, 48.0 Mb/s

Кроме утилиты dd были выполнены тесты с помощью утилиты fio (flexible I/O tester), информацию о которой можно найти по ссылке[3] в конце статьи.

Вкратце отмечу, что по результатам тестирования было выявлено примерно одинаковое количество iops(число операция ввода\вывода в секунду) как в случае с одним каналом так и при Multipath I/O. Такая же ситуация и с  latency(время ответа от массива). То есть количество маршрутов увеличивает суммарную пропускную способность но не как не улучшает остальные характеристики каналов.

Выводы

DM Multipath является низкоуровневым средством для оптимизации и повышения надежности сетевого ввода/вывода. Даже при использовании дешевого оборудования и стандартного Ethernet, можно построить достаточно производительную и надежную среду передачи данных. Особенно это эффективно в случае с iSCSI в контексте виртуализации.
В данной статье я использовал по два сетевых контроллера с каждой стороны, но их число может быть произвольным. Причем не обязательно одинаковым на обеих сторонах.
При более тонкой настройке, можно добиться любой желаемой производительности и обеспечить необходимый уровень резервирования. Особенно, удобно то, что настройки требует только та сторона на которой выполняется подключение блочного устройства.
При сравнении возможных режимов, наиболее оптимальным мне показался режим  multibus т. к. он позволяет задействовать всю пропускную способность, при этом не уступая в надежности режиму failover.

Ссылки

1. Исчерпывающее описание секций и параметров конфигурационного файла multipathd.conf —  http://link.ac/dm-multipath-config
2. Разметка диска с помощью fdisk — http://jack.kiev.ua/docs/slackbook/installation-partitioning.html
3. Утилита fio и методика тестирования дисковой подсистемы —http://habrahabr.ru/post/154235/