Создание высокопроизводительного отказоустойчивого кластера

Итак, первое что нужно будет сделать — это организовать связь между серверами по кросс-кабелю.

Предположим, что дополнительные сетевые карты видны в системе как eth0. Поднимем локальную сеть:

Первый сервер:
ifconfig eth0 192.168.1.1 up
Второй сервер:
ifconfig eth0 192.168.1.2 up

Проверяем — сервера должны пинговать друг-друга по этим IP. Если все в порядке, то нужно организовать автостарт этих IP, отредактировав файл/etc/network/interfaces:

Первый сервер:
auto eth0
iface eth0 inet static
    address 192.168.1.1
    netmask 255.255.255.0
Второй сервер:
auto eth0
iface eth0 inet static
    address 192.168.1.2
    netmask 255.255.255.0

Однако обращаться к серверам по IP неудобно. Назовем их node1 и node2, отредактировав файл /etc/hosts на каждом сервере:

192.168.1.1 node1
192.168.1.2 node2

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

В случае автоматической установки на серверах Hetzner большая часть дискового пространства отошла в программный raid /dev/md3, который подмонтирован в /home. Переделаем из него LVM, предварительно удалив строку монтирования из /etc/fstab:

На node1 и node2:
umount /dev/md3
apt-get install lvm2 psmisc
pvcreate /dev/md3
vgcreate datavg /dev/md3

Теперь создадим там два куска по 5G для Apache и MySQL:

На node1 и node2:
lvcreate -L 5G -n apache datavg
lvcreate -L 5G -n mysql datavg

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

А вот с Apache ситуация иная. Там потребуется общий диск и кластерная файловая система. Кроме того нужно будет следить за тем, чтобы при выходе любого из компонент кластера (общем диске, кластерной файловой системе или apache) на каком-то из серверов, отключить там все и перевести его в «аварийное» состояние, мигрировав IP аварийного сервера на оставшийся рабочий.

Сначала установим и настроим drbd. На обоих серверах выполняем команду:

apt-get install drbd-utils

Создаем общий сетевой диск с пропускной способностью 30%. Для этого в конфиге диска необходимо прописать:

 

syncer {

    rate 33M;

    ...

  }

Учтите, что это значение оптимально для гигабитного канала!
Включаем режим dual primary в drbd, создав на node1 и node2 файл/etc/drbd.d/r1.res с содержимым (диски замените на свои):

 

 

global {

        usage-count no;

}

resource r0 {


        protocol C;


        startup {

                #become-primary-on both;

        }

        net {

                # allow-two-primaries;

                after-sb-0pri discard-zero-changes;

                after-sb-1pri discard-secondary;

                after-sb-2pri disconnect;

        }


        on node1 {

                device     /dev/drbd0;

                disk       /dev/datavg/apache;

                address    192.168.1.1:7788;

                meta-disk  internal;

        }


       on node2 {

                device     /dev/drbd0;

                disk       /dev/datavg/apache;

                address    192.168.1.2:7788;

                meta-disk  internal;

        }


}
На node1 выполняем:
invoke-rc.d drbd restart

drbdadm attach r0

drbdadm syncer r0

drbdadm connect r0

 

 

На node2 выполняем:
invoke-rc.d drbd restart

drbdadm attach r0

drbdadm syncer r0

drbdadm connect r0
Выполняем синхронизацию:
drbdadm -- --overwrite-data-of-peer primary r0
Для ускореняи первоначальной синхронизации можно временно отдать всю пропускную способность при помощи команды
drbdsetup /dev/drbd1 syncer -r 80M

Наблюдать процесс синхронизации в реальном режиме времени можно при помощи команды

watch  cat /proc/drbd

 

После завершения синхронизации активируем dual primary, разрешая запись на обоих дисках паралельно. Для этого надо расскомментировать в конфиге опции:

 

 startup {

                become-primary-on both;

        }

        net {

                allow-two-primaries;

                ...

        }

        ...

 

 

И перезапустить drbd на обеих нодах:

 

invoke-rc.d drbd restart

drbdadm disconnect r0

drbdadm connect r0

drbdadm primary r0

Теперь ставим кластерную файловую систему ocsf2, установив на обоих нодах:
apt-get install ocfs2-tools ocfs2console

echo "O2CB_ENABLED=true" >> /etc/default/o2cb

 

И создав конфиг /etc/ocfs2/cluster.conf на обоих нодах:
node:

        ip_port = 7777

        ip_address = 192.168.1.1

        number = 0

        name = node1

        cluster = ocfs2

node:

        ip_port = 7777

        ip_address = 192.168.1.2

        number = 1

        name = node2

        cluster = ocfs2

cluster:

        node_count = 2

        name = ocfs2
На node1:
invoke-rc.d o2cb restart

invoke-rc.d ocfs2 restart

mkfs -t ocfs2 -N 2 -L ocfs2_drbd0 /dev/drbd0
Теперь у нас есть общая файловая система. Переходим к настройке кластера.

 

Но прежде отключаем автозапуск drbd и apache на node1 и node2. Теперь этим будет управлять кластер.

update-rc.d -f drbd remove
update-rc.d -f apache2 remove

Настраиваем кластер, выполнив на обеих нодах:

 

apt-get install pacemaker
На node1:
corosync-keygen

scp /etc/corosync/authkey node2:
На node2:
mv ~/authkey /etc/corosync/authkey

chown root:root /etc/corosync/authkey

chmod 400 /etc/corosync/authkey
Создадим конфиг /etc/corosync/corosync.conf:
totem {

version: 2

token: 3000

token_retransmits_before_loss_const: 10

join: 60

consensus: 4320

vsftype: none

max_messages: 20

clear_node_high_bit: yes

  secauth: on

  threads: 0

  rrp_mode: none

  interface {

ringnumber: 0

bindnetaddr: 192.168.1.0

mcastaddr: 226.94.1.1

mcastport: 5405

}

}

amf {

mode: disabled

}

service {

  ver:       0

  name:      pacemaker

}

aisexec {

        user:   root

        group:  root

}

logging {

    fileline: off

    to_stderr: yes

    to_logfile: no

    to_syslog: yes

syslog_facility: daemon

        debug: off

        timestamp: on

        logger_subsys {

            subsys: AMF

            debug: off

            tags: enter|leave|trace1|trace2|trace3|trace4|trace6

        }

}
И запускаем его на обеих нодах:
/etc/init.d/corosync restart
Осталось его сконфигурировать при помощи crm, запустив на одной из нод crm configure и ввести готовый конфиг кластера:

node node1

node node2

primitive apache_app ocf:heartbeat:apache \

params configfile=»/etc/apache2/apache2.conf» httpd=»/usr/sbin/apache2″ port=»80″ statusurl=»http://127.0.0.1:80/server-status» testregex=»Apache» \

op monitor interval=»30s»

primitive apache_fs ocf:heartbeat:Filesystem \

params device=»/dev/drbd0″ directory=»/var/www» fstype=»ocfs2″

primitive drbd1 ocf:linbit:drbd \

params drbd_resource=»r0″ \

operations $id=»drbd1-ops» \

op monitor interval=»20″ role=»Master» timeout=»20″ \

op monitor interval=»30″ role=»Slave» timeout=»20″

ms drbd1_ms drbd1 \

meta resource-stickines=»100″ master-max=»2″ notify=»true» interleave=»true» target-role=»Started»

clone apache_fs_clone apache_fs \

meta interleave=»true» ordered=»true» target-role=»Started»

clone www apache_app \

meta interleave=»true» ordered=»true» target-role=»Started»

order ocfs_after_drbd1 inf: drbd1_ms:promote apache_fs_clone:start

order www_after_ocfs inf: apache_fs_clone:start www:start

property $id=»cib-bootstrap-options» \

dc-version=»1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b» \

cluster-infrastructure=»openais» \

expected-quorum-votes=»2″ \

stonith-enabled=»false» \

no-quorum-policy=»ignore» \

last-lrm-refresh=»1326795041″

rsc_defaults $id=»rsc-options» \

resource-stickiness=»100″

commit
Поздравляю! Кластер настроен и готов к работе.
Теперь осталось только настроить Failover IP, чтоб в случае недоступности одного из серверов его IP переходил на соседний: http://wiki.hetzner.de/index.php/Failover_Konfiguration/ru