HAProxy и ProxySQL са много популярни средства за балансиране на натоварването в света на MySQL, но има значителна разлика между двата прокси сървъра. Тук няма да навлизаме в подробности, можете да прочетете повече за HAProxy в HAProxy Tutorial и ProxySQL в ProxySQL Tutorial. Най-важната разлика е, че ProxySQL е прокси, работещ с SQL, анализира трафика и разбира MySQL протокола и като такъв може да се използва за разширено оформяне на трафика - можете да блокирате заявки, да ги пренапишете, да ги насочвате към определени хостове, да кеширате тях и много други. HAProxy, от друга страна, е много прост, но ефективен прокси сървър на слой 4 и всичко, което прави, е да изпраща пакети до бекенда. ProxySQL може да се използва за извършване на разделяне на четене-запис - той разбира SQL и може да бъде конфигуриран да открива дали заявката е SELECT или не и да ги насочва съответно:SELECT към всички възли, други заявки само за овладяване. Тази функция не е налична в HAProxy, който трябва да използва два отделни порта и два отделни бекенда за главен и подчинен – разделянето на четене и запис трябва да се извърши от страната на приложението.
Защо да мигрираме към ProxySQL?
Въз основа на разликите, които обяснихме по-горе, бихме казали, че основната причина, поради която може да искате да преминете от HAProxy към ProxySQL, е поради липсата на разделяне на четене-запис в HAProxy. Ако използвате клъстер от MySQL бази данни и всъщност няма значение дали това е асинхронна репликация или клъстер Galera, вероятно искате да можете да разделяте прочитанията от записите. За MySQL репликация, очевидно, това би бил единственият начин да се използва клъстерът на базата данни, тъй като записите винаги трябва да се изпращат до главния. Следователно, ако не можете да извършите разделянето четене-запис, можете да изпращате заявки само до главния. За Galera разделянето на четене-запис не е задължително, но определено трябва да имате. Разбира се, можете да конфигурирате всички възли на Galera като един бекенд в HAProxy и да изпращате трафик към всички тях по кръгова система, но това може да доведе до конфликти помежду си на запис от множество възли, което води до блокиране и спад на производителността. Виждахме и проблеми и грешки в клъстера Galera, за които, докато не бъдат отстранени, заобиколното решение беше да се насочат всички записи към един възел. По този начин най-добрата практика е да изпратите всички записи до един възел на Galera, тъй като това води до по-стабилно поведение и по-добра производителност.
Друга много добра причина за миграция към ProxySQL е необходимостта от по-добър контрол върху трафика. С HAProxy не можете да направите нищо - той просто изпраща трафика към своите бекендове. С ProxySQL можете да оформите трафика си с помощта на правила за заявка (съпоставяне на трафик с помощта на регулярни изрази, потребител, схема, изходен хост и много други). Можете да пренасочите OLAP SELECT към подчинен аналитичен (това е вярно както за репликация, така и за Galera). Можете да разтоварите своя мастер, като пренасочите някои от SELECTs извън него. Можете да внедрите SQL защитна стена. Можете да добавите забавяне към някои от заявките, можете да прекратите заявките, ако отнемат повече от предварително определено време. Можете да пренапишете заявки, за да добавите съвети за оптимизатор. Всичко това не е възможно с HAProxy.
Как да мигрирам от HAProxy към ProxySQL?
Първо, нека разгледаме следната топология...
ClusterControl MySQL Топология Клъстер за репликация на MySQL в ClusterControlТук имаме клъстер за репликация, състоящ се от главен и два подчинени. Имаме разгърнати два HAProxy възела, всеки използва два бекенда - на порт 3307 за главен (запис) и 3308 за всички възли (чете). Keepalived се използва за предоставяне на виртуален IP в тези два HAProxy екземпляра - ако един от тях се провали, ще се използва друг. Нашето приложение се свързва директно с VIP, през него с един от HAProxy инстанциите. Да приемем, че нашето приложение (ще използваме Sysbench) не може да направи разделянето четене-запис, следователно трябва да се свържем с бекенда на „писача“. В резултат на това по-голямата част от натоварването е върху нашия главен код (10.0.0.101).
Какви биха били стъпките за мигриране към ProxySQL? Нека помислим за момент. Първо, трябва да разположим и конфигурираме ProxySQL. Ще трябва да добавим сървъри към ProxySQL, да създадем необходими потребители за наблюдение и да създадем правилни правила за заявка. И накрая, ще трябва да разположим Keepalived върху ProxySQL, да създадем друг виртуален IP и след това да осигурим възможно най-безпроблемно превключване за нашето приложение от HAProxy към ProxySQL.
Нека да разгледаме как можем да постигнем това...
Как да инсталирам ProxySQL
Човек може да инсталира ProxySQL по много начини. Можете да използвате хранилище или от самия ProxySQL (https://repo.proxysql.com) или ако случайно използвате Percona XtraDB Cluster, можете също да инсталирате ProxySQL от хранилището на Percona, въпреки че може да изисква допълнителна конфигурация, тъй като разчита на CLI администраторски инструменти, създадени за PXC. Като се има предвид, че говорим за репликация, използването им може просто да направи нещата по-сложни. И накрая, можете също да инсталирате двоични файлове на ProxySQL, след като ги изтеглите от ProxySQL GitHub. В момента има две стабилни версии, 1.4.x и 2.0.x. Има разлики между ProxySQL 1.4 и ProxySQL 2.0 по отношение на функциите, за този блог ще се придържаме към клона 1.4.x, тъй като е по-добре тестван и наборът от функции е достатъчен за нас.
Ще използваме ProxySQL хранилище и ще разположим ProxySQL на два допълнителни възела:10.0.0.103 и 10.0.0.104.
Първо, ще инсталираме ProxySQL, използвайки официалното хранилище. Ние също така ще гарантираме, че MySQL клиентът е инсталиран (ще го използваме за конфигуриране на ProxySQL). Моля, имайте предвид, че процесът, през който преминаваме, не е производствен. За производството ще искате да промените поне идентификационните данни по подразбиране за администраторския потребител. Вие също ще искате да прегледате конфигурацията и да се уверите, че е в съответствие с вашите очаквания и изисквания.
apt-get install -y lsb-release
wget -O - 'https://repo.proxysql.com/ProxySQL/repo_pub_key' | apt-key add -
echo deb https://repo.proxysql.com/ProxySQL/proxysql-1.4.x/$(lsb_release -sc)/ ./ | tee /etc/apt/sources.list.d/proxysql.list
apt-get -y update
apt-get -y install proxysql
service proxysql start
Сега, след като ProxySQL е стартиран, ще използваме CLI, за да конфигурираме ProxySQL.
mysql -uadmin -padmin -P6032 -h127.0.0.1
Първо, ще дефинираме бекенд сървъри и хост групи за репликация:
mysql> INSERT INTO mysql_servers (hostgroup_id, hostname) VALUES (10, '10.0.0.101'), (20, '10.0.0.102'), (20, '10.0.0.103');
Query OK, 3 rows affected (0.91 sec)
mysql> INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup) VALUES (10, 20);
Query OK, 1 row affected (0.00 sec)
Имаме три сървъра, дефинирахме също, че ProxySQL трябва да използва хостгрупа 10 за главен (възел с read_only=0) и хостгрупа 20 за подчинени (read_only=1).
Като следваща стъпка трябва да добавим потребител за наблюдение на възлите на MySQL, така че ProxySQL да може да ги наблюдава. Ще преминем към настройките по подразбиране, в идеалния случай вие ще промените идентификационните данни в ProxySQL.
mysql> SHOW VARIABLES LIKE 'mysql-monitor_username';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| mysql-monitor_username | monitor |
+------------------------+---------+
1 row in set (0.00 sec)
mysql> SHOW VARIABLES LIKE 'mysql-monitor_password';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| mysql-monitor_password | monitor |
+------------------------+---------+
1 row in set (0.00 sec)
Така че трябва да създадем потребителски „монитор“ с парола „монитор“. За да направим това, ще трябва да изпълним следното разрешение на главния MySQL сървър:
mysql> create user [email protected]'%' identified by 'monitor';
Query OK, 0 rows affected (0.56 sec)
Обратно към ProxySQL – трябва да конфигурираме потребителите, които нашето приложение ще използва за достъп до MySQL и правила за заявки, които имат за цел да ни дадат разделяне за четене и запис.
mysql> INSERT INTO mysql_users (username, password, default_hostgroup) VALUES ('sbtest', 'sbtest', 10);
Query OK, 1 row affected (0.34 sec)
mysql> INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES (100, 1, '^SELECT.*FOR UPDATE$',10,1), (200,1,'^SELECT',20,1), (300,1,'.*',10,1);
Query OK, 3 rows affected (0.01 sec)
Моля, имайте предвид, че използвахме парола в обикновен текст и ще разчитаме на ProxySQL, за да я хешира. От съображения за сигурност трябва изрично да предадете тук хеша на паролата за MySQL.
Накрая трябва да приложим всички промени.
mysql> LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.02 sec)
mysql> LOAD MYSQL USERS TO RUNTIME;
Query OK, 0 rows affected (0.01 sec)
mysql> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.01 sec)
mysql> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.07 sec)
mysql> SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.02 sec)
Също така искаме да заредим хешираните пароли от времето за изпълнение:паролите с обикновен текст се хешират, когато се заредят в конфигурацията по време на изпълнение, за да ги запазим хеширани на диска, трябва да го заредим от времето за изпълнение и след това да го съхраним на диск:
mysql> SAVE MYSQL USERS FROM RUNTIME;
Query OK, 0 rows affected (0.00 sec)
mysql> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.02 sec)
Това е всичко, когато става въпрос за ProxySQL. Преди да направите допълнителни стъпки, трябва да проверите дали можете да се свържете с прокси сървъри от вашите сървъри на приложения.
[email protected]:~# mysql -h 10.0.0.103 -usbtest -psbtest -P6033 -e "SELECT * FROM sbtest.sbtest4 LIMIT 1\G"
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
id: 1
k: 50147
c: 68487932199-96439406143-93774651418-41631865787-96406072701-20604855487-25459966574-28203206787-41238978918-19503783441
pad: 22195207048-70116052123-74140395089-76317954521-98694025897
В нашия случай всичко изглежда добре. Сега е време да инсталирате Keepalived.
Поддържана инсталация
Инсталацията е доста проста (поне на Ubuntu 16.04, който използвахме):
apt install keepalived
След това трябва да създадете конфигурационни файлове и за двата сървъра:
Главен поддържащ възел:
vrrp_script chk_haproxy {
script "killall -0 haproxy" # verify the pid existance
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_HAPROXY {
interface eth1 # interface to monitor
state MASTER
virtual_router_id 52 # Assign one ID for this route
priority 101
unicast_src_ip 10.0.0.103
unicast_peer {
10.0.0.104
}
virtual_ipaddress {
10.0.0.112 # the virtual IP
}
track_script {
chk_haproxy
}
# notify /usr/local/bin/notify_keepalived.sh
}
Архивно поддържан възел:
vrrp_script chk_haproxy {
script "killall -0 haproxy" # verify the pid existance
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_HAPROXY {
interface eth1 # interface to monitor
state MASTER
virtual_router_id 52 # Assign one ID for this route
priority 100
unicast_src_ip 10.0.0.103
unicast_peer {
10.0.0.104
}
virtual_ipaddress {
10.0.0.112 # the virtual IP
}
track_script {
chk_haproxy
}
# notify /usr/local/bin/notify_keepalived.sh
Това е всичко, можете да започнете да поддържате активност и на двата възела:
service keepalived start
Трябва да видите информация в регистрационните файлове, че един от възлите е влязъл в състояние MASTER и че VIP е изведен на този възел.
May 7 09:52:11 vagrant systemd[1]: Starting Keepalive Daemon (LVS and VRRP)...
May 7 09:52:11 vagrant Keepalived[26686]: Starting Keepalived v1.2.24 (08/06,2018)
May 7 09:52:11 vagrant Keepalived[26686]: Opening file '/etc/keepalived/keepalived.conf'.
May 7 09:52:11 vagrant Keepalived[26696]: Starting Healthcheck child process, pid=26697
May 7 09:52:11 vagrant Keepalived[26696]: Starting VRRP child process, pid=26698
May 7 09:52:11 vagrant Keepalived_healthcheckers[26697]: Initializing ipvs
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Registering Kernel netlink reflector
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Registering Kernel netlink command channel
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Registering gratuitous ARP shared channel
May 7 09:52:11 vagrant systemd[1]: Started Keepalive Daemon (LVS and VRRP).
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Unable to load ipset library
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Unable to initialise ipsets
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Opening file '/etc/keepalived/keepalived.conf'.
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: Using LinkWatch kernel netlink reflector...
May 7 09:52:11 vagrant Keepalived_healthcheckers[26697]: Registering Kernel netlink reflector
May 7 09:52:11 vagrant Keepalived_healthcheckers[26697]: Registering Kernel netlink command channel
May 7 09:52:11 vagrant Keepalived_healthcheckers[26697]: Opening file '/etc/keepalived/keepalived.conf'.
May 7 09:52:11 vagrant Keepalived_healthcheckers[26697]: Using LinkWatch kernel netlink reflector...
May 7 09:52:11 vagrant Keepalived_vrrp[26698]: pid 26701 exited with status 256
May 7 09:52:12 vagrant Keepalived_vrrp[26698]: VRRP_Instance(VI_HAPROXY) Transition to MASTER STATE
May 7 09:52:13 vagrant Keepalived_vrrp[26698]: pid 26763 exited with status 256
May 7 09:52:13 vagrant Keepalived_vrrp[26698]: VRRP_Instance(VI_HAPROXY) Entering MASTER STATE
May 7 09:52:15 vagrant Keepalived_vrrp[26698]: pid 26806 exited with status 256
[email protected]:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:ee:87:c4 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:feee:87c4/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:fc:ac:21 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.103/24 brd 10.0.0.255 scope global eth1
valid_lft forever preferred_lft forever
inet 10.0.0.112/32 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fefc:ac21/64 scope link
valid_lft forever preferred_lft forever
Както можете да видите, на възел 10.0.0.103 е повдигнат VIP (10.0.0.112). Вече можем да завършим с преместването на трафика от старата настройка в новата.
Превключване на трафика към настройка на ProxySQL
Има много методи за това как да го направите, най-вече зависи от вашата конкретна среда. Ако случайно използвате DNS, за да поддържате домейн, сочещ към вашия HAProxy VIP, , можете просто да направите промяна там и постепенно, с течение на времето всички връзки ще насочват отново към новия VIP. Можете също да направите промяна в приложението си, особено ако подробностите за връзката са твърдо кодирани - след като разгърнете промяната, възлите ще започнат да се свързват с новата настройка. Без значение как го правите, би било чудесно да тествате новата настройка, преди да направите глобално превключване. Със сигурност сте го тествали във вашата среда за създаване, но не е лоша идея да изберете шепа сървъри за приложения и да ги пренасочите към новия прокси, като наблюдавате как изглеждат по отношение на производителността. По-долу е даден прост пример за използване на iptables, който може да бъде полезен за тестване.
На хостовете ProxySQL пренасочете трафика от хост 10.0.0.11 и порт 3307 към хост 10.0.0.112 и порт 6033:
iptables -t nat -A OUTPUT -p tcp -d 10.0.0.111 --dport 3307 -j DNAT --to-destination 10.0.0.112:6033
В зависимост от вашето приложение може да се наложи да рестартирате уеб сървъра или други услуги (ако приложението ви създава постоянен пул от връзки към базата данни) или просто изчакайте, когато ще се отворят нови връзки срещу ProxySQL. Можете да проверите дали ProxySQL получава трафика:
mysql> show processlist;
+-----------+--------+--------+-----------+---------+---------+-----------------------------------------------------------------------------+
| SessionID | user | db | hostgroup | command | time_ms | info |
+-----------+--------+--------+-----------+---------+---------+-----------------------------------------------------------------------------+
| 12 | sbtest | sbtest | 20 | Sleep | 0 | |
| 13 | sbtest | sbtest | 10 | Query | 0 | DELETE FROM sbtest23 WHERE id=49957 |
| 14 | sbtest | sbtest | 10 | Query | 59 | DELETE FROM sbtest11 WHERE id=50185 |
| 15 | sbtest | sbtest | 20 | Query | 59 | SELECT c FROM sbtest8 WHERE id=46054 |
| 16 | sbtest | sbtest | 20 | Query | 0 | SELECT DISTINCT c FROM sbtest27 WHERE id BETWEEN 50115 AND 50214 ORDER BY c |
| 17 | sbtest | sbtest | 10 | Query | 0 | DELETE FROM sbtest32 WHERE id=50084 |
| 18 | sbtest | sbtest | 10 | Query | 26 | DELETE FROM sbtest28 WHERE id=34611 |
| 19 | sbtest | sbtest | 10 | Query | 16 | DELETE FROM sbtest4 WHERE id=50151 |
+-----------+--------+--------+-----------+---------+---------+-----------------------------------------------------------------------------+
Това беше всичко, преместихме трафика от HAProxy в настройката на ProxySQL. Отне някои стъпки, но определено е изпълнимо с много малко прекъсване на услугата.
Как да мигрираме от HAProxy към ProxySQL с помощта на ClusterControl?
В предишния раздел обяснихме как ръчно да разположите настройката на ProxySQL и след това да мигрирате към нея. В този раздел бихме искали да обясним как да постигнем същата цел с помощта на ClusterControl. Първоначалната настройка е абсолютно същата, затова трябва да продължим с внедряването на ProxySQL.
Разгръщане на ProxySQL с помощта на ClusterControl
Внедряването на ProxySQL в ClusterControl е само въпрос на шепа кликвания.
Разгръщане на ProxySQL в ClusterControlТрябваше да изберем IP или име на хост на възел, да подадем идентификационни данни за администраторски потребител на CLI и потребител за наблюдение на MySQL. Решихме да използваме съществуващ MySQL и предадохме подробности за достъп за потребител на ‘sbtest’@’%’, който използваме в приложението. Избрахме кои възли искаме да използваме в балансира на натоварването, също така увеличихме максималното забавяне на репликацията (ако този праг бъде прекрачен, ProxySQL няма да изпрати трафика към този подчинен) от 10 секунди по подразбиране на 100, тъй като вече страдаме от репликацията закъснение. След кратко време ProxySQL възлите ще бъдат добавени към клъстера.
Разгръщане на Keepalived за ProxySQL с помощта на ClusterControl
Когато ProxySQL възлите са добавени, е време да внедрите Keepalived.
Поддържа се с ProxySQL в ClusterControlВсичко, което трябваше да направим, е да изберем на кои ProxySQL възли искаме да се разположи Keepalived, виртуален IP и интерфейс, към който ще бъде свързан VIP. Когато разполагането приключи, ще превключим трафика към новата настройка, като използваме един от методите, споменати в раздела „Превключване на трафика към настройката на ProxySQL“ по-горе.
Мониторинг на трафика на ProxySQL в ClusterControlМожем да проверим дали трафикът е превключил на ProxySQL, като погледнем графиката на натоварването - както можете да видите, натоварването е много по-разпределено между възлите в клъстера. Можете също да го видите на графиката по-долу, която показва разпределението на заявките в клъстера.
Табло за управление на ProxySQL в ClusterControlИ накрая, ProxySQL таблото за управление също показва, че трафикът се разпределя между всички възли в клъстера:
ProxySQL Dashboard в ClusterControlНадяваме се, че ще се възползвате от тази публикация в блога, както можете да видите, с ClusterControl, внедряването на новата архитектура отнема само момент и изисква само шепа щраквания, за да стартират нещата. Кажете ни за вашия опит в подобни миграции.