ProxySQL е интелигентен и високопроизводителен SQL прокси, който поддържа MySQL, MariaDB и ClickHouse. Наскоро ProxySQL 2.0 се превърна в GA и се предлага с нови вълнуващи функции като GTID консистентно четене, преден SSL, Galera и MySQL Group Replication собствена поддръжка.
Сравнително лесно е да стартирате ProxySQL като Docker контейнер. По-рано сме писали как да стартирате ProxySQL на Kubernetes като помощен контейнер или като услуга на Kubernetes, която е базирана на ProxySQL 1.x. В тази публикация в блога ще използваме новата версия ProxySQL 2.x, която използва различен подход за конфигурацията на Galera Cluster.
ProxySQL 2.x Docker изображение
Пуснахме нов контейнер за изображения на Docker ProxySQL 2.0 и той е наличен в Docker Hub. README предоставя редица примери за конфигурация, особено за Galera и MySQL репликация, преди и след v2.x. Конфигурационните редове могат да бъдат дефинирани в текстов файл и картографирани в пътя на контейнера в /etc/proxysql.cnf, за да бъдат заредени в услугата ProxySQL.
Тагът на изображението "най-нов" все още сочи към 1.x, докато ProxySQL 2.0 официално не стане GA (все още не сме виждали официален блог/статия от екипа на ProxySQL). Което означава, че когато инсталирате ProxySQL изображение, използвайки последния таг от Severalnines, вие пак ще получите версия 1.x с него. Обърнете внимание, че новите примерни конфигурации също така позволяват уеб статистика на ProxySQL (въведена в 1.4.4, но все още в бета версия) – просто табло за управление, което обобщава цялостната конфигурация и състоянието на самия ProxySQL.
ProxySQL 2.x поддръжка за Galera Cluster
Нека поговорим за собствената поддръжка на Galera Cluster по-подробно. Новата таблица mysql_galera_hostgroups се състои от следните полета:
- writer_hostgroup : Идентификатор на хост групата, която ще съдържа всички членове, които са писатели (read_only=0).
- backup_writer_hostgroup : Ако клъстерът работи в режим на няколко записващи устройства (т.е. има множество възли с read_only=0) и max_writers е настроен на по-малък брой от общия брой възли, допълнителните възли се преместват в тази хост група за записване на резервно копие.
- reader_hostgroup : Идентификатор на хост групата, която ще съдържа всички членове, които са читатели (т.е. възли, които имат read_only=1)
- offline_hostgroup : Когато мониторингът на ProxySQL установи, че хостът е ОФЛАЙН, хостът ще бъде преместен в offline_hostgroup.
- активен : булева стойност (0 или 1), за да активирате хост група
- max_writers : Контролира максималния брой допустими възли в хост групата за записване, както бе споменато по-горе, допълнителни възли ще бъдат преместени в backup_writer_hostgroup.
- писец_е_също_четец : Когато е 1, възел в writer_hostgroup също ще бъде поставен в reader_hostgroup, така че да се използва за четене. Когато е зададено на 2, възлите от backup_writer_hostgroup ще бъдат поставени в reader_hostgroup, вместо възела(ите) в writer_hostgroup.
- max_transactions_behind : определя максималния брой набори за запис, които възелът в клъстера може да е поставил на опашка, преди възелът да бъде ИЗБЯГАН, за да се предотврати застояло четене (това се определя чрез запитване на променливата wsrep_local_recv_queue Galera).
- коментар : Текстово поле, което може да се използва за всякакви цели, определени от потребителя
Ето примерна конфигурация за mysql_galera_hostgroups във формат на таблица:
Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
writer_hostgroup: 10
backup_writer_hostgroup: 20
reader_hostgroup: 30
offline_hostgroup: 9999
active: 1
max_writers: 1
writer_is_also_reader: 2
max_transactions_behind: 20
comment:
ProxySQL извършва здравни проверки на Galera, като наблюдава следното състояние/променлива на MySQL:
- само за четене - Ако е ON, тогава ProxySQL ще групира дефинирания хост в reader_hostgroup, освен ако writer_is_also_reader е 1.
- wsrep_desync - Ако е ON, ProxySQL ще маркира възела като недостъпен, премествайки го в offline_hostgroup.
- wsrep_reject_queries - Ако тази променлива е ON, ProxySQL ще маркира възела като недостъпен, премествайки го в offline_hostgroup (полезно в определени ситуации на поддръжка).
- wsrep_sst_donor_rejects_queries - Ако тази променлива е ON, ProxySQL ще маркира възела като недостъпен, докато възелът Galera служи като SST донор, премествайки го в offline_hostgroup.
- wsrep_local_state - Ако това състояние се върне различно от 4 (4 означава синхронизиран), ProxySQL ще маркира възела като недостъпен и ще го премести в offline_hostgroup.
- wsrep_local_recv_queue - Ако това състояние е по-високо от max_transactions_behind, възелът ще бъде избегнат.
- wsrep_cluster_status - Ако това състояние се върне различно от Основно, ProxySQL ще маркира възела като недостъпен и ще го премести в offline_hostgroup.
Като каза това, като комбинира тези нови параметри в mysql_galera_hostgroups заедно с mysql_query_rules, ProxySQL 2.x има гъвкавостта да се вмести в много повече случаи на използване на Galera. Например, може да има хостгрупи с един запис, множество записващи и мулти-четеци, дефинирани като целева хостгрупа на правило за заявка, с възможност за ограничаване на броя на записващите и по-фин контрол върху поведението на остаряло четене.
Сравнете това с ProxySQL 1.x, където потребителят трябваше изрично да дефинира планировчик, който да извика външен скрипт за извършване на проверките на състоянието на бекенда и актуализиране на състоянието на сървърите на базата данни. Това изисква известно персонализиране на скрипта (потребителят трябва да актуализира администраторския потребител/парола/порт на ProxySQL) плюс това зависи от допълнителен инструмент (MySQL клиент), за да се свърже с администраторския интерфейс на ProxySQL.
Ето примерна конфигурация на скриптов планировчик за проверка на здравето на Galera в табличен формат за ProxySQL 1.x:
Admin> select * from scheduler\G
*************************** 1. row ***************************
id: 1
active: 1
interval_ms: 2000
filename: /usr/share/proxysql/tools/proxysql_galera_checker.sh
arg1: 10
arg2: 20
arg3: 1
arg4: 1
arg5: /var/lib/proxysql/proxysql_galera_checker.log
comment:
Освен това, тъй като нишката на планировчика на ProxySQL изпълнява всеки скрипт независимо, има много версии на скриптове за проверка на здравето. Всички екземпляри на ProxySQL, внедрени от ClusterControl, използват скрипта по подразбиране, предоставен от инсталационния пакет на ProxySQL.
В ProxySQL 2.x, max_writers и writer_is_also_reader променливите могат да определят как ProxySQL динамично групира бекенд MySQL сървърите и ще повлияе пряко на разпределението на връзката и маршрутизирането на заявки. Например, помислете за следните сървъри на MySQL:
Admin> select hostgroup_id, hostname, status, weight from mysql_servers;
+--------------+--------------+--------+--------+
| hostgroup_id | hostname | status | weight |
+--------------+--------------+--------+--------+
| 10 | DB1 | ONLINE | 1 |
| 10 | DB2 | ONLINE | 1 |
| 10 | DB3 | ONLINE | 1 |
+--------------+--------------+--------+--------+
Заедно със следната дефиниция на хостгрупи на Galera:
Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
writer_hostgroup: 10
backup_writer_hostgroup: 20
reader_hostgroup: 30
offline_hostgroup: 9999
active: 1
max_writers: 1
writer_is_also_reader: 2
max_transactions_behind: 20
comment:
Като се има предвид, че всички хостове са стартирани и работят, ProxySQL най-вероятно ще групира хостовете, както следва:
Нека ги разгледаме един по един:
Конфигурация | Описание |
---|---|
writer_is_also_reader=0 |
|
writer_is_also_reader=1 |
|
writer_is_also_reader=2 |
|
С тази конфигурация човек може да има различни възможности за избор за дестинация на хостгрупа, за да се погрижи за специфични натоварвания. Записванията на „гореща точка“ могат да бъдат конфигурирани да отиват само до един сървър, за да се намалят конфликтите с множество главни, неконфликтните записи могат да бъдат разпределени по равно на другите главни устройства, повечето четения могат да бъдат разпределени равномерно на всички сървъри на MySQL или не-записващи, критични четения могат да бъдат препратени към най-актуалните сървъри, а аналитичните показания могат да бъдат препратени към подчинена реплика.
Разгръщане на ProxySQL за клъстер Galera
В този пример да предположим, че вече имаме клъстер Galera с три възела, разгърнат от ClusterControl, както е показано на следната диаграма:
Нашите Wordpress приложения се изпълняват на Docker, докато базата данни на Wordpress се хоства на нашия Galera Cluster, работещ на голи сървъри. Решихме да стартираме ProxySQL контейнер заедно с нашите Wordpress контейнери, за да имаме по-добър контрол върху маршрутизирането на заявки за база данни на Wordpress и да използваме напълно нашата клъстерна инфраструктура на базата данни. Тъй като съотношението четене-запис е около 80%-20%, искаме да конфигурираме ProxySQL за:
- Препращане на всички записи към един възел на Galera (по-малко конфликт, фокус върху запис)
- Балансирайте всички показания към другите два възела на Galera (по-добро разпределение за по-голямата част от работното натоварване)
Първо, създайте конфигурационен файл на ProxySQL вътре в хоста на Docker, за да можем да го съпоставим в нашия контейнер:
$ mkdir /root/proxysql-docker
$ vim /root/proxysql-docker/proxysql.cnf
След това копирайте следните редове (ще обясним конфигурационните редове по-долу):
datadir="/var/lib/proxysql"
admin_variables=
{
admin_credentials="admin:admin"
mysql_ifaces="0.0.0.0:6032"
refresh_interval=2000
web_enabled=true
web_port=6080
stats_credentials="stats:admin"
}
mysql_variables=
{
threads=4
max_connections=2048
default_query_delay=0
default_query_timeout=36000000
have_compress=true
poll_timeout=2000
interfaces="0.0.0.0:6033;/tmp/proxysql.sock"
default_schema="information_schema"
stacksize=1048576
server_version="5.1.30"
connect_timeout_server=10000
monitor_history=60000
monitor_connect_interval=200000
monitor_ping_interval=200000
ping_interval_server_msec=10000
ping_timeout_server=200
commands_stats=true
sessions_sort=true
monitor_username="proxysql"
monitor_password="proxysqlpassword"
monitor_galera_healthcheck_interval=2000
monitor_galera_healthcheck_timeout=800
}
mysql_galera_hostgroups =
(
{
writer_hostgroup=10
backup_writer_hostgroup=20
reader_hostgroup=30
offline_hostgroup=9999
max_writers=1
writer_is_also_reader=1
max_transactions_behind=30
active=1
}
)
mysql_servers =
(
{ address="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="db3.cluster.local" , port=3306 , hostgroup=10, max_connections=100 }
)
mysql_query_rules =
(
{
rule_id=100
active=1
match_pattern="^SELECT .* FOR UPDATE"
destination_hostgroup=10
apply=1
},
{
rule_id=200
active=1
match_pattern="^SELECT .*"
destination_hostgroup=30
apply=1
},
{
rule_id=300
active=1
match_pattern=".*"
destination_hostgroup=10
apply=1
}
)
mysql_users =
(
{ username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
{ username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)
Сега, нека да посетим някои от най-конфигурационните секции. Първо, ние дефинираме конфигурацията на хост групите на Galera, както следва:
mysql_galera_hostgroups =
(
{
writer_hostgroup=10
backup_writer_hostgroup=20
reader_hostgroup=30
offline_hostgroup=9999
max_writers=1
writer_is_also_reader=1
max_transactions_behind=30
active=1
}
)
Hostgroup 10 ще бъде writer_hostgroup, hostgroup 20 за backup_writer и hostgroup 30 за reader. Задаваме max_writers на 1, за да можем да имаме хостгрупа с един запис за хостгрупа 10, където трябва да се изпращат всички записи. След това дефинираме writer_is_also_reader на 1, което ще направи всички възли на Galera също така четящи, подходящи за заявки, които могат да бъдат равномерно разпределени към всички възли. Hostgroup 9999 е запазен за offline_hostgroup, ако ProxySQL открие неработещи възли на Galera.
След това конфигурираме нашите MySQL сървъри с хостгрупа 10 по подразбиране:
mysql_servers =
(
{ address="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="db3.cluster.local" , port=3306 , hostgroup=10, max_connections=100 }
)
С горните конфигурации, ProxySQL ще "вижда" нашите хост групи, както е по-долу:
След това дефинираме маршрутизирането на заявката чрез правила за заявка. Въз основа на нашето изискване, всички показания трябва да бъдат изпратени до всички възли на Galera с изключение на записващия (хостгрупа 20), а всичко останало се препраща към хост група 10 за единичен записващ:
mysql_query_rules =
(
{
rule_id=100
active=1
match_pattern="^SELECT .* FOR UPDATE"
destination_hostgroup=10
apply=1
},
{
rule_id=200
active=1
match_pattern="^SELECT .*"
destination_hostgroup=20
apply=1
},
{
rule_id=300
active=1
match_pattern=".*"
destination_hostgroup=10
apply=1
}
)
И накрая, ние дефинираме потребителите на MySQL, които ще бъдат предавани през ProxySQL:
mysql_users =
(
{ username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
{ username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)
Задаваме transaction_persistent на 0, така че всички връзки, идващи от тези потребители, ще спазват правилата за заявка за маршрутизиране на четене и запис. В противен случай връзките в крайна сметка биха удряли една хост група, което побеждава целта за балансиране на натоварването. Не забравяйте първо да създадете тези потребители на всички MySQL сървъри. За потребител на ClusterControl можете да използвате функцията Управление -> Схеми и потребители, за да създадете тези потребители.
Вече сме готови да стартираме нашия контейнер. Ще съпоставим конфигурационния файл на ProxySQL като монтиране на свързване при стартиране на контейнера ProxySQL. По този начин командата за изпълнение ще бъде:
$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
severalnines/proxysql:2.0
И накрая, променете базата данни на Wordpress, сочеща към ProxySQL контейнер порт 6033, например:
$ docker run -d \
--name wordpress \
--publish 80:80 \
--restart=unless-stopped \
-e WORDPRESS_DB_HOST=proxysql2:6033 \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_HOST=passw0rd \
wordpress
В този момент нашата архитектура изглежда така:
Ако искате контейнерът ProxySQL да бъде постоянен, съпоставете /var/lib/proxysql/ с обем на Docker или свързване, например:
$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
-v proxysql-volume:/var/lib/proxysql \
severalnines/proxysql:2.0
Имайте предвид, че работата с постоянно съхранение като горното ще направи нашия /root/proxysql/proxysql.cnf остарял при второто рестартиране. Това се дължи на многослойна конфигурация на ProxySQL, при която ако /var/lib/proxysql/proxysql.db съществува, ProxySQL ще пропусне опциите за зареждане от конфигурационния файл и вместо това ще зареди всичко, което е в базата данни на SQLite (освен ако не стартирате услугата proxysql с --initial флаг). Като се има предвид това, следващото управление на конфигурацията на ProxySQL трябва да се извърши чрез ProxySQL администраторска конзола на порт 6032, вместо да се използва конфигурационен файл.
Наблюдение
Регистрационният файл на процесите на ProxySQL по подразбиране се регистрира в syslog и можете да ги прегледате, като използвате стандартната команда за докер:
$ docker ps
$ docker logs proxysql2
За да проверите текущата хостгрупа, потърсете таблицата runtime_mysql_servers:
$ docker exec -it proxysql2 mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt='Admin> '
Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname | status |
+--------------+--------------+--------+
| 10 | 192.168.0.21 | ONLINE |
| 30 | 192.168.0.21 | ONLINE |
| 30 | 192.168.0.22 | ONLINE |
| 30 | 192.168.0.23 | ONLINE |
| 20 | 192.168.0.22 | ONLINE |
| 20 | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+
Ако избраната програма за записване падне, тя ще бъде прехвърлена към offline_hostgroup (HID 9999):
Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname | status |
+--------------+--------------+--------+
| 10 | 192.168.0.22 | ONLINE |
| 9999 | 192.168.0.21 | ONLINE |
| 30 | 192.168.0.22 | ONLINE |
| 30 | 192.168.0.23 | ONLINE |
| 20 | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+
Горните промени в топологията могат да бъдат илюстрирани на следната диаграма:
Ние също така активирахме потребителския интерфейс за уеб статистика с admin-web_enabled=true. За достъп до уеб потребителския интерфейс, просто отидете на хоста на Docker в порт 6080, например:http://192.168.0.200:8060 и ще бъдете подканени с изскачащо потребителско име/парола. Въведете идентификационните данни, както са дефинирани под admin-stats_credentials и трябва да видите следната страница:
Чрез наблюдение на MySQL таблицата на пула за връзки можем да получим общ преглед на разпределението на връзките за всички хост групи:
Admin> select hostgroup, srv_host, status, ConnUsed, MaxConnUsed, Queries from stats.stats_mysql_connection_pool order by srv_host;
+-----------+--------------+--------+----------+-------------+---------+
| hostgroup | srv_host | status | ConnUsed | MaxConnUsed | Queries |
+-----------+--------------+--------+----------+-------------+---------+
| 20 | 192.168.0.23 | ONLINE | 5 | 24 | 11458 |
| 30 | 192.168.0.23 | ONLINE | 0 | 0 | 0 |
| 20 | 192.168.0.22 | ONLINE | 2 | 24 | 11485 |
| 30 | 192.168.0.22 | ONLINE | 0 | 0 | 0 |
| 10 | 192.168.0.21 | ONLINE | 32 | 32 | 9746 |
| 30 | 192.168.0.21 | ONLINE | 0 | 0 | 0 |
+-----------+--------------+--------+----------+-------------+---------+
Резултатът по-горе показва, че хостгрупа 30 не обработва нищо, защото нашите правила за заявка нямат тази хостгрупа, конфигурирана като целева хостгрупа.
Статистиката, свързана с възлите Galera, може да се види в таблицата mysql_server_galera_log:
Admin> select * from mysql_server_galera_log order by time_start_us desc limit 3\G
*************************** 1. row ***************************
hostname: 192.168.0.23
port: 3306
time_start_us: 1552992553332489
success_time_us: 2045
primary_partition: YES
read_only: NO
wsrep_local_recv_queue: 0
wsrep_local_state: 4
wsrep_desync: NO
wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
error: NULL
*************************** 2. row ***************************
hostname: 192.168.0.22
port: 3306
time_start_us: 1552992553329653
success_time_us: 2799
primary_partition: YES
read_only: NO
wsrep_local_recv_queue: 0
wsrep_local_state: 4
wsrep_desync: NO
wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
error: NULL
*************************** 3. row ***************************
hostname: 192.168.0.21
port: 3306
time_start_us: 1552992553329013
success_time_us: 2715
primary_partition: YES
read_only: NO
wsrep_local_recv_queue: 0
wsrep_local_state: 4
wsrep_desync: NO
wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
error: NULL
Наборът от резултати връща свързаната променлива/състояние на MySQL за всеки възел на Galera за определен времеви печат. В тази конфигурация конфигурирахме проверката на здравето на Galera да се изпълнява на всеки 2 секунди (monitor_galera_healthcheck_interval=2000). Следователно максималното време за преминаване при отказ ще бъде около 2 секунди, ако се случи промяна в топологията на клъстера.
Препратки
- ProxySQL собствена поддръжка на Galera
- HA и клъстерно решение:ProxySQL като интелигентен рутер за Galera и групова репликация
- ProxySQL Docker изображение от Severalnines
- Как да наблюдавате ProxySQL с Prometheus и ClusterControl