Статья является пошаговым руководством по построению масштабируемого отказоустойчивого файлового хранилища, доступ к которому будет осуществлен по протоколам Samba, NFS. В качестве файловой системы, которая будет непосредственно отвечать за сохранение и масштабирование файловой шары будем использовать GlusterFS, о котором было уже достаточно написано хабрасообществом. Так как GlusterFS — часть Red Hat Storage, туториал написан для RH — like систем.



Каким же образом эти сервисы взаемодействуют?

GlusterFS

Использую версию 3.3.1, rpm-ки скачаны с официального сайта. После создания volume, клиент может получить к нему доступ несколькими способами:
  • # mount.glusterfs
  • # mount -o mountproto=tcp,async -t nfs
  • # mount.cifs

Мы будем использовать первый вариант, так как в этом случае клиент устанавливает связь со всеми серверами и при отказе сервера к которому мы монтировались, мы получаем данные с рабочих серверов:


CTDB

Отлично механика работы описана в этом посте. Хотелось бы добавить, что распределение нагрузки на кластер с использованием LVS в документации прописана только для сети NAT, по этому будем использовать Round Robbin DNS. Есть в стандартных репозиториях, так же как и SMB, NFS:
# yum install ctdb samba nfs-utils cifs-utils

Прис��упим

Допустим, у нас есть 2 ноды:
gluster1, 192.168.122.100
gluster2, 192.168.122.101

Еще необходима парочка IP, которые будут воплощать отказоустойчивость — мигрировать между серверами.
192.168.122.200
192.168.122.201

RR DNS для домена data выглядит так:

; zone file fragment
data. 86400 IN A 192.168.122.200
data. 86400 IN A 192.168.122.201

В создание volume для GlusterFS я углубляться не буду. Скажу, что нам необходимо распределенно — репликационный раздел (distributed+replicated volume). Назовём его smb. Для начала монтируем его локально для каждой ноды:

# mount.glusterfs gluster1:smb /mnt/glustersmb

Каждый сервер в качестве опции использует свой hostname . Не забываем занести запись в /etc/fstab.
Теперь правим конфигурацию Samba (на каждом сервере).

# vim /etc/samba/smb.conf

[global]
# Основной параметр, отвечает за кластеризацию.
clustering = yes
# Связь с БД, которая хранит обращения пользователей (см. ссылку про механику работы )
idmap backend = tdb2
# Папка, с конфигурационными файлами
private dir = /mnt/glustersmb/lock

И туда же добавим секцию самой шары:
[pub]
path = /mnt/glustersmb/lock
browseable = YES
force user = smbcli
force group = smbcli
writable = yes
guest ok = yes
guest account = smbcli
guest only = yes

Папка получится для общего пользования, доступ от пользователя smbcli без авторизации. Пожже создадим его и назначим права.
Тепер на одном из серверов создаем папку, в которой будем размещать некоторые конфигурационные файлы CTDB

# mkdir /mnt/glustersmb/lock
И добавим файл:
# touch /mnt/glustersmb/lock/lockfile

Конфигурационный файл CTDB на каждом сервере приводим к виду:
# vim /etc/sysconfig/ctdb
CTDB_RECOVERY_LOCK=/mnt/glustersmb/lock/lockfile
CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
CTDB_MANAGES_SAMBA=yes
CTDB_NODES=/etc/ctdb/nodes
CTDB_MANAGES_NFS=yes
# Файл, который исполняется каждый раз, когда нода кластера CTDB изменяет свой статус (например письмецо отправлять)
CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh

Указываем наши public adresses (на каждом сервере):
# vim /etc/ctdb/public_addesses
192.168.122.200/24 eth0
192.168.122.201/24 eth0

Указываем ноды кластера CTDB (на каждом сервере):
# vim /etc/ctdb/nodes
192.168.122.100
192.168.122.101

SElinux я отключаю, IPtables выглядят следующим образом (естественно, для каждого сервера):
# vim /etc/sysconfig/iptables
-A INPUT -p tcp --dport 4379 -j ctdb
-A INPUT -p udp --dport 4379 -j ctdb
-A INPUT -p tcp -m multiport --ports 137:139,445 -m comment --comment "SAMBA" -j SMB
-A INPUT -p udp -m multiport --ports 137:139,445 -m comment --comment "SAMBA" -j SMB
-A INPUT -p tcp -m multiport --ports 111,2049,595:599 -j NFS
-A INPUT -p udp -m multiport --ports 111,2049,595:599 -j NFS
-A INPUT -p tcp -m tcp --dport 24007:24220 -m comment --comment "Gluster daemon" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 38465:38667 -m comment --comment "Gluster daemon(nfs ports)" -j ACCEPT
# Вместо названия цепочек, можно укзать просто ACCEPT.

Вернемся к Samba и пользователю smbcli (на каждом сервере):
# useradd smbcli
# chown -R smbcli.smbcli /mnt/glustersmb/pub

Предпоследние штрихи:
# chkconfig smbd off
# chkconfig ctdb on
# service ctdb start

Теперь можно наблюдать
# ctdb status
Number of nodes:2
pnn:0 192.168.122.100 OK (THIS NODE)
pnn:1 192.168.122.101 OK
Generation:1112747960
Size:2
hash:0 lmaster:0
hash:1 lmaster:1
Recovery mode:NORMAL (0)
Recovery master:0

Список публичных мигрирующих IP и их приналежность к серверам получаем командой
# ctdb ip
Public IPs on node 0
192.168.122.200 node[1] active[] available[eth0] configured[eth0]
192.168.122.201 node[0] active[eth0] available[eth0] configured[eth0]

Монтируем клиенту по протоколу SMB или NFS командами:
# mount.cifs data:smb /mnt
# mount -o mountproto=tcp,async -t nfs data:smb /mnt

Из личного опыта скажу, что падения сети тестирую до сих пор, результат очень даже сносный. Обрыв соединения практически не заметен. В��е обьясняет AndreyKirov
Ликбез
Узел, который принял на себя IP адрес другого, знает о старых TCP соединениях только то, что они были, и не знает «TCP squence number» соединений. Соответственно, не может их продолжить. Также как и клиент, ничего не знает о том, что соединения теперь осуществляются с другим узлом.

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

Новый узел, получив себе ip адрес, посылает клиенту пакет с флагом ACK и заведомо неправильным «squence number» равным нулю. В ответ клиент, в соответствии с правилами работы протокола TCP, отправляет назад пакет ACK Reply с корректным «squence number». Получив корректный «squence number» узел формирует пакет с флагом RST и этим «squence number». Получив его, клиент незамедлительно перезапускает соединение.


Приятного коддинга!