一些在 k8s 上部署 Proxysql 集群时的的配置记录,
一些在使用 ProxySQL 时遇到的问题,及解决办法。
一、StatefulSet 集群部署
1. ProxySQL 部署方式一些说明
ProxySQL 很轻量,作为应用的数据库连接代理,最好放置在客户端应用就近点部署。例如可以和应用在同一个 kubernetes 集群中,又或者针对单独应用当作 sidecar 和应用放在同一个 POD 内。
2. ProxySQL 配置文件一些基础
主要是下面 4 块配置
mysql_query_rules
配置匹配 SQL 语句规则,按照优先级顺序匹配到规则后转发到指定 MySQL 服务器组
路由概述可以参考:https://www.cnblogs.com/f-ck-need-u/p/9300829.html
mysql_servers
配置可用的 MySQL 服务器组
mysql_users
配置可用的 MySQL 用户,需要连接的数据库账号都要添加在这里
proxysql_servers
配置 ProxySQL 集群中实例信息
官方wiki参考:https://github.com/sysown/proxysql/wiki/ProxySQL-Cluster#preface
使用 Configmap 存放配置文件
ProxySQL 通常通过登陆管理接口使用 SQL 语句热更新来进行配置,使用配置文件只用来完成初始化。在 Kubernetes 中使用 configmap 好处是可以集中修改持久化的配置文件,缺点是不能在 proxysql 中热更新后再 load 配置到 disk 持久化。
生成并创建 configmap
配置文件命令参考:
1
2
| kubectl create configmap proxysql-cnf --from-file=proxysql.cnf --dry-run -o yaml > proxysql.cnf.yaml
kubectl apply -f proxysql.cnf.yaml
|
修改配置可以使用:
1
| kubectl edit cm proxysql-cnf
|
初始化配置文件参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
| # filename:proxysql.cnf
datadir="/var/lib/proxysql"
admin_variables=
{
# 配置管理账号,即 6032 端口登陆的管理员账号密码。
# 默认账号 admin 无法远程登陆,不适用于容器环境
admin_credentials="proxysql-admin:adminpassword;cluster1:clusterpassword1"
mysql_ifaces="0.0.0.0:6032"
refresh_interval=2000
cluster_username="cluster1"
cluster_password="clusterpassword1"
cluster_check_interval_ms=200
cluster_check_status_frequency=100
cluster_mysql_query_rules_save_to_disk=true
cluster_mysql_servers_save_to_disk=true
cluster_mysql_users_save_to_disk=true
cluster_proxysql_servers_save_to_disk=true
cluster_mysql_query_rules_diffs_before_sync=3
cluster_mysql_servers_diffs_before_sync=3
cluster_mysql_users_diffs_before_sync=3
cluster_proxysql_servers_diffs_before_sync=3
}
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
# 实际发现 mysql-default_charset 配置没有生效
mysql-default_charset="utf8mb4"
mysql-set_query_lock_on_hostgroup=0
ping_interval_server_msec=10000
ping_timeout_server=200
commands_stats=true
sessions_sort=true
# 需要高权限账号,近似于 root
monitor_username="proxysql_monitor"
monitor_password="proxysql_monitor"
monitor_galera_healthcheck_interval=2000
monitor_galera_healthcheck_timeout=800
}
mysql_replication_hostgroups =
(
{
writer_hostgroup=10
reader_hostgroup=20
offline_hostgroup=9999
max_writers=1
writer_is_also_reader=1
max_transactions_behind=30
active=1
}
)
mysql_servers =
(
{ address="172.17.0.12" , port=3306 , hostgroup=10, max_connections=500 },
# 读库可以分配权重,测试没生效,建议通过管理接口手动配置
{ address="172.17.0.12" , port=3306 , hostgroup=20, max_connections=500, weight=0 },
{ address="172.17.0.130" , port=3306 , hostgroup=20, max_connections=500, weight=70 }
)
mysql_query_rules =
(
{
rule_id=10
active=1
match_digest="^SELECT.*FOR UPDATE$"
destination_hostgroup=10
apply=1
},
{
rule_id=20
active=1
match_digest="^SELECT"
destination_hostgroup=20
apply=1
},
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_users =
(
{ username = "user1", password = "password1", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
{ username = "user2", password = "password2", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)
proxysql_servers =
(
{ hostname = "proxysql-0.proxysqlcluster", port = 6032, weight = 1 },
{ hostname = "proxysql-1.proxysqlcluster", port = 6032, weight = 1 }
)
|
部署之前准备
根据实际配置文件中内容修改下面命令或配置文件
- 由于配置文件中需要指定的 monitor 账号,需要提前在 MySQL 内准备好,并添加
USAGE
权限。
1
| GRANT USAGE ON *.* TO 'proxysql_monitor'@'%';
|
配置文件中 proxysql_servers
里面的 hostname
指定的 proxysql-0.proxysqlcluster
需要提前创建无头服务,方便配置文件初始化时直接解析自己
声明 headless svc 文件配置参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # filename: proxysql-admin-svc-headless.yml
apiVersion: v1
kind: Service
metadata:
labels:
app: proxysql
name: proxysqlcluster
spec:
clusterIP: None # 指明为无头服务,使解析直接返回 POD 的 IP 地址
ports:
- name: proxysql-admin
port: 6032
protocol: TCP
targetPort: 6032
selector:
app: proxysql # 绑定接下来创建的服务
sessionAffinity: None
type: ClusterIP
|
部署 workload 类型为 StatefulSet 的 Proxysql 集群
StatefulSet 声明文件参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| # filename: proxysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: proxysql
labels:
app: proxysql
spec:
replicas: 2
serviceName: proxysqlcluster
selector:
matchLabels:
app: proxysql
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: proxysql
spec:
restartPolicy: Always
containers:
- image: proxysql/proxysql:2.0.8
name: proxysql
volumeMounts:
- name: proxysql-cnf
mountPath: /etc/proxysql.cnf
subPath: proxysql.cnf
ports:
- containerPort: 6033
name: proxysql-mysql
- containerPort: 6032
name: proxysql-admin
volumes:
- name: proxysql-cnf
configMap:
name: proxysql-cnf
---
# filename: proxysql-svc-nodeport.yaml
# 根据需求是否创建 nodeport
apiVersion: v1
kind: Service
metadata:
annotations:
labels:
app: proxysql
name: proxysql
spec:
ports:
- name: proxysql-mysql
port: 6033
protocol: TCP
targetPort: 6033
nodePort: 6033
- name: proxysql-admin
nodePort: 6032
port: 6032
protocol: TCP
targetPort: 6032
selector:
app: proxysql
type: NodePort
|
apply 上面文件完成部署。
验证启动状态
二、 添加 Prometheus 监控支持
使用 proxysql-export 查询 PorySQL 状态暴露指标给 prometheus 。
创建 Deployment,声明文件参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: proxysql-exporter
spec:
replicas: 1
selector:
matchLabels:
name: proxysql-exporter
template:
metadata:
labels:
name: proxysql-exporter
app: proxysql-exporter
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "42004"
prometheus.io/scrape: "true"
spec:
containers:
- name: proxysql-exporter
image: epurs/proxysql_exporter
imagePullPolicy: IfNotPresent
ports:
- containerPort: 42004
env:
- name: DATA_SOURCE_NAME
value: "proxysql-admin:adminpassword@tcp(proxysql.default:6032)/"
# args:
# - -web.listen-address=:42004
|
Grafana dashboard 可以使用
三、ProxySQL 常见问题
1. 添加用户
需要增加新用户访问时,登陆 6032 管理接口,参考如下命令查看添加:
1
2
3
4
5
6
7
8
9
10
| -- 查看当前用户
select * from mysql_users -- 内存数据库中配置
select * from runtime_mysql_users -- 当前运行时中生效的配置,同 MySQL 密码为 * 开头的 hash 结果
-- 添加新用户
insert into mysql_users(username,password,default_hostgroup) values('sqlsender','P@ssword1!',10) -- 此时密码为明文
-- 加载配置
load mysql users to runtime -- 此时已生效
save mysql users to memory; -- 可选:将 hash 密码加载到内存数据库中
-- 验证
select * from mysql_users
|
参考:mysql_users表中用户的密码管理
2. 添加/修改 backend 数据库
需要增加新数据库实例到数据库组时,登陆 6032 管理接口,参考如下命令查看和添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| -- 查看当前后端情况 select * from mysql_servers\G
select hostgroup_id,hostname,port,status,weight from mysql_servers;
--
-- 需要平滑下掉某个节点,可以将状态改为 OFFLINE_SOFT,该后端将不再有新链接建立,但是旧链接不会主动释放。效果和把 weight 设置为 0 相同。
-- 如果需要立即停掉所有链接,可以 DELETE 实例条目,或者修改状态为 OFFLINE_HARD
UPDATE mysql_servers SET status='OFFLINE_SOFT' WHERE hostname='172.17.0.1'
--
-- 添加后端 MySQL 节点(简化版本)
insert into mysql_servers(hostgroup_id,hostname,port)
values(10,'172.17.0.0',3306)
-- 添加后端 MySQL 节点(完整版本)
NSERT INTO mysql_servers(hostgroup_id,hostname,port,status,weight,compression,max_connections) VALUES ('10','172.17.0.0','3306','ONLINE','10','0','500');
--
-- 加载配置
load mysql servers to runtime;
-- 验证
select * from mysql_servers\G
|
3. 读写分离配置
比较通用的读写分离规则,rule_id
值越小优先级越高,先匹配到会直接按照规则执行 :
1
2
3
4
| INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply)
VALUES
(10,1,'^SELECT.*FOR UPDATE$',10,1),
(20,1,'^SELECT',20,1);
|
改配置官方认为只能作为例子使用,详细创建及优化流程参考官方 wiki 说明,https://github.com/sysown/proxysql/wiki/ProxySQL-Read-Write-Split-(HOWTO)
4. utf8mb4 字符集问题
使用中遇到了配置文件中指定数据库变量 mysql-default_charset="utf8mb4"
不生效的问题,需要部署完集群后,执行:
1
2
3
4
| SET mysql-default_charset='utf8mb4';
LOAD MYSQL VARIABLES TO RUNTIME;
-- SAVE MYSQL VARIABLES TO DISK;
select * from global_variables ;
|
5. 查看读写分离路由统计
1
2
| select * from stats_mysql_query_rules;
select hostgroup,schemaname,username,digest_text from stats_mysql_query_digest;
|
6. SQL 查询遇到报错 ProxySQL Error: connection is locked to hostgroup 100 but trying to reach hostgroup 200
修改配置
1
| set mysql-set_query_lock_on_hostgroup=0;
|
解释如下:
Possible values for mysql-set_query_lock_on_hostgroup
:
- 0 : legacy behavior , before 2.0.6
- 1 : (default) . SET statements that cannot be parsed correctly disable
both multiplexing AND routing. Attempting to route traffic while a
connection is linked to a specific backend connection will trigger
an error to be returned to the client
Issue 参考:
https://github.com/sysown/proxysql/pull/2156
https://github.com/sysown/proxysql/issues/2234
Reference
部署参考:
https://severalnines.com/database-blog/proxysql-native-clustering-kubernetes
配置详解参考:
https://www.cnblogs.com/f-ck-need-u/p/7586194.html#auto_id_4
github 地址:
https://github.com/sysown/proxysql