Главная > IT > HA-Apache2 Web-Site and HA-MySQL

HA-Apache2 Web-Site and HA-MySQL

Ершов Илья
Высокодоступное отказоустойчивое web-приложение на Apache2 и MySQL
10 сентября 2010

Цель: обеспечить высокую доступность web-приложения и минимальное время простоя при отказе одного как web-сервера, так и сервера баз данных.
Замечание! Схема предполагает, что web-приложение и база данных находится на разных серверах.
Для примера будем устанавливать wordpress.

Вариант решения:
Поскольку web-приложение должно быть постоянно доступно, то необходимо минимум два сервера с установленным приложением. Серверы будут отслеживать состояние друг друга, при этом в каждый момент времени ведущим будет только один из них. В случае отказа ведущего сервера его роль принимает второй. Когда первый сервер будет вновь доступен, к нему опять вернется роль ведущего.

Т.к. для обеспечения отказоустойчивости базы данных будут использоваться минимум два сервера, то для обращения к ним мы будем использовать один виртуальный ip-адрес, на который и настроим наше web-приложение. В этом случае отказ одного из серверов никак не скажется на работоспособности web-сервера, т.к. оно продолжит работать с базой резервного сервера. Для синхронизации баз на основном и резервном сервере будем использовать механизм двунаправленной репликации («master-master»). Для увеличения уровня безопасности и балансировки запросов от web-приложения добавим два проксирующих сервера в архитектуру. Серверы будут слушать запросы на порт 3306 и распределять их между серверами баз данных. Один из серверов будет ведущим. При отказе ведущего, его роль на себя принимает второй сервер (принцип аналогичен работе web-серверов).

Архитектура системы:

Будем использовать следующие имена серверов и ip-адреса:

Сервер IP-адрес
apache-app1 192.168.8.221
apache-app2 192.168.8.222
mysql-proxy1 192.168.8.224
mysql-proxy2 192.168.8.225
mysql-data1 192.168.8.226
mysql-data2 192.168.8.227

Дополнительно нам потребуются еще два ip-адреса:

IP-адрес Назначение
192.168.8.220 Адрес для клиентских обращений к web-приложению
192.168.8.223 Адрес для обращения к базе MySQL

Замечание! Все используемые в данном руководстве системы работают под управлением Ubuntu Server 8.04 LTS с установленным OpenSSH-сервером.

Для начала приступим к настройке серверов баз данных (mysql-data1 и mysql-data2).
Замечание! Все действия выполняются от суперпользователя.
Ставим необходимые компоненты на обоих серверах. Нам потребуется MySQL-сервер. Во время установки вводим надежный пароль для пользователя root.

apt-get install mysql-server --yes

Переходим к настройке. Для начала настроим наши серверы таким образом, чтобы они слушали запросы к серверу MySQL из сети. Для этого отредактируем файл /etc/mysql/my.cnf. В нем необходимо найти строку bind-address=127.0.0.1 и заменить ее на

bind-address=192.168.8.226

для сервера mysql-data1 и

bind-address=192.168.8.227

для сервера mysql-data2
Рестартуем службы:

/etc/init.d/mysql restart

Переходим к настройке репликации.
При однонаправленной репликации («master-slave») в случае записи в подчиненную базу данных база данных данные могут оказаться противоречивыми, что может привести к ошибке репликации. В случае двунаправленной репликации базы данных будут находиться в согласованном состоянии.
Для репликации будем использовать пользователя MySQL replication с паролем some_password.
На сервере mysql-data1 редактируем файл /etc/mysql/my.cnf. Вставляем следующие строки в раздел, относящийся к репликации:

server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 100M
binlog_ignore_db = test
binlog_ignore_db = mysql
master-host = 192.168.8.227 #ip-адрес сервера mysql-data2
master-user = replication #пользователь для репликации
master-password = some_password #пароль пользователя
master-port = 3306

Заходим в MySQL под пользователем root и даем право пользователю replication подключаться к нашему серверу с сервера mysql-data2:

mysql -u root -p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>grant replication slave on *.* to 'replication'@'192.168.8.227' identified by 'some_password';
>flush privileges;
>quit;
/etc/init.d/mysql restart

Переходим на сервер mysql-data2.
Редактируем файл /etc/mysql/my.cnf. Вставляем следующие строки в раздел, относящийся к репликации:

server-id = 2
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 100M
binlog_ignore_db = test
binlog_ignore_db = mysql
master-host = 192.168.8.226 #ip-адрес сервера mysql-data1
master-user = replication #пользователь для репликации
master-password = some_password #пароль пользователя
master-port = 3306

Заходим в MySQL под пользователем root и даем право пользователю replication подключаться к нашему серверу с сервера mysql-data1:

mysql -u root -p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>grant replication slave on *.* to 'replication'@'192.168.8.226' identified by 'some_password';
>flush privileges;
>quit;
/etc/init.d/mysql restart

На обоих серверах проверяем, что процесс репликации запущен. Для этого выполняем следующее:

mysql —u root —p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>show slave status \G

В выведенной информации нас интересуют три параметра:

Slave_IO_State: Waiting for master to send event
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

Если указанные параметры на обоих серверах соответствуют указанным выше, то все замечательно, репликация настроена. Если нет, смотрим логи.
Создадим базу данных для нашего приложения. На сервере mysql-data1 выполним следующее:

mysql —u root —p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>create database wp_database;

Перейдем на сервер mysql-data2 и проверим, что база реплицировалась на этот сервер:

mysql —u root —p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>show databases;

Вывод должен содержать имя созданной нами ранее базы.
Настроим права доступа к этой базе со стороны проксирующих серверов. На обоих серверах выполняем следующее:

mysql —u root —p
Enter password: Вводим пароль для пользователя root, заданный во время установки
>grant all on wp_database.* to 'wp_user'@'192.168.8.224' identified by 'wp_user_password';
>grant all on wp_database.* to 'wp_user'@'192.168.8.225' identified by 'wp_user_password';
>flush privileges;
>quit;

Переходим к настройке балансировки и mysql-proxy.
На серверах mysql-proxy1 и mysql-proxy2 устанавливаем необходимые компоненты (здесь и далее, все команды выполняются от имени суперпользователя).

apt-get install mysql-proxy heartbeat

Создадим start-up скрипт для запуска служб mysql-proxy с использованием конфигурационного файла. Для начала создадим каталог для хранения конфига.

mkdir /etc/mysql-proxy

В созданном каталоге создадим файл mysql-proxy.conf. Содержимое моего фала:

#########################################
# A configuration file for mysql-proxy service.
#########################################
# Author: ozzy
# Date: /09/15/2010
# Versio: 1.0
#########################################
# Service configuration section
# Specify backend MySQL servers (one per line)
#########################################
proxy-backend-addresses = 192.168.8.226
proxy-backend-addresses = 192.168.8.227
#########################################
# Port configuration section
# Defines port on which mysql-proxy will
# listen to incoming requests.
# Attention! Don't modify this section!
#########################################
proxy-address = :3306

Теперь создадим файл mysql-proxy в /etc/init.d/ со следующим содержимым:

#!/usr/bin/perl -w
$appPath='mysql-proxy ';
#Path for configuration file. Modify if different.
$configFileName='/etc/mysql-proxy/mysql-proxy.conf';
chomp($input=lc($ARGV[0]));
if ($input eq 'start')
{
open(CONFIG, "$configFileName")||die "File open error!: $!\n";
while (){push (@fileStrings, $_);}
close(CONFIG);
chomp(@addresses = grep {/^\s*proxy-backend-addresses\s*=/i} @fileStrings);
foreach (@addresses)
{
($parameter,$value)=split(/=/);
$parameter =~ s/\s+//g;
$value =~ s/\s+//g;
$appPath=$appPath."--".$parameter."=".$value." ";
}
chomp(@addresses = grep {/^\s*proxy-address\s*=/i} @fileStrings);
@addresses= split(/=/,$addresses[0]);
$addresses[1] =~ s/\s+//g;
$appPath=$appPath."--proxy-address=".$addresses[1]." --daemon";
print "Starting mysql-proxy...\n";
system($appPath);
print "Done!\n";
}
else
{
if ($input eq 'stop')
{
print "Trying to kill mysql-proxy...\n";
system ('killall mysql-proxy');
print "Done!\n";
}
else {print "Usage: /etc/init.d/mysql-proxy start|stop\n";}
}

Сделаем его исполняемым и выставим необходимые права:

chmod 755 /etc/init.d/mysql-proxy

Переходим к настройке высокой доступности на основе heartbeat на обоих серверах.
Создадим необходимые файлы:

touch /etc/ha.d/authkeys
touch /etc/ha.d/ha.cf
touch /etc/ha.d/haresources

Выставим параметры безопасности на файл /etc/ha.d/authkeys

chmod 600 /etc/ha.d/authkeys

И отредактируем его следующим образом:

auth 2
2 sha1 your-strong-password

Отредактируем файл /etc/ha.d/ha.cf в соответствии с нашей конфигурацией. Файл должен быть идентичным на обоих узлах.

logfile /var/log/ha-log #куда писать лог
logfacility local0
keepalive 2 #как часто опрашивать хосты, в секундах
deadtime 10 #через какое время хост признается умершим
initdead 120
bcast eth0
udpport 694
auto_failback on
node mysql-proxy1
node mysql-proxy2

Замечание! Параметр node должен соответствовать выводу команды uname -n на обоих узлах!

Отредактируем файл /etc/ha.d/haresources. Файл должен быть идентичным на обоих узлах.

mysql-proxy1 192.168.8.223 #общий адрес для обращения приложений к MySQL

Все готово. Осталось только рестартовать службы на обоих серверах (сначала на mysql-proxy1, а потом mysql-proxy2).

/etc/init.d/heartbeat restart

Приступаем к настройке web-серверов apache-app1 и apache-app2.
Устанавливаем необходимые компоненты.

apt-get install apache2 php5 php5-gd php5-mysql libapache2-mod heartbeat --yes

Переходим к настройке отказоустойчивости.
Создадим необходимые файлы:

touch /etc/ha.d/authkeys
touch /etc/ha.d/ha.cf
touch /etc/ha.d/haresources

Выставим параметры безопасности на файл /etc/ha.d/authkeys

chmod 600 /etc/ha.d/authkeys

И отредактируем его следующим образом:

auth 2
2 sha1 your-strong-password

Отредактируем файл /etc/ha.d/ha.cf в соответствии с нашей конфигурацией. Файл должен быть идентичным на обоих узлах.

logfile /var/log/ha-log #куда писать лог
logfacility local0
keepalive 2 #как часто опрашивать хосты, в секундах
deadtime 10 #через какое время хост признается умершим
initdead 120
bcast eth0
udpport 694
auto_failback on
node apache-app1
node apache-app2

Замечание! Параметр node должен соответствовать выводу команды uname -n на обоих узлах!

Отредактируем файл /etc/ha.d/haresources. Файл должен быть идентичным на обоих узлах.

apache-app1 192.168.8.220 apache2 #общий адрес для обращения приложений к нашему web-приложению

Все готово. Осталось только рестартовать службы на обоих серверах (сначала на apache-app1, а потом apache-app2).

/etc/init.d/heartbeat restart

Настройка iptables
Закроем все ненужные нам порты на firewall.
На обоих узлах Apache

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#Разрешаем входящие tcp-запросы на ssh на интерфейс eth0
iptables -A INPUT -i eth0 -p tcp --dport ssh -j ACCEPT
#Разрешаем входящие tcp-запросы http на интерфейс eth0
iptables -A INPUT -i eth0 -p tcp --dport http -j ACCEPT
#Разрешаем входящие udp-запросы на 694 порт на интерфейс eth0
iptables -A INPUT -i eth0 -p udp --dport 694 -j ACCEPT
iptables -P INPUT DROP

На узлах mysql-proxy

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#Разрешаем входящие tcp-запросы на ssh на интерфейс eth0
iptables -A INPUT -i eth0 -p tcp --dport ssh -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport mysql -j ACCEPT
#Разрешаем входящие udp-запросы на 694 порт на интерфейс eth0
iptables -A INPUT -i eth0 -p udp --dport 694 -j ACCEPT
iptables -P INPUT DROP

На узлах mysql-data

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#Разрешаем входящие tcp-запросы на ssh на интерфейс eth0
iptables -A INPUT -i eth0 -p tcp --dport ssh -j ACCEPT
#Разрешим подключение к MySQL только с узлов mysql-proxy
iptables -A INPUT -i eth0 -p tcp --dport mysql -s 192.168.8.224 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport mysql -s 192.168.8.225 -j ACCEPT
iptables -P INPUT DROP

И добавим автоматическую загрузку цепочек iptables при поднятии сетевых интерфейсов. Вставляем следующие строки в файл /etc/network/interfaces

pre-up iptables-restore < /etc/iptables.current
pre-down iptables-save > /etc/iptables.current

Установка wordpress.
Wordpress устанавливаем на оба web-сервера и настраиваем одинаково. Подробная инструкция по установке есть на официальном сайте. Здесь привожу параметры из файла wp-config.php для подключения к созданной нами ранее базе.

/** Имя базы данных для WordPress */
define(’DB_NAME’, ’wp_database’);
/** Имя пользователя MySQL */
define(’DB_USER’, ’wp_user’);
/** Пароль пользователя MySQL */
define(’DB_PASSWORD’, ’wp_user_password’);
/** Адрес сервера MySQL */
define(’DB_HOST’, ’192.168.8.223′);

Все готово. Для обращения к wordpress используем адрес http://192.168.8.220/имя_узла_wordpress

Ссылки по теме:
1. High Availability Apache on Ubuntu 8.04
2. Load-balanced highly available MySQL on Ubuntu 8.04
3. High Availability MySQL on Ubuntu 8.04
4. MySQL Failover
5. How to quickly setup a load balanced, high availability, Apache cluster
6. ApacheMySQLPHP

Реклама
  1. alek
    26.04.2011 в 15:40

    >Отредактируем файл /etc/ha.d/haresources. Файл должен быть идентичным на обоих узлах.
    Не совсем: только адрес должен совпадать, а имя свое.
    mysql-proxy1:
    mysql-proxy1 192.168.8.223

    mysql-proxy2:
    mysql-proxy2 192.168.8.223

  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: