Доступная отказоустойчивость для вашего сайта
Возможно, вы уже попадали в ситуацию, когда во время пика продаж сервер, на котором расположен ваш интернет-магазин или другой проект, приносящий прибыль, выходит из строя.
К сожалению, даже надежная техника может отказать в самый неподходящий момент. На сервере могут возникнуть проблемы с дисками, дисковыми и сетевыми контролерами, оперативной памятью, блоком питания и другим оборудованием. В дата-центре, где находится ваш сервер, могут отказать каналы передачи данных, электропитание или даже случиться пожар.
Конечно, можно отремонтировать сервер или установить новый в том же или в другом дата-центре. Но на ремонт или аренду нового сервера с последующей подготовкой его к работе, на восстановление данных из бекапа может уйти очень много времени.
А есть ли способы защитить ваш интернет-магазин или другой сервис от таких проблем?
Да, конечно, есть, и не один, но также есть и множество нюансов.
К сожалению, обычно отказоустойчивое решение стоит очень и очень дорого. Даже в простых конфигурациях ежемесячные расходы могут достигать 100–200 тысяч рублей и больше. Немало средств придется потратить и на первоначальную настройку. Но есть и недорогие решения.
Эта статья поможет вам настроить доступный вариант отказоустойчивости, созданный на базе технологии VRRP (Virtual Router Redundancy Protocol) и сервиса keepalived.
Такой вариант подойдет, если у вас нет возможности использовать, например, весьма дорогостоящие в эксплуатации контейнеры, систему Kubernetes или отказоустойчивые облака, а весь проект размещается на одном сервере. Описанная в статье технология будет полезна, если многократное увеличение расходов на оборудование и сопровождение при внедрении отказоустойчивости крайне нежелательно.
Наивная реализация отказоустойчивости
Если мы защищаем наш интернет-магазин от отказа сервера или проблем в датацентре, не будет ли достаточно просто арендовать резервный сервер в другом датацентре, а затем настроить репликацию данных?
На рис. 1 показан такой вариант, когда серверы расположены в разных датацентрах и у них разные адреса IP (адреса IP показаны только для примера).
Здесь сервер m01host играет роль основного сервера (MASTER-сервер), а сервер s01host — резервного (BACKUP-сервер). Если в проекте используется СУБД, то настраивается репликация базы данных с основного сервера на резервный. Репликацию файлов можно организовать, например, при помощи rsync.
Если основной сервер интернет-магазина или дата-центр, в котором этот сервер расположен, выйдут из строя, то резервный сервер будет содержать актуальные данные. Теперь достаточно изменить запись A домена сайта интернет-магазина в DNS, указав там адрес IP резервного сервера вместо основного и, казалось бы, интернет-магазин сможет снова работать.
Но тут есть нюанс. Проблема в том, что на распространение изменений в DNS может уйти очень много времени, от нескольких часов до 2–3 дней. И все это время сайт интернет-магазина будет недоступен всем или части пользователей.
Также может оказаться, что зоны DNS домена хранятся у того же провайдера, где находится ваш сервер. Если дата-центр провайдера отказал, то будет невозможно даже внести изменения в DNS. Именно поэтому рекомендуется зоны доменов хранить отдельно, на ресурсах таких регистраторов доменов или провайдеров, которые обеспечивают отказоустойчивость при хранении зон.
А можно ли каким-либо образом обеспечить переключение сайта с основного сервера на резервный без изменений в DNS?
Да, такая возможность имеется, и она реализуется различными способами.
Реальные способы обеспечения отказоустойчивости
Существуют различные отказоустойчивые решения, допускающие быстрое переключение сайта с отказавшего сервера на работоспособный, например, отказоустойчивые облака или отказоустойчивые балансировщики.
Провайдер, предоставляющий отказоустойчивое облако, изолирует вас от всех проблем с аппаратным обеспечением. Если какое-либо оборудование провайдера выйдет из строя, то оно автоматически будет заменено исправным и ваше приложение этого даже не заметит.
Но тут нужно учесть три неприятных момента.
Во-первых, отказоустойчивость всегда обеспечивается за счет резервирования оборудования. Поэтому стоимость ресурсов в отказоустойчивых облаках очень высока и нужно решить, готовы ли вы тратить такие средства.
Во-вторых, скорость доступа к сетевым дисковым устройствам обычно ниже скорости доступа к локальным дискам SSD и NVMe, что может отрицательно сказаться на производительности СУБД. Да, в облаках есть скоростные сетевые диски, но они стоят дорого.
В-третьих, облачные провайдеры могут тарифицировать исходящий трафик. Если вы ежедневно копируете данные бекапов к другому провайдеру, то это может привести к значительным расходам. А держать проекты и данные резервных копий этих проектов у одного и того же провайдера едва ли целесообразно с точки зрения сохранности данных.
Еще есть решение на базе отказоустойчивых балансировщиков нагрузки. Такие балансировщики могут исключить направление трафика на отказавшие узлы, однако сами по себе они не решают всех проблем, в частности проблемы отказоустойчивости базы данных.
Также относительно недорого можно реализовать отказоустойчивость с помощью системы виртуализации Proxmox VE. В этом случае вам потребуются как минимум три узла Proxmox VE, а также сетевое хранилище данных. При добавлении узлов виртуальных машин в репликацию и настройке для них отказоустойчивости выход из строя одного из узлов Proxmox VE не приведет к длительной остановке виртуальной машины. Виртуальная машина будет автоматически перемещена на исправный узел и продолжит свою работу с тем же адресом IP. Обратное перемещение нужно будет делать вручную.
Но самым бюджетным и достаточно надежным способом реализации отказоустойчивости сайта, работающего на одном выделенном сервере, оказалось использование VRRP и keepalived.
Применение VRRP и keepalived
VRRP — это сетевой протокол увеличения доступности маршрутизаторов, выполняющих роль шлюза по умолчанию. Если кратко, то VRRP совместно с сервисом keepalived обеспечит быстрый перенос адреса IP с главного сервера на резервный при отказе главного сервера.
Так как адрес IP при этом останется тем же самым, то никаких настроек в DNS изменять не потребуется. Такой адрес IP еще называют «плавающим», потому что он может переходить с одного сервера на другой, или виртуальным (Virtual IP, VIP).
При использовании VRRP и keepalived, а также при настроенной репликации базы данных и файлов после переключения сервера с основного на резервный интернет-магазин автоматически продолжит свою работу уже на резервном сервере. Время переключения задается в файле конфигурации keepalived и может измеряться секундами или минутами.
А есть ли проблемы при использовании VRRP и keepalived?
Да, есть. И основная проблема — сложность автоматизации обратного переключения с резервного сервера на основной, особенно при использовании репликации базы данных. В то время как переключение на резервный сервер при выходе из строя основного происходит автоматически, обратное переключение по ряду причин приходится делать вручную.
С другой стороны, при выходе из строя основного сервера работа интернет-магазина или другого вашего сервиса не прекратится. При правильной настройке мониторинга администратор получит извещение о таком переключении и сможет сделать обратное переключение вручную, в плановом режиме. И в такое время, когда количество обращений к сервису будет минимально.
В некоторых компаниях, например, в Селектел, вы можете взять в аренду готовую отказоустойчивую сеть VRRP, объединяющую дата-центры из разных городов всего за несколько тысяч рублей в месяц. Добавьте к этому стоимость аренды или размещения в дата-центре двух серверов подходящей мощности, и вы получите ежемесячные затраты на отказоустойчивое решение.
Также вы можете заказать пару серверов и недорогую отказоустойчивую сеть с плавающим IP в компании Servers.ru, которая позволит защитить ваш интернет-магазин от отказа сервера или дата-центра с помощью keepalived.
Тестирование перед заказом сети VRRP
Если вы собираетесь испытать сервис keepalived, то для этого можно создать две виртуальные машины при помощи, например, VMware Workstation Pro. При этом на время отладки вам не придется арендовать у провайдера два сервера и сеть.
В процессе тестирования вы сможете настроить файлы конфигурации keepalived и вспомогательные скрипты. А когда все будет готово, закажите серверы и сеть VRRP у провайдера. Селектел, например, выделит вам подсеть /29 из шести адресов IP:
служебный адрес IP;
широковещательный адрес;
четыре свободных адреса IP
Вам также будет предоставлена маска подсети 255.255.255.248 и адрес шлюза по умолчанию.
Что касается свободных адресов, то один из них нужно будет задействовать в роли плавающего IP, который будет переходить от главного сервера к резервному. При этом у вас останется еще три адреса IP для ваших серверов.
Установка keepalived
Расскажем о том, как провести установку и отладку конфигурации keepalived на виртуальных машинах VMware Workstation Pro.
Сразу заметим, что обычно провайдеры могут объединить в сеть VRRP только физические серверы, а не виртуальные.
Итак, с помощью VMware Workstation Pro создадим две виртуальные машины Debian 11 и установим на них сервис keepalived.
Используем следующее распределение адресов и настройки сети:
192.168.0.182: мастер-узел m01host (MASTER);
192.168.0.181: резервный узел s01host (BACKUP);
192.168.0.179: плавающий IP (виртуальный IP, VIP);
192.168.0.1: шлюз по умолчанию и сервер DNS;
255.255.255.0: маска сети
Если это возможно, при создании виртуальных машин в VMware Workstation Pro выделите для них по 8 Гбайт оперативной памяти, по 80 Гбайт дисковой памяти и по четыре ядра процессора (или задайте больше ресурсов, если это требует ваш сайт).
Обязательно укажите Network connection как Bridged.
Установка необходимых пакетов и модулей
Установите на главном и резервном серверах Exim для отправки сообщений об изменении состояния keepalived по электронной почте:
# apt-get install exim4
Разрешите отправку почты через интернет:
# dpkg-reconfigure exim4-config
Для тестирования репликации базы данных установите на обоих серверах MariaDB:
# apt install mariadb-server
Задайте пароль пользователя root для главного сервера:
# mysql -u root
> ALTER USER 'root'@'localhost' IDENTIFIED BY 'master_password';
> FLUSH PRIVILEGES;
Также аналогичным образом задайте пароль пользователя root для резервного сервера:
> ALTER USER 'root'@'localhost' IDENTIFIED BY 'slave_password';
Настройте безопасность MariaDB на каждом сервере, разрешив доступ к СУБД через сокеты:
# mysql_secure_installation
Установите пакеты gcc и make:
# apt install gcc make
Также вам потребуются модули Perl, которые можно установить при помощи cpan:
File::Slurp
File::Copy
Sys::Hostname
Data::Dumper
И, наконец, установите сервис keepalived в ОС Debian 11 на главном и резервном сервере:
# apt install keepalived
При необходимости на сайте https://keepalived.readthedocs.io/en/latest/installing_keepalived.html вы найдете инструкции по установке keepalived для этой и других ОС.
Конфигурирование keepalived на главном сервере
После установки основных пакетов и модулей необходимо настроить конфигурацию keepalived, отредактировав файл /etc/keepalived/keepalived.conf на главном и резервном сервере.
Для главного сервера конфигурация должна быть такой (адреса электронной почты и адреса IP показаны только для примера):
global_defs {
notification_email {
admin@domain.ru
}
notification_email_from admin-vrrp@domain.ru
smtp_server 127.0.0.1
smtp_connect_timeout 60
router_id master
}
vrrp_instance my_site {
#state MASTER
interface ens33
virtual_router_id 77
priority 180
nopreempt
advert_int 5
smtp_alert
notify /home/frolov/keepalivednotify.pl root
virtual_ipaddress {
192.168.0.197/24
}
}
В самом начале файла конфигурации располагается блок глобальных определений global_defs. Здесь нужно разместить информацию о том, как и куда keepalived сможет отправлять сообщения электронной почты при изменении состояния узла.
Укажите здесь адрес электронной почты системного администратора notification_email, а также адрес notification_email_from, от имени которого будет приходить почта.
Также необходимо задать в параметре smtp_server адрес IP сервера SMTP и таймаут при отправке почты smtp_connect_timeout.
Необязательный параметр router_id предназначен для идентификации узла. По умолчанию здесь используется имя хоста, а мы указали строку «master».
Блок vrrp_instance задает параметры работы с VRRP. Строка после vrrp_instance используется для идентификации блока VRRP, и здесь можно указать, например, название сайта интернет-магазина. Это название должно быть одинаковым в файле конфигурации как для главного, так и для резервного сервера. Мы указали строку «my_site».
Параметр state задает начальное состояние узла при запуске keepalived. Он может иметь значение «MASTER» для основного сервера или «BACKUP» для резервного. Причины, по которой эта строка закрыта символом комментария, будут рассмотрены позже, при описании схем переключения с главного сервера на резервный и обратно.
Параметр interface задает имя сетевого интерфейса на сервере. Вы можете узнать его, например, командой ip -a:
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
В данном случае используется имя «ens33».
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:34:5f:6c brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 192.168.0.181/24 brd 192.168.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe34:5f6c/64 scope link
valid_lft forever preferred_lft forever
При настройке keepalive обязательно уточните имена сетевых интерфейсов на ваших серверах. При ошибке перенос виртуального адреса IP с главного сервера на резервный работать не будет.
Параметр virtual_router_id задает идентификатор блока VRRP, и он также должен быть одинаковый для главного и резервного серверов.
При помощи параметра priority нужно задать приоритет блока VRRP (от 1 до 255). Для главного сервера этот приоритет должен быть выше, чем для резервного. Если в сети VRRP два или несколько узлов, то в состояние MASTER переводится узел с наибольшим значением приоритета.
Если задан параметр nopreempt, параметр state должен иметь значение BACKUP, или он не должен указываться. Мы задаем этот параметр для того, чтобы предотвратить автоматическое переключение главного сервера в состояние MASTER, если этот сервер был какое-то время недоступен.
Параметр advert_int задает периодичность в секундах, с которой главный узел сообщает о себе с помощью широковещательного уведомления. Если в течение периода времени, заданного этим параметром, резервные узлы не получают уведомления от мастера, начинается выбор нового мастера на основе приоритета, заданного параметром priority.
Параметр smtp_alert активирует отправку сообщения об изменении состояния по электронной почте. Параметры отправки задаются в ранее описанном блоке global_defs.
Если при изменении состояния узла нужно выполнять какие-либо действия, следует задать в параметре notify пусть к скрипту. Этот скрипт будет запущен, если состояние узла изменится. В параметре notify можно указать имя пользователя операционной системы, с правами которого будет запущен скрипт. Наш скрипт будет изменять файл конфигурации MariaDB, поэтому тут нужны права пользователя root.
И, наконец, блок virtual_ipaddress задает виртуальный адрес IP, который будет переходить с главного сервера на резервный, если главный сервер окажется недоступен.
Описание перечисленных выше параметров можно найти в документации keepalived.
Конфигурация keepalived резервного сервера
На резервном сервере подготовьте в файле /etc/keepalived/keepalived.conf другую конфигурацию (адреса электронной почты и адреса IP показаны только для примера):
global_defs {
notification_email {
admin@domain.ru
}
notification_email_from admin-vrrp@domain.ru
smtp_server 127.0.0.1
smtp_connect_timeout 60
router_id backup
}
vrrp_instance my_site {
state BACKUP
interface ens33
virtual_router_id 77
priority 100
nopreempt
advert_int 5
smtp_alert
notify /home/frolov/keepalivednotify.pl root
virtual_ipaddress {
192.168.0.197/24
}
}
Как видите, здесь параметр state задает начальное состояние узла как BACKUP. В параметре router_id узел идентифицируется строкой «backup».
Кроме того, приоритет для резервного сервера priority равен 100, он имеет меньшее значение, чем для главного (там указано 180, максимальное значение — 255).
В остальном файл конфигурации резервного сервера аналогичен файлу главного сервера.
Настройка репликации базы данных
В рабочем режиме база данных и файлы реплицируются с главного сервера на резервный. Однако при изменении состояния резервного сервера с MASTER на BACKUP необходимо отключить репликацию базы данных. Этим занимается упомянутый выше скрипт /home/frolov/keepalivednotify.pl.
Для тестирования мы создадим на основном и резервном сервере базу данных my_shop_db и настроим ее репликацию.
Подробнее о настройке репликации и ее мониторинга вы можете узнать из моей статьи «Репликация MySQL и MariaDB: мониторинг с помощью Zabbix».
Подключитесь на главном и резервном серверах к MariaDB как пользователь root:
# mysql -u root -p
Если вы делаете это в Debian, то пароль указывать не нужно, так как авторизация выполняется через сокет.
После этого на обоих серверах создайте базу данных my_shop_db и пользователя shop_db_user:
> CREATE DATABASE my_shop_db;
> CREATE USER 'shop_db_user'@'%' IDENTIFIED BY 'db_password';
> GRANT ALL PRIVILEGES ON my_shop_db.* TO 'shop_db_user'@'%' WITH GRANT OPTION;
Не забудьте изменить здесь пароль пользователя. Также задайте минимально необходимые права доступа пользователя к базе данных.
Далее на главном сервере добавьте в созданную базу данных таблицу goods и вставьте в эту таблицу две записи:
> use my_shop_db;
> create table goods(id int, name varchar(80));
> INSERT INTO goods VALUES (1, "sony123");
> INSERT INTO goods VALUES (2, "sony456");
Посмотрите содержимое таблицы:
> select * from goods;
+------+---------+
| id | name |
+------+---------+
| 1 | sony123 |
| 2 | sony456 |
+------+---------+
Итак, вы создали базы данных, теперь нужно отредактировать файлы конфигурации MariaDB /etc/mysql/mariadb.conf.d/50-server.cnf на обоих серверах для включения репликации.
Конфигурация MariaDB для сервера MASTER
Прежде всего, найдите в файле конфигурации параметр bind-address и закройте его символом комментария:
# bind-address = 127.0.0.1
Это необходимо для того, чтобы разрешить доступ к сервису MariaDB с других узлов по сети. Разумеется, этот доступ дополнительно следует ограничить файрволлом, но об этом позже.
Далее добавьте в файл конфигурации MariaDB следующие строки:
### Replica master
server-id=182
log_bin=/var/log/mysql/mysql-bin.log
expire_logs_days=5
max_binlog_size=50M
sync-binlog=0
binlog_format=mixed
binlog-do-db=my_shop_db
innodb_flush_log_at_trx_commit=0
innodb_flush_method=O_DIRECT
Добавленные параметры описаны в статье "Репликация MySQL и MariaDB: мониторинг с помощью Zabbix".
Обратите внимание, что параметр server-id должен быть разным на главном и резервном сервере, а в параметре binlog-do-db следует указать имя реплицируемой базы данных.
После редактирования файла конфигурации перезапустите сервис MariaDB и убедитесь, что перезапуск прошел успешно:
# systemctl restart mysql
# systemctl status mysql
Конфигурация MariaDB для сервера BACKUP
В файле конфигурации MariaDB резервного сервера обязательно нужно закрыть символом комментария строку bind-address:
#bind-address = 127.0.0.1
Добавьте в файл конфигурации строки:
### Replication Slave
server-id = 181
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 5
max_binlog_size = 50M
sync-binlog=0
binlog_format=mixed
relay-log = /var/log/mysql/mysql-relay-bin.log
replicate-do-db = my_shop_db
report-host=s01host.itmatrix.ru
slave_sql_verify_checksum=0
#skip_slave_start = 1 # prevent restart slave after failure
Здесь при помощи параметра replicate-do-db задается имя реплицируемой базы данных. Параметр report-host позволяет узнать имя сервера реплики с помощью команды «show slave hosts».
Параметр skip_slave_start со значением, равным единице, отключает репликацию при перезагрузке сервера реплики. Этот параметр нужен только в том случае, если требуется отменить репликацию, поэтому он закрыт символом комментария.
Создание пользователя репликации
Чтобы настроить репликацию, создайте пользователя repl_user на главном и резервном серверах:
> CREATE USER repl_user;
> GRANT REPLICATION SLAVE ON *.* TO repl_user IDENTIFIED BY 'repl_password';
> FLUSH PRIVILEGES;
Не забудьте изменить пароль пользователя при выполнении настройки на рабочих серверах.
Запуск репликации
Прежде всего, заблокируйте базу данных главного сервера на запись в отдельном консольном окне:
> use my_shop_db;
> FLUSH TABLES WITH READ LOCK;
Далее в этом же окне посмотрите статус базы на главном сервере:
> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 328 | my_shop_db | |
+------------------+----------+--------------+------------------+
При включении репликации нам потребуются данные из столбцов File и Position.
Теперь откройте еще одно консольное окно на главном сервере и запустите дамп базы данных:
$ mysqldump -ushop_db_user -pdb_password -hlocalhost --opt --quote-names --default-character-set=cp1251 my_shop_db > my_shop_db.sql
Параметры дампа задайте исходя из нужной вам кодировки.
Как только дамп будет сделан, в первом консольном окне разблокируйте базу данных на главном сервере, чтобы разрешить запись:
> UNLOCK TABLES;
Консольное окно со статусом базы данных пока не закрывайте.
Далее перенесите дамп на сервер реплики (то есть на резервный сервер):
# scp -v my_shop_db.sql frolov@192.168.0.181:/home/frolov/
На резервном сервере загрузите дамп базы данных:
$ mysql -ushop_db_user -pdb_password -hlocalhost my_shop_db < my_shop_db.sql
Теперь проверьте состояние репликации. Оно должно быть таким, как показано ниже:
> SHOW SLAVE STATUS\G
Empty set (0.000 sec)
После восстановления дампа базы почистите журналы в /var/log/mysql и запустите репликацию:
> RESET MASTER;
> CHANGE MASTER TO MASTER_HOST='192.168.0.182', MASTER_USER='repl_user', MASTER_PASSWORD='repl_password', MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 328;
> START SLAVE;
Теперь снова проверьте состояние репликации:
> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.182
Master_User: repl_user
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 328
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 551
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: my_shop_db
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 328
Relay_Log_Space: 856
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 182
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: optimistic
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Slave_DDL_Groups: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
Если репликация работает, значения параметров Slave_IO_Running и Slave_SQL_Running должны быть равны Yes, а значение параметра Seconds_Behind_Master должно быть нулевым.
Теперь получите на главном сервере список узлов репликации:
> show slave hosts;
+-----------+---------------------+------+-----------+
| Server_id | Host | Port | Master_id |
+-----------+---------------------+------+-----------+
| 181 | s01host.itmatrix.ru | 3306 | 182 |
+-----------+---------------------+------+-----------+
В этом списке должен быть резервный сервер s01host.itmatrix.ru.
Скрипт keepalivednotify.pl
Теперь подготовим скрипт /home/frolov/keepalivednotify.pl, который будет запускаться сервисом keepalived при изменении состояния сервера (MASTER или BACKUP).
Задачи этого скрипта:
сохранение текущего состояния сервера (MASTER или BACKUP) в файле /home/frolov/node_keepalive_state.txt;
ведение файла журнала /home/frolov/node_keepalive_log.txt, отражающего действия, предпринятые скриптом keepalivednotify.pl при изменении состояния сервера;
переключение режима репликации MariaDB при переходе сервера из состояния MASTER в состояние BACKUP
Параметры скрипта keepalivednotify.pl
Когда сервис keepalived запускает скрипт, указанный в параметре notify файла конфигурации /etc/keepalived/keepalived.conf, то он передает ему три параметра. Это строка идентификатора блока VRRP, заданная в параметре vrrp_instance файла конфигурации keepalived, группа (если она задана в параметре vrrp_sync_group), а также состояние узла (MASTER или BACKUP).
Программа получает эти параметры и сохраняет их в соответствующих переменных:
my $instance = $ARGV[0];
my $group = $ARGV[1];
my $state = $ARGV[2];
Файлы состояния и журнала
Также программа получает дату и время события, а также имя hostname для записи в упомянутые выше файлы состояния и журнала:
my $datestring = localtime();
my $host = hostname;
Полученная информация добавляется в соответствующие файлы:
my $log_file = '/home/frolov/node_keepalive_log.txt';
open($fh, '>>:encoding(UTF-8)', $log_file) or die "Can't open file '$log_file'";
my $node_keepalive_state_file = '/home/frolov/node_keepalive_state.txt';
my $state_str = $instance.'_'.$group.'_'.$state.','.$host.','.$datestring."\n";
write_file($node_keepalive_state_file, $state_str);
print $fh "$datestring: $host ($instance $group) -> $state\n";
Действия при изменении состояния сервера
Далее программа keepalivednotify.pl анализирует имя сервера, на котором она запущена, и его состояние, предпринимая соответствующие действия:
if($host eq 's01host.itmatrix.ru' and $state eq 'MASTER') # BACKUP go to MASTER
{
my $rc = stop_replica($conf);
print $fh "$datestring: $host ($instance $group) -> Stop MySQL Replication\n";
}
elsif($host eq 's01host.itmatrix.ru' and $state eq 'BACKUP') # BACKUP return from MASTER to BACKUP
{
print $fh "$datestring: $host ($instance $group) -> BACKUP node return from MASTER to BACKUP\n";
}
elsif($host eq 's01host.itmatrix.ru' and $state eq 'STOP') # BACKUP return from MASTER to BACKUP
{
print $fh "$datestring: $host ($instance $group) -> BACKUP node goto STOP\n";
}
elsif($host eq 'm01host.itmatrix.ru') # MASTER state
{
print $fh "$datestring: $host ($instance $group) -> MASTER node goto $state\n";
}
else
{
print $fh "$datestring: $host ($instance $group) -> Invalid host $host or invalid state $state\n";
}
close $fh;
Остановка репликации и замена файла конфигурации Maria DB
Если состояние резервного узла стало MASTER, то резервный сервер стал основным. В этом случае с помощью функции stop_replica скрипт keepalivednotify.pl останавливает репликацию и меняет файл конфигурации MariaDB таким образом, чтобы после перезагрузки резервного сервера репликация не запустилась вновь автоматически.
В других случаях скрипт keepalivednotify.pl дописывает информацию об изменении состояния сервера в файл журнала, а затем закрывает этот файл функцией close.
Функция stop_replica получает в качестве параметра ссылку на хэш, содержащий информацию, необходимую для отключения репликации и для манипуляций с файлами конфигурации MariaDB:
my $conf=
{
'mysql_cmd' => '/usr/bin/mysql -s -uroot -pwJzBruD6WOzV9VCx -e ',
'mysql_config_file' => '/etc/mysql/mariadb.conf.d/50-server.cnf',
'mysql_master_config_file' => '/home/frolov/vrrp/mysql_config/50-server.cnf_master',
'mysql_slave_config_file' => '/home/frolov/vrrp/mysql_config/50-server.cnf_slave',
'mysql_slave_no_replication_config_file' => '/home/frolov/vrrp/mysql_config/50-server.cnf_slave_no_replication',
};
Для рабочего проекта в этом хэше необходимо заменить пароль root для подключения к MariaDB. Лучше всего хранить эти данные не в тексте скрипта, а в отдельном файле, например, формата JSON.
Получив управление, функция stop_replica прежде всего останавливает репликацию с помощью команды «stop slave IO_THREAD»:
my ($conf) = @_;
my $rc = {};
my $cmd = $conf->{mysql_cmd}."\'stop slave IO_THREAD'";
my @rqout = ();
@rqout = split /\n/, `$cmd`;
Далее функция дожидается завершения исполнения сервером реплики всех команды из журнала relay в своей базе при помощи функции relay_log_done.
Если выполнение команд завершено, функция останавливает репликацию и копирует новый файл конфигурации Maria DB:
if(relay_log_done($conf))
{
$cmd = $conf->{mysql_cmd}."\'STOP SLAVE'";
@rqout = ();
@rqout = split /\n/, `$cmd`;
$cmd = $conf->{mysql_cmd}."\'RESET MASTER'";
@rqout = ();
@rqout = split /\n/, `$cmd`;
if(!copy($conf->{ 'mysql_slave_no_replication_config_file'}, $conf->{'mysql_config_file'}))
{
$rc->{ 'err_message' } = "MySQL config file copy failed: $!";
$rc->{ 'rc' } = 'err';
return($rc);
}
$rc->{ 'rc' } = 'ok';
}
…
Что касается функции relay_log_done, то она выполняет несколько попыток обнаружить строку «Slave has read all relay log; waiting for more updates» в результатах выдачи команды «SHOW PROCESSLIST»:
sub relay_log_done
{
my ($conf) = @_;
my $cmd = $conf->{mysql_cmd}."\'SHOW PROCESSLIST'".'|grep "Slave has read all relay log; waiting for more updates"';
my @rqout;
for(my $i=0; $i <= 5; $i++)
{
@rqout = ();
@rqout = split /\n/, `$cmd`;
if(defined $rqout[0]) { return 1; }
sleep(3);
}
return 0;
}
В рабочем проекте записывайте все ошибки, полученные от функций в файл журнала, или обрабатывайте их каким-либо иным способом.
Исходный текст скрипта keepalivednotify.pl можно загрузить здесь.
При использовании этого скрипта в рабочих проектах внесите в него необходимые изменения, в частности, измените пароль доступа к Maria DB.
Также не забудьте сделать файл keepalivednotify.pl исполняемым:
# chmod +x /home/frolov/keepalivednotify.pl
Управление репликацией файлов
О том, как настроить репликацию файлов при помощи rsync и мониторинг этой репликации читайте в статье «Репликация файлов через rsync: мониторинг с помощью Zabbix», написанной мной для блога FirstVDS.
В этой статье приведен скрипт, который запускается через crontab и копирует необходимые файлы с главного сервера на резервный. При этом выполняется проверка, что скрипт запущен именно на резервном сервере, который находится в состоянии BACKUP, а не на главном.
Для проверки скрипт анализирует содержимое файла состояния /home/frolov/node_keepalive_state.txt, а также имя hostname сервера.
В нашем примере hostname резервного сервера — s01host.itmatrix.ru. Если при этом файл состояния содержит строку INSTANCE_my_site_BACKUP, то можно запускать репликацию файлов:
my $node_keepalive_state_file = '/home/frolov/node_keepalive_state.txt';
my $state_file_content = read_file($node_keepalive_state_file);
my $host = hostname;
if($host eq 's01host.itmatrix.ru' and $state_file_content=~/INSTANCE_my_site_BACKUP/)
{
# Запуск репликации файлов
…
}
Когда резервный сервер перейдет в состояние MASTER, репликация файлов запускаться не будет, так как в файле состояния будет строка «INSTANCE_my_site_MASTER».
Управление пакетными заданиями
Как правило, на серверах интернет-магазинов работают пакетные задания, выполняющие, например, выгрузку заказов для доставки, автоматический импорт наличия или какие-либо еще автоматизированные действия.
Важно, чтобы такие пакетные задания запускались только на сервере, который находится в состоянии MASTER.
В качестве решения можно предложить запуск через crontab пакетной программы с правами пользователя root, которая будет определять, доступен ли на сервере виртуальный IP. Если виртуальный IP доступен, то сервер находится в состоянии MASTER, и программа запускает необходимые пакетные задания интернет-магазина (или другого сервиса).
Следующий фрагмент кода выполняет необходимые проверки и запуск пользовательского пакетного задания с правами пользователя siteuser:
my $node_keepalive_state_file = '/home/frolov/node_keepalive_state.txt';
my $state_file_content = read_file($node_keepalive_state_file);
my $ipa_cmd = 'ip a | grep 192.168.0.197';
my @ipaout = ();
@ipaout = split /\n/, `$ipa_cmd`;
my $vip_is_up=0;
if($ipaout[0]) { $vip_is_up=1; }
if($state_file_content=~/INSTANCE_my_site_MASTER/ and $vip_is_up == 1)
{
my $cmd = 'sudo -u siteuser /usr/bin/perl /home/siteuser/data/www/my-site.ru/cgi-bin/batch_job.pl >/dev/null 2>&1';
my @rqout = ();
@rqout = split /\n/, `$cmd`;
}
Для рабочего проекта тут нужно как минимум заменить адрес виртуального IP и путь к пакетной программе вашего интернет-магазина.
Запуск отказоустойчивой системы
При первом запуске keepalived на главном сервере он перейдет в состояние BACKUP, а через некоторое время — в состояние MASTER. Серверу будет выделен виртуальный адрес IP, в нашем случае 192.168.0.197.
Если теперь запустить keepalive на резервном сервере, то этот сервер останется в состоянии BACKUP, потому что его приоритет, заданный параметром priority, ниже, чем у главного сервера.
Проверка переключения виртуального адреса IP
Прежде чем менять IP сайта вашего интернет-магазина в DNS на виртуальный IP, проверьте, как этот адрес будет переходить с главного сервера на резервный и обратно.
Предполагая, что главный сервер находится в состоянии MASTER, а резервный — в состоянии BACKUP, остановите сервис keepalived на главном сервере. Так вы смоделируете выход из строя главного сервера.
Через некоторое время резервный сервер перейдет в состояние MASTER и получит виртуальный IP, как и должно быть.
Обратное переключение
Теперь предположим, что главный сервер снова оказался доступен. Запустите на нем сервис keepalived.
Можно было бы ожидать, что виртуальный IP «перепрыгнет» назад на главный сервер. Но этого не случиться, так как в конфигурации keepalived задан параметр nopreempt.
Зачем используется этот параметр?
Дело в том, что как только виртуальный IP перешел на резервный сервер и тот получил статус MASTER, посетители сайта стали работать уже с резервным сервером, изменяя его базу данных. Если теперь переключить виртуальный IP обратно на главный сервер, все изменения в базе данных резервного сервера будут потеряны.
Именно поэтому обратное переключение на главный сервер всегда выполняется вручную.
После восстановления работоспособности главного сервера вам нужно сначала скопировать на него базу данных с резервного сервера, запретив предварительно ее редактирование. Потом нужно переключить виртуальный IP на главный сервер, перезапустив keepalived на резервном сервере.
Контроль трафика keepalived
Для того чтобы понять, как работает keepalived, можно посмотреть широковещательный трафик от этого сервиса с помощью утилиты keepalived.
Установите tcpdump на главном и резервном сервере:
# apt install tcpdump
Далее в отдельных консольных окнах запустите такую команду:
tcpdump -c 10 -i ens33 host 224.0.0.18
Эта команда покажет трафик, приходящий на адрес 224.0.0.18 сетевого интерфейса ens33 (у вас может быть другой интерфейс).
Пока главный и резервный сервер работают в обычном режиме, keepalived сообщает о том, что он жив, рассылая с главного сервера широковещательные запросы такого вида:
13:47:35.948780 IP m02host > 18.0.0.224.in-addr.arpa: VRRPv2, Advertisement, vrid 77, prio 180, authtype none, intvl 5s, length 20
Если же остановить keepalived на главном сервере, то резервный сервер, перестав получать широковещательные пакеты от этого сервера, переходит в состояние MASTER. Теперь он уже сам начинает рассылать широковещательные пакеты:
13:49:18.344152 IP 192.168.0.181 > 18.0.0.224.in-addr.arpa: VRRPv2, Advertisement, vrid 77, prio 100, authtype none, intvl 5s, length 20
Как видите, в этих пакетах есть идентификатор блока VRRP, заданный параметром virtual_router_id в файле конфигурации keepalived, приоритет priority, а также интервал advert_int.
Таким образом, если серверы с установленным keepalived и одинаковым идентификатором блока VRRP (а их может быть больше двух) перестают получать широковещательные пакеты от главного сервера, то между ними через время, заданное параметром advert_int начинаются новые выборы сервера MASTER. При выборе сравниваются приоритеты, заданные параметром priority.
Заметим, что если на серверах установлен файрволл, необходимо разрешить широковещательный трафик, добавив правила вида:
iptables -A INPUT -I ens33 -d 224.0.0.0/8 -j ACCEPT
Настройка конфигурации NGINX
Очень часто в качестве обратного прокси для сайтов используется NGINX. Заметим, что в конфигурации NGINX для сайта обычно указывается адрес IP сервера, например:
server {
server_name my-site.ru www.my-site.ru;
…
listen xxx.xxx.xxx.xxx:80;
…
}
Чтобы сайт был доступен на виртуальном IP, на главном и резервном серверах укажите в параметре listen адрес 0.0.0.0:
server {
server_name my-site.ru www.my-site.ru;
…
listen 0.0.0.0:80;
…
}
После изменения адреса перезапустите сервис NGINX.
В том случае, если на сервере установлена какая-либо панель управления сервером, защитите отредактированный файл конфигурации от изменений с помощью команды chattr:
# chattr +i /etc/nginx/vhosts/siteuser/my-site.ru.conf
Восстановить возможность внесения изменений можно так:
# chattr -i /etc/nginx/vhosts/siteuser/my-site.ru.conf
Если этого не сделать, то любые операции с конфигурацией NGINX для сайта могут привести к восстановлению адреса IP, что, в свою очередь, приведет к недоступности сайта.
О чем еще нужно помнить
Если вы создаете отказоустойчивую систему из двух серверов, как это описано в статье, учтите, что о резервном сервере нужно заботиться не меньше, чем о главном.
В частности, вам нужно настроить мониторинг основного и резервного сервера, выполнять резервное копирование данных как на основном, так и на резервном сервере и хранить эти копии отдельно.
Производительность резервного сервера должна быть достаточной для работы в пиках продаж.
Мы также рекомендуем настроить мониторинг состояния серверов (MASTER или SLAVE) с помощь Zabbix. В скрипте мониторинга можно контролировать содержимое файла состояния, а также наличие на сервере виртуального IP.
Комментарии (44)
vadimr
09.01.2023 17:26Описанное вами решение с репликацией позволит обеспечить устойчивость только при проблемах с железом сервера или с сетью. В то время как обычно наиболее частой причиной отказов в обслуживании является нарушение конфигурации программного обеспечения.
Проектирование отказоустойчивой системы необходимо начинать с прикладного уровня, и только уже всё сделав на уровне бизнес-логики и общесистемного ПО, вы доберётесь до железа, а при этом будет уже более-менее понятно, какие требования к нему закладывать, исходя из выбранной архитектуры отказоустойчивости приложения.
AlexandreFrolov Автор
09.01.2023 18:21В то время как обычно наиболее частой причиной отказов в обслуживании является нарушение конфигурации программного обеспечения.
При правильной технологии сопровождения сайта все изменения конфигурации и ПО должно предварительно отлаживаться на тестовом сервере.
Проектирование отказоустойчивой системы необходимо начинать с прикладного уровня, и только уже всё сделав на уровне бизнес-логики и общесистемного ПО
В идеальном случае да. Реально вы уже имеете систему, работающую на протяжении ряда лет, и когда нужно обеспечить ее отказоустойчивость, приходится вносить изменения в работающий код, а может быть и в архитектуру. Кроме того нужно оценить затраты на изменения.
Когда мы делали такую систему для одного из наших клиентов, изменения в конфигурации ПО сайта были минимальны.
В каждом случае перед внедрением отказоустойчивости необходимо изучить существующую систему и принимать решение индивидуально, в том числе анализируя бюджет клиента на реализацию отказоустойчивости.
vadimr
09.01.2023 19:05Реально вы уже имеете систему, работающую на протяжении ряда лет, и когда нужно обеспечить ее отказоустойчивость
Это лукавство и злоупотребление ожиданиями клиента, когда ему под видом отказоустойчивого решения продают дублирование железа.
Вы измеряли коэффициент готовности конечного прикладного решения?
AlexandreFrolov Автор
09.01.2023 19:20Сайт клиента работает очень надежно более 8 лет, и единственные серьезные проблемы, которые с ним происходили, были связаны именно с отказом железа.
В первый раз когда отказал арендованный сервер на его ремонт потребовалось около трех часов, при этом отказ произошел в пике продаж. После настройки отказоустойчивости с использованием VRRP и keepalived в аналогичной ситуации время простоя составило одну минуту, которая ушла на автоматическое переключение с главного сервера на резервный. Обратное переключение было выполнено в плановом режиме, когда посещаемость сайта была минимальна.
Настройка репликации базы данных и файлов обеспечила очень быстрое переключение с минимальной потерей заказов.Перед тем как предложить это решение клиенту, был проведен анализ различных способов реализации отказоустойчивости с оценкой затрат. Все остальные предложения были как минимум на порядок дороже, при этом у них не было никаких особых преимуществ.
Ну и в чем тут лукавство?
vadimr
09.01.2023 19:24Лукавство вот в этом примере:
Сайт клиента работает очень надежно более 8 лет, и единственные серьезные проблемы, которые с ним происходили, были связаны именно с отказом железа.
Я не ставлю под сомнение ваши слова (хотя не думаю, что вы наблюдали за сайтом клиента более 8 лет), но если это так, то описано крайне маловероятное событие.
AlexandreFrolov Автор
09.01.2023 19:32Я не ставлю под сомнение ваши слова (хотя не думаю, что вы наблюдали за сайтом клиента более 8 лет), но если это так, то описано крайне маловероятное событие.
То есть вы думаете, что я вас обманываю? Зачем бы это мне. У нас есть сайты, которые мы сопровождаем уже больше 10 лет. За это время мы открыли сотни сайтов интернет-магазинов, и они находились у нас на постоянном сопровождении.
Насчет вероятности выхода из строя сервера — она не велика, но есть. Настоящие проблемы начинаются, когда сервер ломается именно в пике продаж.
vadimr
09.01.2023 19:35Настоящие проблемы начинаются, когда сисадмин по ошибке или по злому умыслу вводит rm -rf /, а репликатор это подхватывает.
AlexandreFrolov Автор
09.01.2023 19:41Во-первых, у нас работают вменяемая техническая поддержка. Во-вторых, реализовано многоуровневое резервное копирование данных. В третьих, репликация файлов затрагивает только данные сайта, которые есть в резервной копии, а не весь диск сервера со всем его содержимым.
И кстати, не ко всем резервным копиям есть доступ у технической поддержки, и не все копии постоянно онлайн.
vadimr
09.01.2023 19:46Так вот хотелось бы, в частности, про все эти вещи прочитать в статье, которая называется “доступная отказоустойчивость”, а не про банальную мысль продублировать железку.
AlexandreFrolov Автор
09.01.2023 20:02Так ведь правильная организация сопровождения сайтов — это тема для нескольких статей как минимум. У нас есть технология и свой инструментарий, которым мы пользуемся уже примерно 15 лет. Кое-чем я пытаюсь поделиться.
Но как говорил Козьма Прутков, "нельзя объять необъятое". Я надеюсь постепенно добавить и другие статьи.
Вот например, я уже написал немало статей про мониторинг серверов и сервисов с помощью Zabbix для блога FirstVDS, а мониторинг — тоже элемент защиты от отказов ПО и железа.
Про репликацию файлов статья есть, и на нее имеется ссылка в статье про доступную отказоустойчивость. Статья про многоуровневое резервное копирование в планах, напишу, как только появится время.
Но если кратко - храните копии за 5 дней непосредственно на хостинговом сервере, за 5 дней и 2-3 недели и месячные копии на серверах бекапов, расположенных в другом датацентре, и держите архивные копии (3 недельных, 3 месячных, полугодовые и годовые) на сервере в офисе, который включается только на время копирования.
Результаты копирования контролируйте с помощью Zabbix, также проверяйте возможность восстановления копий.
Остальное — детали, которые нужно прорабатывать в каждом конкретном случае, тема бекапов не очень простая. Вот, например, у нас в день 20 ТБайт бекапов, такие объемы сами по себе создают трудности.
В любом случае создание надежного отказоустойчивого решения, да еще с высокой нагрузочной способностью требует опыта и денег. Я надеюсь, что моя статья поможет начинающим администраторам реализовать отказоустойчивость, когда у клиента нет большого бюджета.
А предпринимателям покажет, что имеются различные способы реализации отказоустойчивости с различным бюджетом. И если не требуется так называемая "бесшовная" отказоустойчивость, то можно не тратить на отказоустойчивость все свои деньги.
AlexandreFrolov Автор
09.01.2023 20:34Кстати, там очень много всего сделано для отказоустойчивости, мониторинг настроен железа и сервисов, многоуровневое резервное копирование данных, для отладки используются выделенные серверы девелоперов и так далее.
Опять же, сделать дублирование, а точнее горячее резервирование железа, чтобы оно работало и не стоило слишком дорого, и обеспечивало малое время простоя при выходе из строя сервера или дата-центра — не совсем тривиальная задача. Там много разных тонкостей и граблей.
RedPandaHere
09.01.2023 19:18+1Не, коллеги, если вам нужна отказоустойчивость, то никогда не используйте VRRP и подобные протоколы.
Я не большой сторонник селектела, но если быть его клиентом, то для отказоустойчивости лучше использовать https://selectel.ru/lab/general-load-balancer/ что намного лучше ,чем carp, hsrp vrrp и прочая хрень.
И кроме селектела есть альтернативы, и по цене доступные и по функционалу.
AlexandreFrolov Автор
09.01.2023 19:30Балансировщик - хорошее решение, но для него нужно настраивать репликацию базы данных MASTER-MASTER, что привносит свои проблемы. Снижение производительности, например, и возможность "расщепления мозга". Там тоже не все тривиально.
Опять же, интересно было бы услышать, чем именно лучше. Решение на базе VRRP у нас работает без проблем уже несколько лет и не раз выручало при выходе из строя серверов.
Про альтернативы тоже интересно было бы услышать.
Jaizer
10.01.2023 01:29Использование FHRP оправдано внутри одной площадки (когда вам нужно зарезервировать gateway, например). За растягивание такого между двумя городами (порядка 700км) я бы... Ну, как минимум, посмотрел был косо. Все-таки, мир не стоит на месте. Да и скрипт на Perl намекает на то, что решение явно не ново (я не имею ничего против Perl, сам когда-то писал скрипты - лет 15 назад).
Я к тому, что делать отказоустойчивость между разными площадками - не всегда тривиальная задача. Но явно не та, чтобы решать ее с помощью FHRP.
AlexandreFrolov Автор
10.01.2023 05:13Вот в чем согласен — это в том, что делать отказоустойчивость в любом случае задача не тривиальная. И весьма дорогостоящая, особенно если подходить к этому без анализа реальных потребностей заказчика.
Но мы не пытались получить приз за новизну, потратив кучу денег клиента. Ему не нужна бесшовная отказоустойчивость. Он также не готов платить за полную переработку архитектуры давно и надежно работающего сайта с целью внедрения отказоустойчивости.
Практика показала, что решение на базе VRRP и keepalive недорогое и оно реально выручало при выходе из строя сервера.
Что касается геораспределеннной отказоустойчивой сети VRRP, то это в зоне ответственности Селектела. Оно работает и нам подошло.
Как я уже писал, альтернативные решения по бюджету были кратно дороже. Возможно, при неограниченном бюджете мы бы переписали все для контейнеров, но в данном случае с точки зрения требований по отказоустойчивости в этом нет никакой необходимости.
Я бы с удовольствием послушал, как еще можно сделать защиту от выхода из строя сервера и дата-центра, оставаясь в рамках затрат на аренду двух серверов и сети между дата-центрами, которая стоит несколько тысяч рублей в месяц.Кстати, новая версия Perl v5.36 вышла всего полгода назад. Если кто-то предпочитает другие языки, то он сможет без проблем реализовать на них алгоритмы, необходимые при использовании keepalived.
AlexGluck
10.01.2023 06:17Современный мультимастер работает на gtid и уже сплитбрейны не проблема. Но перформанс конечно чуть-чуть уменьшается. Зато никаких ручных действий никогда не надо делать.
AlexandreFrolov Автор
10.01.2023 08:36Правильно ли я понимаю, что там все же нужно три сервера брать, а не два, чтобы не было проблем с расщеплением мозга?
И еще придется вносить изменения в архитектуру сайта, которая изначально создана для работы на одном сервере. А там очень сложные процессы в бэкофисе (делали несколько лет), и их придется переделывать, чтобы, например, они не шли одновременно на всех серверах. А значит надо еще отслеживать, какие серверы работают и распределять по ним процессы.
Переделать конечно можно, но это затраты для клиента.
Подозреваю, что настройка схемы с балансировщиком будет далеко не тривиальной. Да и производительность в нашем случае очень важна.
А если это будет стоить дороже, чем сейчас, клиент откажется. Ведь целесообразность настройки таких схем определяется убытками во время простоя. Для многих клиентов потенциальный простой даже в 1-2 дня не является причиной дополнительных затрат, не говоря уже о 2-3 часах. Все же серверы и дата-центры выходят из строя относительно редко. Если что, можно поднять новый сервер и развернуть сайт из бекапов.У кого-то продажи идут равномерно и нет явных пиков, когда убытки от аварий очень велики. Кто-то еще не знает, что серверы и дата-центры могут выходить из строя, ведь работали же несколько лет, и нечего такого не было. Это как бекапы, которые кто-то уже делает, а кто-то — еще нет.
В данном случае был выбран компромисс, когда обратное переключение выполняется вручную, но при авариях на главном сервере сайт не работает всего минуту-две. Оптимизация при этом сделана на бюджет при допустимом времени простоя.
AlexGluck
10.01.2023 14:48Нет, вы понимаете не правильно. Реализовать multimaster можно и из 2х серверов, древняя статья лет 5 назад была у перконы https://www.percona.com/blog/2018/03/13/the-multi-source-gtid-replication-maze/ где базируется на 2х нодах мультимастера. GTID репликация решает вопрос сплитбрейна за счёт глобального идентификатора.
AlexandreFrolov Автор
10.01.2023 14:58Это хорошо, с идентификатором понятно, но вообще репликация мастер-мастер еще накладывает разные ограничения, требует ревизии SQL-запросов и логики работы приложения. В целом я посчитал что в данном случае проще обойтись репликацией мастер-слейв.
AlexGluck
10.01.2023 15:03Ничего не надо, приложение смотрит всегда в свою базу и работает как и сейчас и ничего не меняется. Только репликация между бд по другому настраивается. А для репликации файлов вместо rsync лучше использовать lsync работающий на inotify событиях.
AlexGluck
10.01.2023 15:09Правда для файлов сплитбрейн возможен и я бы попробовал drbd мультимастер с diskless, как делает это linstore.
AlexandreFrolov Автор
10.01.2023 15:57Так просто не получится. Вот, например, процессы экспорта заказов в службу доставки и импорта ассортимента и наличия от поставщиков не могут идти сразу на нескольких серверах — будет большая беда.
А если на одном, то на каком из двух?
Значит нужно отслеживать, какие серверы доступны и запускать только на одном из них.
Это только на поверхности, а в глубине наверняка есть еще похожие проблемы.
С файлами да, отдельная боль.
AlexGluck
10.01.2023 16:09У вас есть VIP, он всегда указывает только на один какой-то сервер, он является маркером какой сервер активен. Обращение к бд должны идти через вип, тогда они всегда будут попадать только на один из двух серверов.
AlexandreFrolov Автор
10.01.2023 16:22Да, это решает часть проблем. Однако все равно потребуется ревизия всего проекта — там все очень сложно, много людей делали несколько лет. Хотя бы те же обращения к базе нужно все проверять, искать поля в таблицах с автонумерацией и т.п.
И еще к базе придется обращаться по сети, что будет тормозом, помимо того что надо дожидаться выполнения транзакций на других мастер-серверах.
Но если подвернется заказчик с подходящим бюджетом — обязательно попробую.
AlexandreFrolov Автор
10.01.2023 16:58Кстати, а что будет при одновременном обращении по VIP к базе с разных серверов? Возможно что ничего хорошего, если бекофис на это не рассчитан. Так что по любому придется просматривать все подряд.
А вот при репликации master-slave это все разрулить намного проще. Но тоже нужно блокировать запуск на slave скриптов, которые обращаются к базе для записи.
AlexGluck
10.01.2023 17:02Приложение будут корректно работать.
Чем возможно? Какая разница сколько копий приложения обращается к бд? Что надо просматривать, не совсем вас понял?
AlexandreFrolov Автор
10.01.2023 17:05Ну вот представьте себе, что на двух серверах запустился одновременно или с небольшим интервалом длительный пакетный процесс выгрузки заказов в службу доставки. В этом случае выгрузка будет выполнена дважды. С двойной отметкой в базе данных магазина.
Аналогичные проблемы будут при одновременном запуске двух пакетных заданий импорта ассортимента и наличия. Если не предпринимать никаких мер, одно и тоже будет импортировано дважды.
AlexGluck
10.01.2023 17:07Вы же в своей статье указали, что пакетные задания вы включаете там где вип, какая разница мультимастер у вас бд или нет?
AlexandreFrolov Автор
10.01.2023 17:11Да, этот способ позволит не запускать пакетные задания, если VIP на сервере не поднят. Только я вот точно не знаю, в случае балансировщика появляется этот VIP на сетевом интерфейсе сервера (как при keepalived), или же там только перенаправление трафика.
Надо еще посмотреть, как работает балансировщик. Подозреваю это все же не то, что позволяет управлять, на каких серверах что нужно запускать, а а что нет.
Если сервер вышел из строя, то балансировщик не будет направлять на него трафик, но как остальные серверы об этом узнают, пока непонятно.
И ведь балансировщик будет направлять трафик сразу на несколько серверов, если они все рабочие.
AlexandreFrolov Автор
10.01.2023 17:30Ну мы обсуждаем репликацию мастер-мастер при использовании балансировщика. А если VRRP и keepalived, то не очень понятно, зачем тут мастер-мастер.
Возможно это позволило бы автоматизировать обратный переход на отказавший мастер-сервер после его восстановления, но едва ли стоит это делать.
Мало ли что было с мастер-сервером, и почему он перестал работать. Тут безопаснее вначале проверить все на нем, а потом уже включать его в работу.
Может там ОС надо переустанавливать или какие-нибудь пакеты, может быть файлы конфигурации испортились или еще чего. Может там оперативная память вышла из строя и он будет перезагружаться каждые десять минут, у меня такое было.
И уж точно нужно копировать файлы обратно со слейва на мастер, за время недоступности мастера они изменятся на слейве.
В любом случае я не рискну автоматически возобновлять доступ к отказавшему серверу, если он вдруг снова появился в сети. Не исключено, что он стал негодным для использования.
AlexGluck
10.01.2023 17:36Ни про какой балансировщик я не говорил, не упоминал и не имел ввиду. Если вышедший из строя сервер вернётся в работу, то попытка восстановить его как слейв в случае проблем провалиться, а в случае успеха уберёт необходимость ручных действий. Что бы с сервером не произошло, вернуть его в работу как слейв можно.
AlexandreFrolov Автор
10.01.2023 17:54А кто его знает, провалится или нет. Сервис keepalived может и заработает, а вот все остальное я предпочитаю смотреть вручную. А то я буду думать, что со слейвом все хорошо, а там, например, nginx перестал работать или еще что испортилось, или он начнет периодически перезагружаться.
Конечно, Zabbix при этом пришлет много нехороших писем, но уж лучше я не буду рисковать и посмотрю все сам. Все проблемы от лени)
Что касается балансировщика, то я изучал возможность использования Селектеловского, они мне и прислали инструкцию по настройке репликации мастер-мастер для Maria DB.
AlexandreFrolov Автор
10.01.2023 17:37По хорошему тут бы два слейв-сервера, чтобы при выходе мастера из строя сохранялась отказоустойчивость. Но это дополнительные расходы.
AlexGluck
10.01.2023 17:56По хорошему, вспомним CAP-теорему, 3 мультимастера с оркестратором и получим кубернетис хД
AlexandreFrolov Автор
10.01.2023 18:01Затраты на переписывание исходников магазина для кубернетиса, а также на сопровождение по технологии DevOps будут слишком велики в данном случае.
Вот если новый проект для богатого заказчика, то да, стоит подумать!
ALIEN900
10.01.2023 08:15Сильно не пинать но возможно наверное с разными хостерами реализовать через Docker. тестировал nginx балансировщик через Docker+keepalived запускался для тестов. в прод не зашло из-за избыточности. За развернутую статью с бд спасибо. на досуге попробую потестировать.
AlexandreFrolov Автор
10.01.2023 08:42В данном случае сайт изначально не был разработан для Docker, а переделка для контейнеров будет чрезмерно дорогой. Кроме того значительно увеличатся расходы на сопровождение — ведь специалисты по Kubernetes стоят ну очень дорого. И таких хорошо бы как минимум два.
Кроме того, контейнеры сами по себе никак не решают проблему отказоустойчивости базы данных. Этим придется заниматься отдельно.
Abyss777
Т.е. это можно реализовать только в рамках одного хостера? А если что-то случится с хостером? Тут есть подобные истории...
Какова технология если нужно реализовать VIP между ДЦ разных провайдеров?
Как сделать VIP маршрутизируемым в совершенно разные подсети?
AlexandreFrolov Автор
Своими силами никак или трудно (дорого), но думаю что можно заказать создание такой сети компаниям, владеющим дата-центрами. Тут опять же, вопрос цены.
Я выбрал Селектел, так как у него есть дата-центры в разных городах, и недорогая отказоустойчивая геораспределенная сеть. При этом все работает надежно уже несколько лет. При выходе из строя памяти на серверах оно срабатывало, ощутимых простоев сайта не было, что и требовалось получить.
AlexGluck
Самым частым и хорошим решением будет создать свою AS (автономная система) и публиковать по bgp протоколу свои публичные адреса с разных точек присутствия. Дальше уже обрабатывать входящий трафик. Такая сетевая схема была построена на заре нулевых в яндексе.
AlexandreFrolov Автор
Да, решение хорошее, но дорогостоящее по сравнению с использованием уже готовых и настроенных отказоустойчивых сетей. Для крупных компаний может и подойдет, а для клиентов с одним сервером и ограниченным бюджетом — не факт, к сожалению.
Abyss777
Если у вас много клиентов, то можете купить AS и продавать свою отказоустойчивую сеть. Вместо того чтоб клиенты платили Селектелу, они могут платить вам :)
AlexandreFrolov Автор
Насколько я понимаю, сделать такую отказоустойчивую сеть стоит довольно дорого. Все же нам проще пользоваться готовой сетью, тем более она стоит порядка 5-6 тыс. руб. в месяц. Ради этих денег вкладывать миллионы в собственную отказоустойчивую сеть для нас пока не выгодно)
И даже покупать свои серверы, вместо того чтобы арендовать, тоже выгода небольшая. К тому же, свои серверы нужно самим ремонтировать, и это тоже затраты.