ProxySQL快速上手

安装并登陆管理界面

1 wgethttps://github.com/sysown/proxysql/releases/download/v1.3.6/proxysql-1.3.6-1-centos67.x86_64.rpm

2 yum install perl-DBD-MySQL

3 rpm -ivh proxysql-1.3.6-1-centos67.x86_64.rpm

4 service proxysql start

5 proxysql --version

ProxySQL version 1.3.6-0-g434b376, codename Truls

6 登陆管理界面(配置信息从启动进程的配置文件查看)

mysql -u admin -padmin -h127.0.0.1 -P6032--prompt='proxysql>'

mysql -u admin -padmin -S /tmp/proxysql_admin.sock--prompt='proxysql>'

配置读写分离和路由规则

环境(三个后台服务器,一主两从的架构)

Master 10.9.160.248:3306

Slave1  10.9.117.107:3306  设置read_only

Slave2    10.9.150.86:3306    设置read_only

 
在db的主节点上创建proxy的监控账户和业务账户

GRANT ALLPRIVILEGES ON *.* TO 'monitor'@'%' IDENTIFIED BY ‘monitor’;

GRANT ALLPRIVILEGES ON *.* TO 'msandbox'@'%' IDENTIFIED BY ‘msandbox’;

在proxy管理命令行添加后端服务器列表

proxysql>INSERTINTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'10.9.160.248',3306);

proxysql>INSERTINTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'10.9.150.86',3306);

proxysql>INSERTINTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'10.9.117.107',3306);

注意到这时的hostgroup都为1,这没什么问题

即使生效

LOAD MYSQL SERVERS TO RUNTIME;

 
配置和注册监控账户

UPDATE global_variablesSET variable_value='monitor'WHERE variable_name='mysql-monitor_username';

UPDATE global_variables SET variable_value='monitor'WHERE variable_name='mysql-monitor_password';

这里填的账户和密码均为monitor的信息就是步骤1中在后端服务器创建的监控账户

即使生效,并持久化到磁盘

LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
查看监控是否生效
proxysql>SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 10;
+--------------+------+------------------+-------------------------+---------------+
| hostname     | port | time_start_us    | connect_success_time_us | connect_error |
+--------------+------+------------------+-------------------------+---------------+
| 10.9.160.248 | 3306 | 1497001266520778 | 688                     | NULL          |
| 10.9.150.86  | 3306 | 1497001266510692 | 541                     | NULL          |
| 10.9.117.107 | 3306 | 1497001266500632 | 718                     | NULL          |
| 10.9.160.248 | 3306 | 1497001206520719 | 652                     | NULL          |
| 10.9.150.86  | 3306 | 1497001206510580 | 618                     | NULL          |
| 10.9.117.107 | 3306 | 1497001206500519 | 744                     | NULL          |
| 10.9.160.248 | 3306 | 1497001146520616 | 699                     | NULL          |
| 10.9.150.86  | 3306 | 1497001146510561 | 557                     | NULL          |
| 10.9.117.107 | 3306 | 1497001146500487 | 759                     | NULL          |
| 10.9.160.248 | 3306 | 1497001086520458 | 595                     | NULL          |
+--------------+------+------------------+-------------------------+---------------+
10 rows in set (0.00 sec)
proxysql>SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start_us DESC LIMIT 10;
+--------------+------+------------------+----------------------+------------+
| hostname     | port | time_start_us    | ping_success_time_us | ping_error |
+--------------+------+------------------+----------------------+------------+
| 10.9.160.248 | 3306 | 1497001317166006 | 181                  | NULL       |
| 10.9.150.86  | 3306 | 1497001317164253 | 153                  | NULL       |
| 10.9.117.107 | 3306 | 1497001317162511 | 262                  | NULL       |
| 10.9.160.248 | 3306 | 1497001307165766 | 218                  | NULL       |
| 10.9.150.86  | 3306 | 1497001307163997 | 137                  | NULL       |
| 10.9.117.107 | 3306 | 1497001307162247 | 289                  | NULL       |
| 10.9.160.248 | 3306 | 1497001297165761 | 213                  | NULL       |
| 10.9.150.86  | 3306 | 1497001297163999 | 175                  | NULL       |
| 10.9.117.107 | 3306 | 1497001297162241 | 280                  | NULL       |
| 10.9.160.248 | 3306 | 1497001287165645 | 183                  | NULL       |
+--------------+------+------------------+----------------------+------------+
10 rows in set (0.00 sec)
 

 

配置主从信息

表示该复制组,1为写入组的编号,2为读取组的编号
INSERT INTO mysql_replication_hostgroups VALUES (1,2,’ one-master-2-slave’);
即时生效
LOAD MYSQL SERVERS TO RUNTIME;    
当生效后,proxysql会去检测后端的数据节点
假设该节点read_only1,则会将该server移入group 2
假设该节点read_only0,则会将该server移入group 1
这时再查mysql_servers表,就会发现节点的hostgroup_id根据read_only的情况自动变化了
proxysql>select hostgroup_id,hostname from mysql_servers;
+--------------+--------------+
| hostgroup_id | hostname     |
+--------------+--------------+
| 1            | 10.9.160.248 |
| 2            | 10.9.117.107 |
| 2            | 10.9.150.86  |
+--------------+--------------+
3 rows in set (0.00 sec)
确认无误后  持久化到磁盘
SAVE MYSQL SERVERS TO DISK;
 

 

配置和注册业务账户

插入步骤1中生成的业务账户
INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('msandbox','msandbox',1);
proxysql>select * from mysql_users\G
*************************** 1. row ***************************
              username: msandbox
              password: msandbox
                active: 1
               use_ssl: 0
     default_hostgroup: 1
        default_schema: NULL
         schema_locked: 0
transaction_persistent: 0
          fast_forward: 0
               backend: 1
              frontend: 1
       max_connections: 10000
1 row in set (0.00 sec)
proxysql>update mysql_users set transaction_persistent=1 where username='msandbox';
Query OK, 1 row affected (0.00 sec)
即时生效,持久化
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
 
 
说明几个比较重要的列名含义
Active:表示该用户是否生效
default_hostgroup :表示如果没有配置其他路由规则,那么默认走的就是该值指定的hostgroup
max_connections:该用户能创建的最大连接数
transaction_persistent :如果为1,则一个完整的SQL只可能路由到一个节点;这点非常重要,主要解决这种情况:一个事务有混合的读操作和写操作组成,事务未提交前,如果事务中的读操作和写操作路由到不同节点,那么读取到的结果必然是脏数据。所以一般情况下,该值应该设置为1,尤其是业务中使用到事务机制的情况(默认为0
PS:该值设为1后,sysbench不好测试读写分离的情况,因为sysbench中的oltp脚本中的SQL都是包含在一个个事务中的,所以测试阶段可以将其值改为0
frontend backend列目前的版本必须为1,因为目前的proxy和底层的节点共用一套账户认证体系,后续可能会单独分离出来,所以增加了这两个字段。
 
这时验证下账户登陆,确定登陆上去的就是预想中的主库
[root@10-9-192-94 ~]# mysql -u msandbox -pmsandbox -h 127.0.0.1 -P6033 -e "show slave hosts"
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
| 168392043 |      | 3306 | 168403192 | baaf5e8b-4cbe-11e7-8ca2-e8611f12fd90 |
| 168400470 |      | 3306 | 168403192 | aed780a0-4cbe-11e7-8ca2-6c92bf15bed0 |
 

配置读写分离策略

1 除了select ..for update以为的select都路由到从库

2 其他所有操作都路由到主库

proxysql>showcreate table mysql_query_rules\G

***************************1. row ***************************

       table: mysql_query_rules

Create Table:CREATE TABLE mysql_query_rules (

    rule_id INTEGER PRIMARY KEY AUTOINCREMENTNOT NULL,

    active INT CHECK (active IN (0,1)) NOT NULLDEFAULT 0,

    username VARCHAR,

    schemaname VARCHAR,

    flagIN INT NOT NULL DEFAULT 0,

    client_addr VARCHAR,

    proxy_addr VARCHAR,

    proxy_port INT,

    digest VARCHAR,

    match_digest VARCHAR,

    match_pattern VARCHAR,

    negate_match_pattern INT CHECK(negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0,

    flagOUT INT,

    replace_pattern VARCHAR,

    destination_hostgroup INT DEFAULT NULL,

    cache_ttl INT CHECK(cache_ttl > 0),

    reconnect INT CHECK (reconnect IN (0,1))DEFAULT NULL,

    timeout INT UNSIGNED,

    retries INT CHECK (retries>=0 ANDretries <=1000),

    delay INT UNSIGNED,

    mirror_flagOUT INT UNSIGNED,

    mirror_hostgroup INT UNSIGNED,

    error_msg VARCHAR,

    log INT CHECK (log IN (0,1)),

    apply INT CHECK(apply IN (0,1)) NOT NULLDEFAULT 0,

    comment VARCHAR)

1 row in set(0.00 sec)

Active:是否启用这个路由规则

Username:如果不为空,该规则匹配该用户

schemaname :如果不为空,该规则只匹配该库名称

 

destination_hostgroup:该路由规则发往哪个组

apply:1表示该正则匹配后,将不再接受其他匹配,直接转发

match_digest:描述规则的正则表达式,其中1.4版本以后,正则表达式支持PCRE和RE2两种,默认使用pcre,即perl语言支持的正则表达式

cache_ttl:用户查询缓存的时间阈值,单位为毫秒

更多字段说明,参考官方wiki文档

https://github.com/sysown/proxysql/wiki/MySQL-Query-Rules

通过查看该表的表结构,不难看出所有的路由规则是用户完全自定义的,也就是说不仅仅可以实现读写分离,任何SQL类型都可以自定义发送到指定的数据节点执行,比如在实现大部分读写分离的同时,一些对实时性要求很高的SQL,可以定义成发送到master节点运行;

Insert into mysql_query_rules(rule_id,active,username,match_digest, destination_hostgroup,apply) values(10,1,’ msandbox’,’ ^SELECT.*FORUPDATE$’,1,1);

Insert into mysql_query_rules(rule_id,active,username,match_digest, destination_hostgroup,apply) values(11,1,’ msandbox’,’ ^SELECT’,2,1);

刚才通过mysql_users表的配置和解释可知,路由规则以外的SQL都发往mysql_users表中的default_hostgroup字段,即数值1,该组为master节点;

即时生效并持久化
load mysql query rules to runtime;
save mysql query rules todisk;

 

读写分离测试

清空历史查询记录

proxysql>select* from stats.stats_mysql_query_digest_reset limit 1;

通过查询stats_mysql_query_digest_reset的效果是这样的:返回stats_mysql_query_digest表的查询结果,并且执行truncate table stats_mysql_query_digest清空stats_mysql_query_digest表

proxysql>select* from stats.stats_mysql_query_digest;

Empty set (0.00sec)

修改transaction_persistent为0,使得sysbench适用该场景

update mysql_users set transaction_persistent=0 where username='msandbox';
LOAD MYSQL USERS TO RUNTIME;

 

sysbench压测proxy

sysbench--report-interval=1 --num-threads=4 --max-time=2000 --test=sysbench/tests/db/oltp.lua--mysql-user='msandbox' --mysql-password='msandbox' --oltp-table-size=10000--mysql-host=127.0.0.1 --mysql-port=6033 --mysql-db=proxytest  --max-requests=100000000 prepare

sysbench--report-interval=1 --num-threads=4 --max-time=2000 --test=sysbench/tests/db/oltp.lua--mysql-user='msandbox' --mysql-password='msandbox' --oltp-table-size=10000--mysql-host=127.0.0.1 --mysql-port=6033 --mysql-db=proxytest  --max-requests=100000000 run

压测过程中观察读写分离情况


可以看到查询都是发往group 2,写操作都是发往group 1,即实现了读写分离

另外可以分别登陆三个数据节点show  processlist确定proxysql真实实现了读写分离;

关于select ..for update和事务的路由测试,可以手工写几条特定的SQL测试,这里忽略;

测试proxysql的查询缓存

Proxysql的查询缓存和mysql的查询缓存有点类似,但不是一回事;proxysql的查询缓存指的是:如果在指定时间大小范围内发送的SQL一摸一样,那么直接返回结果集,而返回的结果集可能并不是准确的查询结果,所以需要设置合适的时间范围,既能提升性能,又得满足业务需求,即查询结果足够的“新”。这个特性我想可以用于这个方便:针对一些查询频率很高但结果并不需要太精确的业务,可以单独给这些SQL配置查询缓存

proxysql>update mysql_query_rules setcache_ttl=2000 where rule_id=11\G

Query OK, 1 row affected (0.00 sec)

proxysql>LOAD MYSQL QUERY RULES TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)         

sysbench --report-interval=1--num-threads=4  --max-time=2000--test=sysbench/tests/db/oltp.lua --mysql-user='msandbox'--mysql-password='msandbox' --oltp-table-size=10000 --mysql-host=127.0.0.1--mysql-port=6033 --mysql-db=proxytest --max-requests=100000000 run



可以看到host部分为-1,表示这些查询是使用了proxy查询缓存的,耗时为0,这里的0不可能是真的没有耗时,只是不好统计,显示上直接显示成0

测试查询重写

范例   将带distinct的SQL去掉排序      

9.1 写入下面这条改写规则,注意规则中大小写是敏感的

proxysql>select * frommysql_query_rules\G

*************************** 1. row***************************

              rule_id: 31

               active: 1 

            username: msandbox

          schemaname: NULL

               flagIN: 0

         client_addr: NULL

          proxy_addr: NULL

          proxy_port: NULL

               digest: NULL

        match_digest: NULL

        match_pattern: DISTINCT(.*)ORDER BY c

 negate_match_pattern: 0

              flagOUT: NULL

     replace_pattern: DISTINCT\1

destination_hostgroup: NULL

           cache_ttl: NULL

           reconnect: NULL

              timeout: NULL

              retries: NULL

                delay: NULL

      mirror_flagOUT: NULL

    mirror_hostgroup: NULL

           error_msg: NULL

                  log: NULL

                apply: 1

              comment: NULL

1 row in set (0.00 sec)

9.2 执行下面这个SQL


可以看到解析计划中没有using filesort,SQL已经被改写了

9.3 执行一把SQL内容,查看规则命中情况和执行列表确认

proxysql>select * fromstats_mysql_query_rules ;

+---------+------+

| rule_id | hits |

+---------+------+

| 31     | 1    |

+---------+------+

1 row in set (0.00 sec)

proxysql>select hostgroup,digest_textfrom stats.stats_mysql_query_digest;

+-----------+--------------------------------------------------------------------+

| hostgroup | digest_text                                                       |

+-----------+--------------------------------------------------------------------+

| 1        | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? and ? order by c |

+-----------+--------------------------------------------------------------------+

1 row in set (0.00 sec)

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章