您好,我叫Alexander Yakovlev,我在Citimobil工作并运营。今天,我将向您介绍一个非常有趣的ProxySQL产品-它是一种高性能的MySQL Proxy,可以完成很多事情-通过掩码捕获和杀死请求,借助它您可以搜索sql注入,复制负载等等。我将谈论我们与他的经历。迟来的情况是,任何大型IT项目(其开发都是从一对服务器开始的)都面临着以下情况。想象一下,该项目最初只有一个数据库-主服务器。逐渐地,一群奴隶被加入其中。然后他们引入了分片。一天,负载突然增加了十倍。例如,因为您的主要竞争对手已经倒下,而客户却赶到了您。此时,您似乎可以通过添加Web服务器来简单地扩展负载。但是完成此操作后,就会出现不愉快的情况。考虑一个向导的示例。假设您有50个Web服务器,每200个php-fpm进程。然后,将有50 * 200个连接到达主服务器,然后以50 * 200 /个从服务器到达每个从服务器(当然,如果在roproxy中配置了roundrobin)-参见下图。当然,到主服务器的一万个连接是很多,但仍然可以承受,如果有200个网站,则连接的数量将更多,一个连接=一个线程。我们遇到了这个瓶颈。
然后我们开始争论:与向导的连接始终安装在代码中,但是所有fpm进程是否都必须这样做?可能不是。我们注意到,与主服务器的大量持久连接只是简单地挂起。他们决定我们需要解复用。
为此,我们提请注意一种名为ProxySQL的产品。它像普通的反向代理一样工作:建立连接,并根据配置中指定的某些规则重新分配流量。我们在所有Web服务器上安装了ProxySQL,并在应用程序配置中指定对主数据库的调用在地址127.0.0.1处进行。如果以前每台Web服务器上的200名FPM工作人员意味着从这台机器到主数据库的200条连接,那么情况已经改变了。这200个连接来自ProxySQL,而50-70个连接则在不同时间断开。也就是说,ProxySQL可以重用现有的连接。由于多路分解,我们在所有主机上将连接数减少了3-10倍,请参阅下面其中一个主机的当前连接图。
多亏了ProxySQL,我们摆脱了上述瓶颈。但这不是我们使用此工具改进的唯一工作流程。我们还没有完成第二个过程,但是非常接近完成。我们计划使用ProxySQL在测试环境中复制实际负载。这是检查战斗流量的新功能所必需的。如何实施?该应用程序转到ProxySQL,并通过两条路径发送流量:进入战斗数据库以使该应用程序正常运行,以及到达测试环境以检查负载下的新功能。ProxySQL的功能是有它的配置,在我们的案例中是通过puppet推出的(对于puppet,有一个ProxySQL模块),但是还有运行时区域的概念,以便进行更改(添加服务器,添加用户,删除服务器和用户) ),则不需要通常的重新启动/重新加载。一切都通过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;"
当然,更详细地,在官方文档proxysql.com/documentation中。感谢您的关注。解决上述问题的配置,请参见下文。我们的配置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,
})