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: