Хабрахабр

ProxySQL — средство для демультиплексирования соединений

Здравствуйте, меня зовут Александр Яковлев, я работаю в компании Ситимобил и занимаюсь эксплуатацией. Сегодня я расскажу про очень интересный продукт ProxySQL — это высокопроизводительный MySQL Proxy, который умеет очень много — отлавливать и убивать запросы по маске, с помощью него можно искать sql injection, дублировать нагрузку и много другое. Я расскажу о нашем опыте работы с ним.
С описанной ниже ситуацией рано или поздно сталкивается любой крупный IT-проект, развитие которого начиналось с пары серверов. Представим, что в проекте сначала была только одна база данных — мастер-сервер. Постепенно к нему добавили кучу слейвов. Потом внедрили шардинг.
И в один прекрасный день нагрузка внезапно возрастает в 10 раз. Например, потому что упал ваш основной конкурент, и клиенты хлынули к вам. В этот момент вам кажется, что можно элементарно масштабировать нагрузку добавлением веб-серверов. Но после того, как вы сделали это, возникает неприятная ситуация.

Рассмотрим на примере одного мастера. Допустим, у вас 50 web серверов и на каждом 200 php-fpm процессов. Тогда в мастер прилетит 50*200 коннектов, при этом в каждый слейв придет 50*200/количество слейвов (если, конечно же, в haproxy настроен roundrobin) — смотрите картинку ниже. Конечно, 10 тыс. коннектов в мастер — это много, но еще терпимо, а если будет 200 вебов, то количество коннектов будет еще больше, а один коннект = один тред.
Именно в это бутылочное горлышко мы уперлись.

image

Дальше мы стали рассуждать: коннект в мастер устанавливается в коде всегда, но нужен ли он всем fpm процессам? Скорее всего, нет. Мы заметили, что большое количество persist-коннектов в мастер просто висят в слипах. И решили, что нам нужно демультиплексирование.

image

Для этого мы обратили внимание на продукт под названием ProxySQL. Он работает как обычный reverse proxy: к нему устанавливаются подключения, и он перераспределяет трафик по определенным правилам, указанным в конфигурации.
Мы установили ProxySQL на всех наших веб-серверах, а в конфигурации приложения прописали, что обращение в мастер-базу выполняется по адресу 127.0.0.1. Если раньше 200 FPM-воркеров на каждом веб-сервере означали 200 подключений к мастер-базе от этой машины, то теперь ситуация изменилась. Эти 200 подключений приходят в ProxySQL, а наружу в разное время выходят 50-70. То есть ProxySQL умеет многократно использовать уже установленные подключения.
Благодаря демультиплексированию мы на всех мастерах сократили количество подключений в 3-10 раз, график current connections одного из мастеров смотрите ниже.

image

Благодаря ProxySQL мы избавились от вышеописанного бутылочного горлышка. Но это не единственный рабочий процесс, который мы улучшили с помощью этого инструмента.
Второй процесс мы еще не доделали, но очень близки к завершению. С помощью ProxySQL мы планируем дублировать реальную нагрузку в тестовую среду. Это нужно для проверки новых фич боевым трафиком.
Как это будет реализовано? Приложение идет в ProxySQL, а тот отправляет трафик по двум маршрутам: в боевые базы данных, чтобы приложение функционировало, и в тестовую среду для проверки новых фич под нагрузкой.

Особенность ProxySQL в том, что есть его конфиг, который в нашем случае выкатывается через puppet (для puppet есть модуль ProxySQL), но еще есть понятие зоны runtime, когда для того, чтобы внести изменение (добавить сервер, добавить пользователя, удалить сервер и пользователя), не нужен привычный рестарт/релоад., Все делается через консоль ProxySQL, например так.
mysql -ulogin -ppassword -h 127.0.0.1 -P6032 -e «INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('sm_username','pass',1);;LOAD MYSQL USERS TO RUNTIME;SAVE MYSQL USERS TO DISK;»
Более подробно конено же в официальной документации github.com/sysown/proxysql/wiki/Users-configuration

Спасибо за внимание.

Наш конфиг, которым мы решили описанную выше задачу смотрите ниже.

Наш конфиг

datadir="/var/lib/proxysql" admin_variables={ admin_credentials="user:pass" mysql_ifaces="0.0.0.0:6032" refresh_interval=2000 web_enabled=true web_port=6080 stats_credentials="stats:admin"} mysql_variables ={ threads = 1000 max_connections = 2000 default_query_delay= 0 default_query_timeout=1 have_compress=true poll_timeout=2000 interfaces="0.0.0.0:6033;/tmp/proxysql.sock" default_schema="information_schema" stacksize=1048576 server_version="5.7.22" connect_timeout_server=10000 monitor_history=60000 monitor_connect_interval=200000 monitor_ping_interval=200000 ping_interval_server_msec=5000 ping_timeout_server=200 commands_stats=true sessions_sort=true monitor_username="root" monitor_password="password" monitor_galera_healthcheck_interval=200 monitor_galera_healthcheck_timeout=80} mysql_servers =( { address = "ip_real_mysql_server", port = 3306, max_connections = 10000, host_group = 1, })mysql_users =( { username = "user", password = "pass", default_hostgroup = 1, transaction_persistent = 0, active = 1, })
Показать больше

Похожие публикации

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»