В 2016 году исполнилось 10 лет с момента появления концепции "облачных" вычислений. За прошедшее время в IT-отрасли не только определились основные "игроки", но и сам термин устоялся, а провайдеры услуг уже не боятся испугать клиентов предложением "облачных" услуг.
В 2016 году исполнилось 10 лет с момента появления концепции "облачных" вычислений в 2006 году. За прошедшее время в IT-отрасли не только определились основные "игроки", такие как Amazon (EC2), Google (GCE), Microsoft (Azure), появились OpenSource-решения (OpenStack, OwnCloud, Seafile), но и сам термин устоялся, а провайдеры услуг уже не боятся испугать клиентов предложением "облачных" услуг. Примером, могут служить разнообразные хостинги предлагающие своим клиентам VPS, и даже частные "облака" на базе OpenStack. Несколько проигрывая в надёжности относительно классической виртуализации (XEN, VMWare, Hyper-V), они предлагают услуги хостинга дешевле.
Большинство клиентов не имеет сайтов исполняющих задачи требующие надёжности 99,671% предоставляемой в ЦОД уровня Tier-1 (это задачи характерные скорее для рынка биржевых товаров, ценных бумаг, валют и др. финансовых инструментов в которых минуты простоя влекут для клиента несоизмеримый ущерб). Для большинства клиентов важнее не потерять основную массу посетителей сайта за сколько-то значимый % времени в течении суток. Отсюда напрашивается необходимость резервирования сайта с использованием технологий доступных на рынке (в том числе OpenSource-решений).
Объединяя первые два тезиса можно заключить, что принципиально возможным является создание относительно дешёвого отказоустойчивого кластера с использованием общедоступных технологий и VPS предоставляемых разными провайдерами услуг на базе "облачных" вычислений. При этом мы можем выбирать VPS разной надёжности по шкале Tier и различающихся по географии ЦОД.
Наиболее простым и дешёвым является обеспечение отказоустойчивости web-сервера через поднятие на каждом VPS собственного NS-сервера с указанием сокращённого времени жизни зоны. Такая схема достаточно распространена и применяется, например на online.sbis.ru. Схема обеспечивает что через максимум 1 мин. все посетители не сумевшие попасть на сайт уйдут на работающий VPS. На практике же не наблюдается даже такая задержка, посетитель не может заметить что одна (и даже две) ноды перестали работать.
БД для всех нод кластера едина и представлена в виде кластера Percona Xtra DB 5.6. Кластер MySQL настроен по схеме Multi-Master репликации. Это означает что изменение в БД на любой из нод будут синхронизированы и внесены в БД двух других. 3 ноды являются технологически минимально необходимым числом нод для кластера MySQL, независимо от применяемого решения (MySQL/Percona/MariaDB и т.д.). Также, кластер MySQL требует чтобы БД помещалась в памяти целиком. Это необходимо для успешной репликации. Увеличение производительности при возрастании нагрузки на кластер MySQL м.б. достигнуто увеличением числа нод и подключением к каждой из Master-нод по 1-2 Slave-нод. Хорошим показателем нагрузки на каждую из нод является число тредов MySQL в мониторинге Zabbix. Увеличение их числа свидетельствует либо о росте нагрузки, либо об увеличении числа медленных запросов к БД.

На каждой ноде кластера запускается демон Lsyncd который через подсистему Inotify в ядре Linux следит за событиями изменения локального дерева файлов, собирая эту информацию каждые 10 сек. При обнаружении изменения он отправляет новые или изменённые файлы на соседние ноды через rsync. Передача происходит с параметром update, т.е. файл на получателе будет заменён только если отправляемый оказался новей. Это даёт возможность избежать коллизий и лишних операций.

# yum install php-xmlseclibs php-xmlrpc php-bcmath php-dba php-pecl-sqlite # localedef ru_RU.UTF-8 -i ru_RU -fUTF-8 # mv -f /etc/php.d/20-sqlite3.ini.disabled /etc/php.d/20-sqlite3.ini # mv -f /etc/php.d/30-mysqli.ini.disabled /etc/php.d/30-mysqli.ini # mv -f /etc/php.d/30-xmlreader.ini.disabled /etc/php.d/30-xmlreader.ini # yum install memcached # chkconfig memcached on
# cd /tmp ; wget http://repos.1c-bitrix.ru/yum/bitrix-env.sh # chmod a+x bitrix-env.sh # ./bitrix-env.sh && rm -rf bitrix-env.sh
# service mysqld stop # rpm --nodeps -e mysql-server mysql mysql-libs # yum install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm # yum install Percona-XtraDB-Cluster-56 # service mysql start # mysql_upgrade
Конфиги по умолчанию находятся здесь:
# yum -y install lsyncd
В /etc/hosts прописываем на всех нодах статику:
<ip1> node01 # node01.domain.tld <ip2> node02 # node02.domain.tld <ip3> node03 # node03.domain.tld
В /etc/sysctl.conf прописываем на всех нодах:
# lsyncd inotify limit fs.inotify.max_user_watches = 16777216 # сколько файлов может отслеживать один пользователь; 8192 default fs.inotify.max_queued_events = 65536 # максимальное число событий в очереди; 16384 default
В /etc/lsyncd.conf пишем:
settings{
logfile = "/var/log/lsyncd/lsyncd.log",
statusFile = "/var/log/lsyncd/lsyncd.status",
statusInterval = 5, --<== чтобы видеть что происходит без включения подробного лога
nodaemon = false,
}
-- node01 (node.domain.tld)
sync{
-- метод синхронизации
default.rsyncssh,
-- задержка обработки очереди после поступления события
delay = 3,
-- отслеживаемый каталог
source = "/home/bitrix/www/static/",
-- целевая нода, доступ по ssh
host = "node01",
-- целевой каталог на удалённом хосте
targetdir="/home/bitrix/www/static/",
-- файлы и каталоги, исключаемые из синхронизации
exclude = {
"/.htaccess",
"/assets/",
"/fonts/",
"/images/",
"/not_image/",
},
-- Опции для rsync на удалённой стороне
rsync = {
binary = "/usr/bin/rsync",
ipv4 = true,
ipv6 = false,
acls = true,
perms = true,
owner = true,
archive = false,
compress = false,
update = true,
sparse = true,
_extra = { "-ausS", "--temp-dir=/tmp" },
verbose = false,
},
}
Тестируем (и смотрим /var/log/lsyncd/lsyncd.log):
# lsyncd -nodaemon /etc/lsyncd.conf
Ставим NS в chroot:
# yum install bind bind-chroot
В /etc/resolv.conf пишем (помним про dhcp):
nameserver 127.0.0.1 nameserver 8.8.8.8
/etc/hosts дополняем:
# Percona cluster <ip1> node01.domain.tld <ip2> node02.domain.tld <ip3> node03.domain.tld # NS continuity <ip1> ns1.domain.tld <ip2> ns2.domain.tld <ip3> ns3.domain.tld
Заполняем chroot, проставляем права:
# cd /var/named/chroot/var/log && mkdir named && chown named. named # cd /var/named/chroot/etc/ # cp /etc/named.rfc1912.zones /var/named/chroot/etc/named.rfc1912.zones # cp /etc/named.root.key /var/named/chroot/etc/named.root.key # cp /var/named/named* /var/named/chroot/ # chown :named named.rfc1912.zones # chown :named named.root.key
Создаём зоны (прямую и обратную):
# touch /var/named/data/domain.tld.zone # chown :named /var/named/data/domain.tld.zone # chmod 640 /var/named/data/domain.tld.zone # touch /var/named/data/<ip1-reverse>.zone # chown :named /var/named/data/<ip1-reverse>.zone # chmod 640 /var/named/data/<ip1-reverse>.zone
Создаём файл для сбора статистики:
# touch /var/named/data/named_stats.txt # chown :named /var/named/data/named_stats.txt # chmod 640 /var/named/data/named_stats.txt
Пишем прямую зону:
$TTL 60
$ORIGIN domain.tld.
@ IN SOA ns1.domain.tld. info.domain.tld. ( ; имя_зоны IN SOA первичный_NS e-mail_администратора_NS
2016072502 ; Serial
10800 ; Refresh 3H (как часто вторичные NS опрашивают первичный)
3600 ; Retry 1H (время ожидания после неудачной попытки опроса)
604800 ; Expire 168H (максимальное время валидности данных о зоне)
86400 ) ; Minimum 24H (минимальное время хранения зоны в кэше вторичного NS)
;;; NS ;;;
IN NS ns1.domain.tld.
IN NS ns2.domain.tld.
IN NS ns3.domain.tld.
;;; MX ;;;
IN MX 5 mx.domain.tld.
IN MX 10 mail.domain.tld.
;;; only for NS1 ;;;
IN A <ip1> ; domain.tld..
www CNAME @
;;; A ;;;
ns1 IN A <ip1> ; ns1.domain.tld.
ns2 IN A <ip2> ; ns2.domain.tld.
ns3 IN A <ip3> ; ns3.domain.tld.
node01 IN A <ip1> ; node01.domain.tld.
node02 IN A <ip2> ; node02.domain.tld.
node03 IN A <ip3> ; node03.domain.tld.
;;; TXT ;;;
@ IN TXT "v=spf1 include:_spf.domain.tld -all"
@ IN SPF "v=spf1 include:_spf.domain.tld -all"
Пишем named.conf
options {
listen-on port 53 { any; };
listen-on-v6 port 53 { none; }; // Отключаем работу на интерфейсе ipv6
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
listen-on { <ip1>; };
version "dns by oev"; // Скрываем версию DNS
allow-query { any; }; // Обычные запросы разрешаем всем
allow-recursion { none; }; // Рекурсивные запросы запрещаем
auth-nxdomain no; // Не позволяет серверу отвечать авторитетно, если запрошенный домен не существует (RFC1035)
forward only; // Собственный поиск несуществующих доменов не производится, отправляем в forwarders
forwarders { }; // Иначе будет DDoS, сейчас через DNS ботами управляют сволочи
// forwarders { <ip1>; <ip2>; }; // ns1.domain.tld, ns2.domain.tld
};
key "rndc-key" {
algorithm hmac-md5;
secret "j/BLA+LA/BlAbla/bLAbLA==";
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
// описание корневых серверов
zone "." IN {
type hint;
file "named.ca";
};
zone "domain.tld" IN {
type master;
file "data/domain.tld.zone";
allow-update { none; };
};
zone "<ip1-reverse>.in-addr.arpa" IN {
type master;
file "data/<ip1-reverse>.zone";
allow-update { none; };
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
logging {
channel default_file {
file "/var/log/named/default.log" versions 3 size 5m;
severity dynamic;
print-time yes;
};
category default { default_file; };
};
Генерируем секрет в rndc.key
cd /var/named/chroot/etc/ rndc-confgen > rndc.key cp rndc.key /etc/rndc.key
из /etc/rndc.key удаляем options. key и controls из rndc.key добавляем в /var/named/chroot/etc/named.conf
Проверяем на ошибки:
# named-checkconf /var/named/chroot/etc/named.conf