前些天我介绍了如何通过 Twemproxy 实现 Redis 连接池, 进而提升 PHP/Redis 的性能. 今天我要介绍一下 ProxySQL http://www.proxysql.com/ , 通过它可以实现 MySQL 连接池, 进而提升 PHP/MySQL 的性能, 实际上原理是差不多的, 本来没必要再写一篇文章赘述, 不过我在配置使用 ProxySQL 的过程中, 遇到了一些小问题, 感觉还是应该记录一下.
关于安装过程, 官方 Wiki https://github.com/sysown/proxysql/wiki 里有详细描述. 主要看配置文件 /etc/proxysql.cnf :
- datadir="/var/lib/proxysql"
- admin_variables=
- {
- admin_credentials="admin:admin"
- mysql_ifaces="0.0.0.0:6032"
- }
- mysql_variables=
- {
- threads=4
- max_connections=2048
- default_query_delay=0
- default_query_timeout=36000000
- have_compress=true
- poll_timeout=2000
- interfaces="/var/run/proxysql.sock"
- default_schema="information_schema"
- stacksize=1048576
- server_version="5.5.30"
- connect_timeout_server=3000
- monitor_username="monitor"
- monitor_password="monitor"
- monitor_history=600000
- monitor_connect_interval=60000
- monitor_ping_interval=10000
- monitor_read_only_interval=1500
- monitor_read_only_timeout=500
- ping_interval_server_msec=120000
- ping_timeout_server=500
- commands_stats=true
- sessions_sort=true
- connect_retries_on_failure=10
- }
- mysql_servers =
- (
- {
- address="..."
- port=3306
- }
- )
- mysql_users:
- (
- {
- username = "..."
- password = "..."
- }
- )
最应该注意的是: ProxySQL 使用 SQLite 来保存配置信息, 配置文件只在第一次启动的时候有效, 后续都是从 SQLite 获取配置. 如果你想强制使用配置文件, 需要使用 https://github.com/sysown/proxysql/wiki#reinitializing-proxysql-from-the-config-file-after-first-startup-the-db-file-is-used-instead-of-the-config-file 命令. 更多信息可以参考: ProxySQL 之安装及配置详解 http://seanlook.com/2017/04/10/mysql-proxysql-install-config/ .
首先, 注意 admin_variables 里的 admin_credentials, 缺省值是admin:admin, 表示缺省用户名和密码都是 admin, 还有 mysql_ifaces, 其缺省值是0.0.0.0:6032, 表示监听所有网络接口的 6032 端口, 设想你有一个外网能访问的网络接口, 那么恶意用户将能使用缺省的用户名密码进入到你的 admin 系统, 所以不要用缺省的用户名和密码, 也不要缺省监听外网接口, 切记! 切记! 切记!
其次, 注意 mysql_variables 里的 interfaces, 因为 PHP 要通过本地的 Unix Domain Socket 来请求 ProxySQL 的连接池, 所以 interfaces 不要使用 ip:port 的形式, 而是设置成本地 Unix Domain Socket 的形式, 本例中设置为 /var/run/proxysql.sock, 需要提醒的是很多人喜欢把 Socket 文件放到 /tmp 路径下, 这不是一个好习惯, 毕竟 /tmp 从名字上看就不像是一个良家妇女, 大家都想弄两下, 搞不好谁 rm 了一下就糟了.
最后, 注意 mysql_variables 里的 monitor_username 和 monitor_password, 它设置了监控用户的相关信息, 以便 ProxySQL 随时掌握后端 MySQL 服务器的状态, 一定要记得提前在后端 MySQL 服务器上创建相应的帐号, 我一开始就没创建监控帐号, 结果 ProxySQL 运行一段时间就没响应了, 这是因为当 ProxySQL 不断用配置里的监控帐号和密码尝试去访问后端服务器的时候, 会生成很多Access denied for user 'monitor'@'...'的错误, 当达到一定阈值, 就会导致Host '...' is blocked because of many connection errors, 此时 ProxySQL 就无法响应请求了, 必须在 MySQL 上mysqladmin flush-hosts才行. 相关的日志信息可以在SELECT * FROM monitor.mysql_server_ping_log里查看到.
下面让我们压测看看性能怎么样, 测试脚本 test.php 如下:
- <?php
- $host = '...';
- $user = '...';
- $password = '...';
- $database = '...';
- $charset = 'utf8mb4';
- $socket = '/var/run/proxysql.sock';
- $dsn = "mysql:dbname={$database};charset={$charset}";
- if (empty($_GET['proxysql'])) {
- $dsn .= ";host={$host}";
- } else {
- $dsn .= ';unix_socket={$socket}';
- }
- $dbh = new PDO($dsn, $user, $password);
- $sql = 'SELECT * FROM foo LIMIT 10';
- $value = $dbh->query($sql);
- foreach ($value as $v) {
- var_dump($v);
- }
- ?>
通过 ab 模拟一个高并发的场景, 压测看看性能有没有提升:
- shell> ab -k -n 10000 -c 100 "http://path/test.php?proxysql=0"
- shell> ab -k -n 10000 -c 100 "http://path/test.php?proxysql=1"
最终, 我在一台一般配置的服务器上, 不通过 ProxySQL 得到了大约 1500 的 RPS, 通过 ProxySQL 得到了大约 2000 的 RPS, 也就是说, ProxySQL 带来了 25% 的性能提升.
有兴趣的推荐继续阅读: Utilizing ProxySQL for Connection Pooling in PHP https://www.percona.com/live/e17/sessions/utilizing-proxysql-for-connection-pooling-in-php , 还有: ProxySQL 之连接复用 (multiplexing) 以及相关问题说明 http://seanlook.com/2017/04/17/mysql-proxysql-multiplexing/ .
来源: http://www.tuicool.com/articles/yyYJVrj