Логичным продожением предыдущей работы будет создание отказоустойчивого кластера с балансировкой нагрузки и единым виртуальным «плавающим» IP для клиентского доступа. В качестве балансировщика нагрузки будем использовать HAProxy. Для управления виртуальным IP адресом — Keepalived.
Установку начинаем с подключения репозитория repoforge:
1 2 3 4 5 |
# cd /tmp # wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm # yum -y localinstall rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm # yum -y update # yum -y install socat |
Устанавливаем HAProxy и Keepalived и добавляем их в автозагрузку при старте системы:
1 2 3 |
# yum -y install haproxy keepalived # chkconfig haproxy on # chkconfig keepalived on |
Настройка HAProxy
Заполняем конфигурационный файл:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak cat << _EOF > /etc/haproxy/haproxy.cfg # # /etc/haproxy/haproxy.cfg # #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global # to have these messages end up in /var/log/haproxy.log you will # need to: # # 1) configure syslog to accept network log events. This is done # by adding the '-r' option to the SYSLOGD_OPTIONS in # /etc/sysconfig/syslog # # 2) configure local2 events to go to the /var/log/haproxy.log # file. A line like the following can be added to # /etc/sysconfig/syslog # # local2.* /var/log/haproxy.log # log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 1020 # See also: ulimit -n user haproxy group haproxy daemon # turn on stats unix socket stats socket /var/lib/haproxy/stats.sock mode 600 level admin stats timeout 2m #--------------------------------------------------------------------- # common defaults that all the 'frontend' and 'backend' sections will # use if not designated in their block #--------------------------------------------------------------------- defaults mode tcp log global option dontlognull option redispatch retries 3 timeout queue 45s timeout connect 5s timeout client 1m timeout server 1m timeout check 10s maxconn 1020 #--------------------------------------------------------------------- # HAProxy statistics backend #--------------------------------------------------------------------- listen haproxy-monitoring *:80 mode http stats enable stats show-legends stats refresh 5s stats uri / stats realm Haproxy\ Statistics stats auth monitor:AdMiN123 stats admin if TRUE listen mariadb_cluster_reads *:3306 balance roundrobin server node1 10.20.20.11:3308 maxconn 300 check server node2 10.20.20.12:3308 maxconn 300 check server node3 10.20.20.13:3308 maxconn 300 check listen mariadb_cluster_writes *:3307 server node1 10.20.20.11:3308 maxconn 300 check server node2 10.20.20.12:3308 maxconn 300 check backup server node3 10.20.20.13:3308 maxconn 300 check backup _EOF |
Запускаем HAProxy:
1 |
# service haproxy start |
Открываем порт 80 в iptables:
1 |
# iptables -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT |
Можно проверить статистику непосредственно через сокет:
# socat /var/lib/haproxy/stats.sock readline
prompt
> show info
> show stat
> help
или через браузер, авторизовавшись monitor с паролем AdMiN123, которые мы задали в файле конфигурации.
Проверяем что балансировка нагрузки работает:
1 |
# mysql --user=app --password=secret --host=10.20.20.11 --port=3306 --exec="SELECT @@wsrep_node_name;" |
1 2 3 4 5 |
+-------------------+ | @@wsrep_node_name | +-------------------+ | Node C | +-------------------+ |
1 |
# mysql --user=app --password=secret --host=10.20.20.11 --port=3306 --exec="SELECT @@wsrep_node_name;" |
1 2 3 4 5 |
+-------------------+ | @@wsrep_node_name | +-------------------+ | Node A | +-------------------+ |
1 |
# mysql --user=app --password=secret --host=10.20.20.11 --port=3306 --exec="SELECT @@wsrep_node_name;" |
1 2 3 4 5 |
+-------------------+ | @@wsrep_node_name | +-------------------+ | Node B | +-------------------+ |
Обратите внимание, мы указываем адрес для подключения явно. Если этого не сделать, подключение будет идти через сокет на localhost.
Настройка Keepalived
Отключаем iptables:
1 |
# service iptables stop |
Заполняем конфигурационный файл на третьей ноде:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak cat << EOF >/etc/keepalived/keepalived.conf # # /etc/keepalived/keepalived.conf # global_defs { notification_email { admin@example.com root@localhost } notification_email_from haproxy3@example.com smtp_server mail.example.com smtp_connect_timeout 30 router_id haproxy1 } vrrp_script chk_haproxy { script "killall -0 haproxy" interval 2 weight 2 } vrrp_script chk_mysql { script "/root/mysqlchk" interval 2 weight 2 } vrrp_instance GALERA_VIP { interface eth0 virtual_router_id 10 # Higher priority on other node priority 100 advert_int 1 smtp_alert virtual_ipaddress { 10.20.20.10 } track_script { chk_haproxy chk_mysql } authentication { auth_type AH auth_pass Sup3rP@ss! } } EOF |
Убеждаемся, что следующие параметры соответствуют нашим реалиям:
– notification_email
– notification_email_from
– smtp_server – interface
– virtual_router_id (одинаков на всех нодах)
– auth_pass (одинаков на всех нодах)
– virtual_ipaddress (одинаков на всех нодах)
В зависимости от того, какая нода будет иметь наибольший приоритет изменяем значение priority на других нодах. В нашем примере наибольший приоритет будет у первой ноды (priority 102). Обратите внимание на различия в настройке priority для каждой из нод:
router_id | haproxy1 | haproxy2 | haproxy3 |
virtual_router_id | 10 | 10 | 10 |
priority | 102 | 101 | 100 |
weight | 2+2 | 2+2 | 2+2 |
priority+weight | 106 | 105 | 104 |
Параметр weight отображает дополнительное количество единиц, которое получает нода дополненительно к priority если выполняется некое условие, в данном случае условий два: работающий HAproxy и обслуживающий запросы MySQL. Таким образом виртуальный IP будет размещаться на первой ноде.
Создадим простенький скрипт проверки:
1 2 3 4 5 |
#touch /root/mysqlchk #cat << EOF_ > /root/mysqlchk #!/bin/bash mysql -u mysqlchk -e "quit" EOF_ |
Чтобы скрипт сработал, создадим пользователя mysqlchk без привилегий:
1 |
mysql -u root -pYourRootPassword --execute="CREATE USER 'mysqlchk'@'localhost';FLUSH PRIVILEGES;" |
Запускаем Keepalived:
1 |
service keepalived start |
Если выполнить:
1 |
# service haproxy stop |
первая нода будет иметь приоритет 104, что меньше чем у второй ноды, и виртуальный IP адрес «переедет» на вторую ноду.
Приоритет, анонсируемый каждой нодой можно проверить командой:
1 2 |
# tcpdump -s0 -v -pni eth0 host 224.0.0.18 10:32:07.243522 IP (tos 0xc0, ttl 255, id 252, offset 0, flags [none], proto AH (51), length 64) 10.20.20.11 > 224.0.0.18: AH(spi=0x0a14de74,sumlen=16,seq=0x155): VRRPv2, Advertisement, vrid 10, prio 104, authtype ah, intvl 1s, length 20, addrs: 10.20.20.10 |
Тестируем Keepalived. Чтобы убедиться, что система приоритетов работает начните с третьей ноды:
1 2 |
# tcpdump -s0 -v -pni eth0 host 224.0.0.18 10:32:07.243522 IP (tos 0xc0, ttl 255, id 252, offset 0, flags [none], proto AH (51), length 64) 10.20.20.11 > 224.0.0.18: AH(spi=0x0a14de74,sumlen=16,seq=0x155): VRRPv2, Advertisement, vrid 10, <strong>prio 104</strong>, authtype ah, intvl 1s, length 20, addrs: 10.20.20.10 |
Теперь запускаем на второй:
1 2 3 4 5 6 7 8 9 10 |
# keepalived -f /etc/keepalived/keepalived.conf --dont-fork --log-console --log-detail ... VRRP_Script(chk_haproxy) succeeded VRRP_Instance(GALERA_VIP) forcing a new MASTER election VRRP_Instance(GALERA_VIP) forcing a new MASTER election VRRP_Instance(GALERA_VIP) Transition to MASTER STATE VRRP_Instance(GALERA_VIP) Entering MASTER STATE VRRP_Instance(GALERA_VIP) setting protocol VIPs. VRRP_Instance(GALERA_VIP) Sending gratuitous ARPs on eth0 for 10.20.20.10 Netlink reflector reports IP 10.20.20.10 added |
Видим, что виртуальный IP переместился на вторую ноду, т.к. у нее выше суммарный приоритет.
Если нужно открыть протокол VRRP в iptables:
1 2 3 4 |
# /sbin/iptables -I INPUT -i eth0 -d 224.0.0.0/8 -j ACCEPT # /sbin/iptables -A INPUT -p 112 -i eth0 -j ACCEPT # /sbin/iptables -A OUTPUT -p 112 -o eth0 -j ACCEPT # /sbin/iptables save |
Пример конфигурации iptables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# cat /etc/sysconfig/iptables # Generated by iptables-save v1.4.7 on Tue Sep 29 18:43:45 2015 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [21247:2382963] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT #Keepalived vrrp.mcast.net multicast -A INPUT -m pkttype --pkt-type multicast -s 10.20.20.0/16 -d 224.0.0.18/24 -j ACCEPT #HAProxy reads -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 3306 -j ACCEPT #HAProxy writes -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 3307 -j ACCEPT #MAriaDB itself -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 3308 -j ACCEPT #Galera Cluster replication traffic -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 4567 -j ACCEPT #Galera Cluster Incremental State Transfer -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 4568 -j ACCEPT #Rsync_SST -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 4444 -j ACCEPT -A INPUT -s 10.20.0.0/16 -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT # Completed on Tue Sep 29 18:43:45 2015 |
Проверить настройки мультикаста на интерфейсах а также членство в мультикаст группах можно следующими командами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# ip maddr show 1: lo inet 224.0.0.1 inet6 ff02::1 2: eth0 link 01:00:5e:00:00:12 link 33:33:00:00:02:02 link 33:33:ff:00:64:53 link 01:00:5e:00:00:01 link 33:33:00:00:00:01 inet 224.0.0.18 inet 224.0.0.1 inet6 ff02::202 inet6 ff02::1:ff00:6453 inet6 ff02::1 3: eth1 link 33:33:00:00:00:01 inet6 ff02::1 # netstat -g IPv6/IPv4 Group Memberships Interface RefCnt Group --------------- ------ --------------------- lo 1 all-systems.mcast.net eth0 1 vrrp.mcast.net eth0 1 all-systems.mcast.net lo 1 ff02::1 eth0 1 ff02::202 eth0 1 ff02::1:ff00:6453 eth0 1 ff02::1 eth1 1 ff02::1 # cat /proc/net/igmp Idx Device : Count Querier Group Users Timer Reporter 1 lo : 1 V3 010000E0 1 0:00000000 0 2 eth0 : 2 V3 120000E0 1 0:00000000 0 010000E0 1 0:00000000 0 |
Если мультикаст отключён на интерфейсе (но включен в ядре), включить его можно командой:
1 |
# ifconfig eth0 multicast |