Отказоустойчивый веб-сервер на Linux c помощью NGINX
1.Введение
Предлагаю вашему вниманию схему по организации отказоустойчивого сервера приложений – например для высоко нагруженных проектов, таких как веб-сервера с посещаемостью от 1000 чел/час.
В данной схеме дублирован каждый узел:
– балансировщики nginx. Будут слушать веб сервера(бэкэнды) и вещать их в сеть. Осуществлояется кэширование в режиме прокси(proxy_chache). Так как на сайте присутствуют и зарегистрированные пользователи и обычные посетители, то кэширование осуществляется по следующей схеме:
– гостям данные отдаются из кеша (обновляются согласно настройкам кеширования – proxy_cache_valid)
– авторизованным пользователям данные всегда отдаются напрямую, кроме случая когда:
– бекэнд сервер выдает ошибку определенную в proxy_cache_use_stale
– если бекэнд не работает или выдает ошибку определенную в proxy_cache_use_stale гостю выдается ответ из кеша не зависимо от его устаревания
– определение зарегистрированного пользователя осуществляется по наличию определенной куки (её название зависит от движка сайта)
– веб сервер – nginx (фронтэнд) для статического содержимого, apache2 для динамического(как бэкэнд). Хостинг размещается на хранилище Gluster Fs(т.е. Дублируется на вебсервера nginx+apache). Для ускорения php используем hhvm в режиме fastcgi для apache(бэкэнд) и nginx(frontend). Так-же оставили php-fpm в качестве резерва. Веб сервер будет обращаться к mysql прокси.
– mysql proxy(2 шт) с общим адресом для обращения приложений к mysql. В случае выхода одно из прокси из строя его заменит второй(настроим hearbeat). Так же серверы слушают запросы на порте 3306 и распределяют их между серверами баз данных
– mysql северы (backend) с репликацией в режиме мастер-мастер и кэшированием(memchached) для ускорения. Два сервера дублируют друг друга, и в случае выхода одного из строя доступ к базам данных останется, т.е это никак не скажется на работоспособности веб-серверов.
На Днс сервере будет 2 А записи, каждая из которых будет указывать на ip адрес одного из балансировщиков
Для увеличения отказоустойчивости предлагается увеличить количество вебсерверов и серверов баз данных. В случае увеличения серверов баз данных репликация пойдет по кругу.
Так же можно использовать вариант с MySQL репликацией на Redis cache server через Ruby, Gearman, triggers, and MySQL UDF. Давайте далее рассмотрим всё на примерах.
ВАРИАНТ №1. Отказоустойчивый веб-сервер nginx(keepalive)+glusterfs+mysqlreplication
Что мы будем иметь в итоге:
2 nginx балансировщика(keep alive), фронтенды будут слушать веб сервера php(php-fpm). Так же они будут “страховать друг друга”, имея один виртуальный ip – 10.1.9.176. Ip серверов 10.1.9.173 и 10.1.9.174
2 веб сервера php(php-fpm+mysql+nginx) c gluster fs для синхронизации файлов и с репликацией баз данных. Ip 10.1.9.175 и 10.1.9.177.
Операционная система: debian 8 minimal(net install) с доступом по ssh.
Server1: debian-test-1.domain.local 10.1.9.173 – основной loadbalancer(MASTER)
Server2: debian-test-2.domain.local 10.1.9.174 – резервный loadbalancer(BACKUP)
VIP(virtual IP) – 10.1.9.176 — плавающий/расшаренный между балансировщиками нагрузки виртуальный IP-адрес,на который прописаны сайты в DNS
2.1Установка Keepalived
(в зависимостях подтянет ipvsadm-утилиту для администрирования ipvs (ip virtul server))
apt-get install keepalived
Включаем маршрутизацию пакетов на обоих балансерах
# nano /etc/sysctl.conf
net.ipv4.ip_forward = 1 net.ipv4.ip_nonlocal_bind = 1
Проверяем
sysctl -p
Далее редактируем server1;
nano /etc/keepalived/keepalived.conf
vrrp_instance VI_1 { interface eth0 # interface to monitor state MASTER virtual_router_id 51 # Assign one ID for this route priority 100 # 100 on master, 50 on backup virtual_ipaddress { 10.1.9.176 # the virtual IP } }
Запускаем keepaliver
sudo /etc/init.d/keepalived start
Проверяем его
ip addr show | grep 176
Видим это
inet 10.1.9.176/32 scope global eth0
Далее на втором серваке (server 2);
nano /etc/keepalived/keepalived.conf
vrrp_instance VI_1 { interface eth0 # interface to monitor state MASTER virtual_router_id 51 # Assign one ID for this route priority 50 # 100 on master, 50 on backup virtual_ipaddress { 10.1.9.176 # the virtual IP } }
Запускаем keepaliver
sudo /etc/init.d/keepalived start
Проверяем его
ip addr show | grep 176
Видим это(если первый сервак выключить или остановить keepalived на 1 серваке)
inet 10.1.9.176/32 scope global eth0
2.2 Установка PHP серверов
В качестве php сервера выберем PHP-FPM
sudo apt-get install nginx nginx-extras - y
sudo apt-get install php5-cli php5-common php5-mysql php5-gd php5-fpm php5-cgi php5-fpm php-pear php5-mcrypt mysql-server -y
Далее перейдем к настройке.
Настройка состоит из двух этапов — настройки «Nginx» и «PHP-FPM». Для начала необходимо остановить процессы (демоны) «Nginx» и «PHP-FPM», например, командами
sudo service nginx stop sudo service php5-fpm stop
ывыв
Настройка PHP-FPM
На обоих серверах( не балансировщиках) web-server 1 и web-server 2 производим почти аналогичную настройку
Прежде всего, следует открыть файл «/etc/php5/fpm/php.ini» для редактирования, например, командой
sudo nano /etc/php5/fpm/php.ini
после чего, найти строчку содержащую «cgi.fix_pathinfo», которая по-умолчанию выглядит так (закомментирована)
;cgi.fix_pathinfo = 1
и привести её к виду
cgi.fix_pathinfo = 0
Это призвано устранить опасность неправильно трактования (и возникающей уязвимости) запросов вида «/image.gif/foo.php» (см. Don’t trust the tutorials: check your configuration!, Nginx 0day exploit for nginx + fastcgi PHP).
Если планируется загрузка больших файлов (важно для ownCloud версий < 8, в новой версии 8 и выше имеется отдельный файл для этих настроек), то можно увеличить максимальный объем загружаемых данных, например, до 200 МБ
post_max_size = 200M
и ниже
upload_max_filesize = 200M
Затем сохранить изменения в файле.
listen.owner = www-data listen.group = www-data listen.mode = 0660
Следует сохранить изменения в файле и перезапустить «PHP-FPM», например, командой
sudo service php5-fpm start
Можно убедится в том, что права доступа к сокету установлены верно:
ls -la /var/run/php5-fpm.sock
Установка и Настройка glusterfs
Настроим firewall:
sudo apt-get install ufw ufw allow 24007:24010/tcp ufw allow 49152:49153/tcp ufw allow 38465:38467/tcp ufw allow 111/tcp ufw allow 111/udp
Приведем к виду /etc/hosts на webserver-1
GNU nano 2.2.6 Файл: /etc/hosts
127.0.0.1 localhost 10.1.9.175 debian-server-web-1.domain.local debian-server-web-1 10.1.9.177 debian-server-web-2.domain.local debian-server-web-2 # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Приведем к виду /etc/hosts на webserver-2
GNU nano 2.2.6 Файл: /etc/hosts
127.0.0.1 localhost 10.1.9.175 debian-server-web-1.domain.local debian-server-web-1 10.1.9.177 debian-server-web-2.domain.local debian-server-web-2 # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Установим gluster-fs
apt-get install glusterfs-server -y
Теперь переходим на первый веб сервер и выполняем команду.
gluster peer probe debian-server-web-2
root@debian-server-web-1:/home/human# gluster peer probe debian-server-web-2 peer probe: success.
Далее. переходим на второй веб сервер и выполняем команду.
gluster peer probe debian-server-web-1
root@debian-server-web-2:/home/human# gluster peer probe debian-server-web-1 peer probe: success.
Проверяем статус на каждом серваке
gluster peer status
Hostname: debian-server-web-2
Uuid: f98ad7a2-2e72-4748-ad10-8fdfe41a813c
State: Peer in Cluster (Connected)
root@debian-server-web-1:/home/human#
Всё ок.
Теперь создадим кластерное хранилище с именем volume1,
gluster volume create volume1 replica 2 transport tcp debian-server-web-1:/gluster-storage debian-server-web-2:/gluster-storage force
В данной команде:
volume1 — название хранилища
replica 2 — количество серверов реплик
debian-server-web-1:/gluster-storage -В данном случае debian-server-web-1 имя сервера gluster, а /gluster-storage путь к папке в которой будут храниться изменения в фс Gluster.
Вывод команды должне быть таким:
volume create: volume1: success: please start the volume to access data gluster volume start volume1
Вывод команды должен быть таким:
volume start: volume1: success
Теперь установим клиентскую часть, для подключения созданной фс.
Выполните данные действия на каждом веб сервере:
Устанавливаем необходимые компоненты.
apt-get install glusterfs-client
Создаем директорию для монтирования (Выполняем на каждом веб сервере).
Настройка Nginx
Приведем конфиг nginx к необходимому виду. Для этого в старом клнфиге удалим все строки и вставим новые( в виме режим редактирования активируется клавишей ins):
vim /etc/nginx/sites-enabled/default
Вставим след содержимое(старое удалим)
## # You should look at the following URL's in order to grasp a solid understanding # of Nginx configuration files in order to fully unleash the power of Nginx. # https://wiki.nginx.org/Pitfalls # https://wiki.nginx.org/QuickStart # https://wiki.nginx.org/Configuration # # Generally, you will want to move this file somewhere, and start with a clean # file but keep this around for reference. Or just disable in sites-enabled. # # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. ## # Default server configuration # server { listen 80 default_server; listen [::]:80 default_server; # SSL configuration # # listen 443 ssl default_server; # listen [::]:443 ssl default_server; # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! # # include snippets/snakeoil.conf; root /usr/share/nginx/html; # Add index.php to the list if you are using PHP index index.php; server_name _; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { include snippets/fastcgi-php.conf; # # With php5-cgi alone: # fastcgi_pass 127.0.0.1:9000; # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
Сохранимся (esc, затем wq и enter). Все можем в базе создавать юзера
mysql -u root -p
create database wordpress;
exit
Далее, для тестов, установим wordpress
sudo su cd /usr/share/nginx/html/ rm -r /usr/share/nginx/html/* wget https://wordpress.org/latest.zip unzip latest.zip mv wordpress/* . rm -r wordpress cd .. chown -R www-data.www-data html
Перейдем по ip 10.1.9.177 (webserver-2) (на это серв мы ставили всё) и закончим установку wordpress. Введем пользователся bd root и пароль, который мы указали при установке. остальное придумайте сами.
Здравствуйте!
Спасибо за такую полезную информацию!
У меня возникло несколько вопросов –
1. На DNS сервер я всё-таки прописываю две А-записи с балансироващиками, или же, цитирую: “VIP(virtual IP) – 10.1.9.176 — плавающий/расшаренный между балансировщиками нагрузки виртуальный IP-адрес,на который прописаны сайты в DNS”
2. Можно ли обойтись без apache для бекенда ?
3. Текст поплыл в абзаце – В данной схеме дублирован каждый узел: