
igor@0: \section{Реплицируемое блочное устройство DRBD}
igor@0: 
igor@0: 
igor@0: Здесь детально рассматривается процедура
igor@0: подготовки двух систем для синхронизации одного
igor@0: из своих дисковых разделов с помощью DRBD.
igor@0: 
igor@0: Может применяться для организации отказоустойчивых систем
igor@0: хранения данных и отказоустойчивых кластерных систем.
igor@0: 
igor@0: \subsection{Что такое DRBD?}
igor@0: \textbf{DRBD} (англ. \textit{Distributed Replicated Block Device}, распределённое реплицируемое блочное устройство) --- это блочное устройство, 
igor@0: предназначенное для построения отказоустойчивых кластерных систем на операционной системе Linux. DRBD занимается полным отражением (mirroring) по сети всех операций с блочным устройством. Можно считать, что DRBD это сетевой RAID-1.
igor@0: 
igor@0: DRBD берёт данные, записывает их на локальный диск и пересылает на другой хост.
igor@0: На другом хосте они тоже записываются на диск.
igor@0: 
igor@0: Помимо DRBD в кластере должно быть ещё два важных компонента:
igor@0: \begin{enumerate}
igor@0: \item  Служба кластера (Cluster membership service), (в качестве которого чаще всего выступает \textit{heartbeat};
igor@0: \item  Приложение, работающее поверх распределённого блочного устройства.
igor@0: \end{enumerate}
igor@0: 
igor@0: Примеры приложений:
igor@0: \begin{itemize}
igor@0: \item  Файловая система c fsck;
igor@0: \item  Журналируемая файловая система;
igor@0: \item  СУБД;
igor@0: \item  домен Xen.
igor@0: \end{itemize}
igor@0: 
igor@0: \subsection{Как работает DRBD?}
igor@0: Каждое DRBD-устройство (а DRBD-устройств одновременно может быть много)
igor@0: находится в одном из двух состояний:
igor@0: \begin{itemize}
igor@0: \item  primary — главном (первичном);
igor@0: \item  secondary — резервном (вторичном).
igor@0: \end{itemize}
igor@0: На узле, на котором DRBD-устройство находится в основном состоянии,
igor@0: операционная система или процессы могут работать
igor@0: с DRBD-устройством (оно доступно через файл-устройства \texttt{/dev/drbdX}).
igor@0: 
igor@0: Каждое обращение на запись к DRBD-устройству
igor@0: отправляется локальном к нижележащему устройству
igor@0: и на узел, на котором находится реплика устройства.
igor@0: Резервное устройство, получившее запрос, выполняет запись.
igor@0: 
igor@0: Чтение выполняется всегда только локально.
igor@0: 
igor@0: \begin{center} \resizebox{10cm}{!}{\includegraphics{/var/lib/mediawiki/images/d/da/Drbd.png}}\\ \textit{}\end{center}
igor@0: 
igor@0: \begin{verbatim}
igor@0: 
igor@0: \end{verbatim}
igor@0: Если основной узел падает, heartbeat  переключает запасной узел в
igor@0: состояние ведущего и запускает приложения на нём
igor@0: (если используется нежурналируемая файловая система,
igor@0: кроме всего прочего ещё выполнится fsck).
igor@0: 
igor@0: Когда сбойный узел поднимается, DRBD-устройство на нём находится в состоянии
igor@0: второстепенного (secondary), и оно начинается синхронизироваться с основным устройством.
igor@0: Конечно же, это происходит в фоне, без нарушения работы системы.
igor@0: 
igor@0: Синхронизируются только те части устройства,
igor@0: которые подверглись изменению.
igor@0: DRBD старается выполнять ресинхронизацию максимально эффективным способом.
igor@0: Начиная с DRBD-0.7 существует возможность
igor@0: создания так называемых \textit{активных множеств} (active set)
igor@0: определённого размера.
igor@0: Что позволяет выполнять ресинхронизацию на 1—3 минуты, независимо от размера устройства (сегодня до 4TB) даже после падения активного узла.
igor@0: 
igor@0: \subsubsection{Какое отношение DRBD имеет к HA-кластерам?}
igor@0: Сегодня HA-кластеры (отказоуйстойчивые кластеры) используют в своей работе внешние хранилища, которые подключаюся сразу к нескольким узлам.
igor@0: Обычно это делается с помощью шин SCSI или Fibre Channel (но не обязательно).
igor@0: 
igor@0: DRBD позволяет делать похожие вещи, только оно не использует никакого специального оборудования, а работает поверх обычных IP-сетей.
igor@0: 
igor@0: \subsubsection{DRBD и кластерные файловые системы}
igor@0: Как уже говорилось, обычно
igor@0: DRBD-устройство работает на одном из узлов в режиме главного (primary role),
igor@0: а на других — в режиме второстепенного или резервного (secondary role).
igor@0: Запись идёт на устройство, которое находится в режиме главного,
igor@0: а на остальные просто выполняется репликация.
igor@0: Такой режим применим для классических отказоустойчивых кластеров,
igor@0: его следует использовать, если на DRBD-устройстве непосредственно
igor@0: находятся традиционные, не кластерные файловые системы (ext3, XFS, JFS и т.д.).
igor@0: 
igor@0: Начиная с DRBD-8.0.08 можно заставить работать оба узла в режиме primary.
igor@0: Это даёт возможность монтировать кластерную ФС сразу на двух узлах
igor@0: одновременно. Примеры таких кластерных файловых систем: \textit{GFS}, \textit{OCFS2}.
igor@0: 
igor@0: Кроме того, эта возможность DRBD позволяет выполнять живую миграцию
igor@0: доменов Xen, которые используют эти устройства.
igor@0: В этом случае использование кластерных систем в домене Xen
igor@0: не является обязательным, можно обойтись традиционными системами,
igor@0: такими как \textit{ext3}, \textit{XFS}, \textit{JFS}.
igor@0: 
igor@0: \subsection{DRBD: подготовка модуля ядра Linux}
igor@0: Процедуры подготовки DRBD
igor@0: для различных дистрибутивов Linux описаны здесь \htmladdnormallinkfoot{Howto Build and Install DRBD}{http://www.linux-ha.org/DRBD/HowTo/Install} (англ.).
igor@0: 
igor@0: В Debian GNU/Linux подготовка выполняется очень просто:
igor@0: 
igor@0: 1) Найти пакет с модулем ядра:
igor@0: \begin{verbatim}
igor@0:     %# apt-cache search drbd
igor@0:     drbd0.7-module-source - RAID 1 over tcp/ip for Linux module source
igor@0:     drbd0.7-utils - RAID 1 over tcp/ip for Linux utilities
igor@0:     drbd8-module-source - RAID 1 over tcp/ip for Linux module source
igor@0:     drbd8-utils - RAID 1 over tcp/ip for Linux utilities
igor@0:     drbdlinks - Manages symlinks into a shared DRBD partition
igor@0: \end{verbatim}
igor@0: 
igor@0: 2) Установить этот пакет:
igor@0: \begin{verbatim}
igor@0:     %# apt-get install drbd8-module-source
igor@0: \end{verbatim}
igor@0: 
igor@0: 3) Собрать и загрузить модуль ядра:
igor@0: \begin{verbatim}
igor@0:     %# module-assistant auto-install drbd8
igor@0: \end{verbatim}
igor@0: 
igor@0: \subsection{Настройка DRBD}
igor@0: Если инсталляция выполняется из архива исходных текстов,
igor@0: нужно прочитать \texttt{README}, \texttt{INSTALL}
igor@0: и \htmladdnormallinkfoot{DRBD/HowTo/Install}{http://www.linux-ha.org/DRBD/HowTo/Install}.
igor@0: Нужно также ознакомится с файлами \texttt{upgrade\(\ast{}\).txt}
igor@0: в каталоге \texttt{src/} drbd или непосредственно в репозитории проекта.
igor@0: 
igor@0: В дистрибутив входит хорошо прокомментированный конфигурационный файл-пример.
igor@0: В архиве исходных текстов он находится в \texttt{./scripts/drbd.conf};
igor@0: в пакетах может быть в одном из каталогов:
igor@0: \texttt{/usr/\{shared/,\}doc/packages/drbd}.
igor@0: 
igor@0: Нужно отредактировать этот файл в соответствии с вашими требованиями,
igor@0: а потом скопировать его на оба узла. Затем убедиться, что meta-disk\rq{}и
igor@0: находятся в правильных местах.
igor@0: Если вы настраиваете синхронизацию нескольких ресурсов,
igor@0: убедитесь, что в файле \texttt{/etc/drbd.conf}
igor@0: указаны разные порты (или разные IP) для этих ресурсов.
igor@0: 
igor@0: Пример фрагмента конфигурационного файла:
igor@0: \begin{verbatim}
igor@0: resource dns {
igor@0:     protocol C;
igor@0:     net {
igor@0:         allow-two-primaries;
igor@0:         after-sb-0pri discard-least-changes;
igor@0:         after-sb-1pri call-pri-lost-after-sb;
igor@0:         after-sb-2pri call-pri-lost-after-sb;
igor@0:     }
igor@0:     syncer {
igor@0:         rate 5M;
igor@0:     }
igor@0:     on dom0
igor@0:     {
igor@0:         device /dev/drbd1;
igor@0:         disk /dev/XEN/dns;
igor@0:         address 192.168.1.190:7792;
igor@0:         meta-disk /dev/XEN/meta[1];
igor@0:     }
igor@0:     on dom0m
igor@0:     {
igor@0:         device /dev/drbd1;
igor@0:         disk /dev/XEN/dns;
igor@0:         address 192.168.1.191:7792;
igor@0:         meta-disk /dev/XEN/meta[1];
igor@0:     }
igor@0: }
igor@0: \end{verbatim}
igor@0: 
igor@0: 
igor@0: Нужно обратить особое внимание на местоположение метадиска.
igor@0: Если DRBD не найдёт метаданных там, где он их ождиает, он создаст новые.
igor@0: Если вы укажите на неверное место, будут переписаны несколько килобайтов
igor@0: или даже несколько мегабайтов возможно полезных данных!
igor@0: Если использовать внутренний метадиск (\texttt{meta-disk=internal}),
igor@0: нужно обязательно уменьшить файловую систему раздела (если она там есть).
igor@0: 
igor@0: В настоящий момент метаданные DRBD забирают 128M,
igor@0: независимо от настоящего размера физических данных.
igor@0: В связи с этим маскимальный размер одного хранилища DRBD
igor@0: не может превышать ~4TB.
igor@0: 
igor@0: Скопируйте \texttt{drbd.conf} в \texttt{/etc/drbd.conf}
igor@0: на обоих узлах.
igor@0: После этого на обоих узлах выполните команду:
igor@0: \begin{verbatim}
igor@0:    %# drbdadm up all
igor@0: \end{verbatim}
igor@0: Узлы должны подняться и перейти в состояние \textit{Secondary} и \textit{Inconsistent}.
igor@0: 
igor@0: Последнее связано с тем, что хранилища на нижнем уровне не синхронизированы между собой, 
igor@0: и DRBD не знает откуда куда выполнять синхронизацию.
igor@0: Источник и, соответственно, направлени синхронизации нужно указать явным образом указать.
igor@0: Если данных нет, не имеет значения в какую сторону синхронизировать.
igor@0: Если есть файловая система, которая должна быть скопирована,
igor@0: указание неправильного направления приведёт к тому, что файловая система будет утеряна.
igor@0: 
igor@0: Выберите, какой из узлов будет \textit{primary} (если есть данные, то это должен
igor@0: быть узел, на котором они уже есть).
igor@0: После этого выполните:
igor@0: \begin{verbatim}
igor@0:   %# drbdsetup /dev/drbd1 primary -o
igor@0: \end{verbatim}
igor@0: или (для более старых версий)
igor@0: \begin{verbatim}
igor@0:    %# drbdadm -- --do-what-I-say primary all
igor@0: \end{verbatim}
igor@0: Команда установит одно из устройств /dev/drbd1 в основной режим (если быть точным, 
igor@0: то это будет устройство на той машине, где вызывалась команда).
igor@0: После этого должна выполниться полная синхронизация нижележащих устройств.
igor@0: 
igor@0: Устройство готово к использованию. Если у вас ещё нет файловой системы на нём,
igor@0: можно её создать прямо сейчас.
igor@0: 
igor@0: Теперь:
igor@0: \begin{itemize}
igor@0: \item  Смонтируйте DRBD-устройство на том узле, который находится в состоянии \textit{primary};
igor@0: \item  Отредактируйте какие-нибудь файлы;
igor@0: \item  Размонтируйте DRBD;
igor@0: \item  Переведите этот узел \textit{secondary}, а второй — \textit{primary};
igor@0: \item  Смонитруйте DRBD на новом узле;
igor@0: \item  Посмотрите изменения в файлах, которые вы сделали -- они должны были отразиться на втором узле.
igor@0: \end{itemize}
igor@0: 
igor@0: Устройство настроено и готово к использованию.
igor@0: 
igor@0: \subsection{Пример настройки}
igor@0: В этом примере используются устройства \texttt{/dev/drbdX}.
igor@0: Раньше использовались \texttt{/dev/nbX}.
igor@0: Исторически так сложилось что DRBD хищнечиски захватил
igor@0: мажорный номер NBD (43) и узлы устройств.
igor@0: Сейчас официально DRBD может использовать свой номер (147).
igor@0: В связи с этим начиная с версии 0.7.1
igor@0: по умолчанию используются свои номера устройств и названия файлов устройств.
igor@0: 
igor@0: Если система ничего не знает о \texttt{/dev/drbdX},
igor@0: нужно создать их командой наподобие такой:
igor@0: \begin{verbatim}
igor@0:   %# for i in $(seq 0 15) ; do mknod /dev/drbd$i b 147 $i ; done
igor@0: \end{verbatim}
igor@0: Подробнее можно почитать в файлах \texttt{upgrade\(\ast{}\).txt},
igor@0: упоминавшихся выше.
igor@0: 
igor@0: \begin{verbatim}
igor@0:     # administration ips of the nodes:
igor@0:     left=10.0.0.1
igor@0:     right=10.0.0.2
igor@0: 
igor@0:     vi drbd.conf
igor@0:     # double check.
igor@0:     scp drbd.conf $left:/etc/drbd.conf
igor@0:     scp drbd.conf $right:/etc/drbd.conf
igor@0: 
igor@0:     cmd='modprobe drbd; drbdadm up all; dmesg | tail; cat /proc/drbd'
igor@0:     ssh root@$left -- "$cmd"
igor@0:     ssh root@$right -- "$cmd"
igor@0: \end{verbatim}
igor@0: 
igor@0: Фрагмент из dmesg (или syslog) должен выглядеть так
igor@0: (в примере хранилище размером 5М).
igor@0: \begin{verbatim}
igor@0:     drbd: initialised. Version: 0.7.0 svn $Rev: 1442 $ (api:74/proto:74)
igor@0:     drbd: registered as block device major 147
igor@0: 
igor@0:     nb: to have it register as 43 (NBD) you can say
igor@0:     modprobe drbd use_nbd_major
igor@0: 
igor@0:     drbd0: Creating state block
igor@0:     drbd0: resync bitmap: bits=1250 words=40
igor@0:     drbd0: size = 5000 KB
igor@0:     drbd0: Assuming that all blocks are out of sync (aka FullSync)
igor@0:     drbd0: 5000 KB now marked out-of-sync by on disk bit-map.
igor@0:     drbd0: Handshake successful: DRBD Network Protocol version 74
igor@0:     drbd0: Connection established.
igor@0:     drbd0: I am inconsistent, but there is no sync? BOTH nodes inconsistent!
igor@0:     drbd0: Secondary/Unknown --> Secondary/Secondary
igor@0: \end{verbatim}
igor@0: 
igor@0: Файл /proc/drbd должен выглядеть так:
igor@0: \begin{verbatim}
igor@0:     %# cat /proc/drbd
igor@0:     version: 0.7.0 svn $Rev: 1442 $ (api:74/proto:74)
igor@0: 
igor@0:     0: cs:Connected st:Secondary/Secondary ld:Inconsistent
igor@0:         ns:0 nr:0 dw:0 dr:0 al:0 bm:1 lo:0 pe:0 ua:0 ap:0
igor@0: \end{verbatim}
igor@0: 
igor@0: Пусть \texttt{\$left} будет \textit{primary}:
igor@0: \begin{verbatim}
igor@0:     %# ssh root@$left -- "drbdadm primary all"
igor@0:     ioctl(,SET_STATE,) failed: Input/output error
igor@0:     Local replica is inconsistent (--do-what-I-say ?)
igor@0:     Command line was '/sbin/drbdsetup /dev/drbd0 primary'
igor@0:     drbdsetup exited with code 21
igor@0: \end{verbatim}
igor@0: 
igor@0: Замечание: Это приведёт к перезагрузке системы (!)
igor@0: 
igor@0: В действительности drbdadm просто выполняет команду \dq{}incon-degr-cmd\dq{}.
igor@0: Поскольку в примере был \dq{}halt -f\dq{},
igor@0: вы сами попросили о перезапуске.
igor@0: Возможно, лучше указать что-то менее жётское.
igor@0: Это можно сделать, указав в файле \texttt{drbd.conf}:
igor@0: 
igor@0: \begin{verbatim}
igor@0: incon-degr-cmd "echo 'DRBD: primary requested but inconsistent!' \
igor@0:   | wall; sleep 300000";
igor@0: \end{verbatim}
igor@0: 
igor@0: Ещё одна хорошая команда:
igor@0: 
igor@0: \begin{verbatim}
igor@0: killall -9 heartbeat ipfail ccm
igor@0: \end{verbatim}
igor@0: 
igor@0: Продолжаем.
igor@0: 
igor@0: \begin{verbatim}
igor@0: # ok, this was expected.
igor@0: # so double check that $left is the correct node.
igor@0: # then force it:
igor@0: ssh root@$left -- "drbdadm -- --do-what-I-say primary all"
igor@0: # which will succeed silently.
igor@0: 
igor@0: ## Bryce Porter suggests that:
igor@0: ## At this point, you need to connect the resource(s)
igor@0: # ssh root@$left -- "drbdadm -- connect all"
igor@0: #
igor@0: ## well, they should have been connected all along, see /proc/drbd excerpt above,
igor@0: ## so if this was neccessary, something "unexpected" happend already...
igor@0: ##     -- lge
igor@0: 
igor@0: ssh $left -- 'dmesg | tail ; cat /proc/drbd'
igor@0: # output is:
igor@0: drbd0: Resync started as SyncSource (need to sync 5000 KB [1250 bits set]).
igor@0: 
igor@0: version: 0.7.0 svn $Rev: 1442 $ (api:74/proto:74)
igor@0: 
igor@0:  0: cs:SyncSource st:Primary/Secondary ld:Consistent
igor@0:     ns:9276 nr:0 dw:0 dr:9404 al:0 bm:2 lo:0 pe:915 ua:32 ap:0
igor@0:         [=========>..........] sync'ed: 50.0% (4380/5000)K
igor@0:         finish: 0:00:05 speed: 620 (620) K/sec
igor@0: 
igor@0: # or, to give an example from a larger device:
igor@0:  0: cs:SyncSource st:Primary/Secondary ld:Consistent
igor@0:     ns:12940824 nr:0 dw:87492 dr:13690591 al:109 bm:1668 lo:1000 pe:1876 ua:1000 ap:0
igor@0:         [========>...........] sync'ed: 44.4% (15858/28487)M
igor@0:         finish: 0:09:20 speed: 28,933 (25,160) K/sec
igor@0: 
igor@0: # whereas on the other node:
igor@0: ssh $right -- 'dmesg | tail ; cat /proc/drbd'
igor@0: drbd0: Resync started as SyncTarget (need to sync 5000 KB [1250 bits set]).
igor@0: 
igor@0: version: 0.7.0 svn $Rev: 1442 $ (api:74/proto:74)
igor@0: 
igor@0:  0: cs:SyncTarget st:Secondary/Primary ld:Inconsistent
igor@0:     ns:0 nr:15000 dw:15000 dr:0 al:0 bm:6 lo:0 pe:0 ua:0 ap:0
igor@0:         [=========>..........] sync'ed: 50.0% (5000/5000)K
igor@0:         finish: 0:00:12 speed: 5 (5) K/sec
igor@0: 
igor@0: # or, to give an example from a larger device:
igor@0:  0: cs:SyncTarget st:Secondary/Primary ld:Inconsistent
igor@0:     ns:0 nr:27311780 dw:27311780 dr:0 al:0 bm:3447 lo:134 pe:493 ua:134 ap:0
igor@0:         [==================>.] sync'ed: 93.7% (1818/28487)M
igor@0:         finish: 0:01:07 speed: 27,482 (25,008) K/sec
igor@0: \end{verbatim}
igor@0: 
igor@0: Убедимся, что всё работает:
igor@0: 
igor@0: \begin{verbatim}
igor@0: # if you have no file system yet, create one
igor@0: # ssh root@$left -- 'mkreiserfs /dev/drbd0'
igor@0: 
igor@0: ssh root@$left -- \
igor@0:  'mkdir -p /mnt/ha0; mount /dev/drbd0 /mnt/ha0 && touch /mnt/ha0/been_there'
igor@0: 
igor@0: # 'switch over'
igor@0: ssh root@$left -- \
igor@0:  'umount /mnt/ha0 && drbdadm secondary all'
igor@0: # even during sync!
igor@0: ssh root@$right -- \
igor@0:  'drbdadm primary all'
igor@0: ssh root@$right -- \
igor@0:  'mkdir -p /mnt/ha0; mount /dev/drbd0 /mnt/ha0 && ls -l /mnt/ha0/been_there'
igor@0: \end{verbatim}
igor@0: 
igor@0: Обратите внимание, что хотя ошибки и не будет, но лучше так не делать:
igor@0: \textit{SyncTarget} можно сделать \textit{primary}, но в случае проблем с сетью будет паника из-за отсутствия доступа к правильным данным.
igor@0: Поэтому лучше так не делать никогда.
igor@0: 
igor@0: \subsection{Дополнительная информация}
igor@0: \begin{itemize}
igor@0: \item \htmladdnormallinkfoot{DRBD}{http://xgu.ru/wiki/DRBD} (рус.)
igor@0: \item \htmladdnormallinkfoot{DRBD}{http://www.drbd.org/} (англ.) — домашняя страница проекта DRBD
igor@0: \item \htmladdnormallinkfoot{DRBD FAQ}{http://www.linux-ha.org/DRBD/FAQ} (англ.)
igor@0: \item \htmladdnormallinkfoot{Howto Build and Install DRBD}{http://www.linux-ha.org/DRBD/HowTo/Install} (англ.) — процедура подготовки DRBD, в частности модуля ядра Linux
igor@0: \item \htmladdnormallinkfoot{Data Redundancy with DRBD}{http://www.drbd.org/drbd-article.html} (англ.) — статья о DRBD 0.6
igor@0: \item \htmladdnormallinkfoot{DRBD How To in the IBB Wiki}{https://services.ibb.gatech.edu/wiki/index.php/Howto:Software:DRBD} (англ.) — специфичное для RedHat (Fedora, RHEL, CentOS и других RedHat-based) описание процедуры поднятия DRBD
igor@0: \item \htmladdnormallinkfoot{Xen with DRBD, GNBD and OCFS2 HOWTO}{http://xenamo.sourceforge.net/index.html} (англ.) 
igor@0: \item \htmladdnormallinkfoot{CLVM Project Page}{http://sources.redhat.com/cluster/clvm/} (англ.) - кластерный LVM
igor@0: \item \htmladdnormallinkfoot{(openvz-wiki) HA cluster with DRBD and Heartbeat}{http://wiki.openvz.org/HA\_cluster\_with\_DRBD\_and\_Heartbeat} HA cluster with DRBD and Heartbeat (англ.) 
igor@0: \item \htmladdnormallinkfoot{DRBD, Xen und Heartbeat}{http://www.pro-linux.de/work/virtual-ha/virtual-ha5.html} (нем.)
igor@0: \item http://te.to/~ts1/xen\_cluster.html (англ.)
igor@0: 
igor@0: \subsubsection{Обсуждения}
igor@0: \item \htmladdnormallinkfoot{Sensible maximum number of drbd devices}{http://www.gossamer-threads.com/lists/drbd/users/10007} (англ.) - вопросы использования Xen и DRBD
igor@0: \item \htmladdnormallinkfoot{(DRBD-user) DRBD 8.0, how to manage a split-brain on Master-Master}{http://lists.linbit.com/pipermail/drbd-user/2005-September/003779.html} (англ.) 
igor@0: \item \htmladdnormallinkfoot{(Xen-devel) Debian, Xen and DRBD: Enabling true server redundancy}{http://lists.xensource.com/archives/html/xen-devel/2005-06/msg00544.html} (англ.) 
igor@0: \end{itemize}
igor@0: 




