当前位置: 首页 > news >正文

mysql读写分离与proxysql的结合

上一篇文章介绍了mysql如何设置成主从复制模式,而主从复制的目的,是为了读写分离。

读写分离,拿spring boot项目来说,可以有2种方式:
1)设置2个数据源,读和写分开使用
2)使用中间件,如proxysql。它会根据sql语句自动匹配到主、从库

方式一好处是灵活,可控,缺点是需要自己写一点代码,已有的项目修改可能比较大;proxysql的话,还是跟之前一样,只有一个数据源,代码好像也不用改。问题是,我用了一下,感觉有一些坑。也许是还不懂得怎么使用的缘故。

以下是步骤和一些坑:

一、安装proxysql

proxysql是一个中间件,需要安装。安装好了之后,可以把它看作一个mysql,因为它是一个伪装成mysql的中介。你看看,这个”“mysql数据源”:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.10.249:6033/testdb?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong&allowPublicKeyRetrieval=true
    username: work
    password: 123456 # 你的数据库密码

其中 192.168.10.249:6033 就是proxysql的地址。简直了。

1、安装

还是跑在docker里。拉取 ProxySQL Docker 镜像

sudo docker pull proxysql/proxysql

目前由于不可描述的原因,各种镜像源大都不可用,令人无语。费了九牛二虎之力,才下载到一个镜像。中国程序员真难啊。方法可参考拙作:修改centos7的dns解决docker拉取镜像超时问题

2、在mysql主库中创建监控用户

sudo docker exec -it mysql-1 /bin/bash

mysql -uroot -pdata2025

--监控账号与默认保持一致最保险(monitor/monitor)
create user 'monitor' identified WITH mysql_native_password by 'monitor';

-- 授予监控用户必要的权限
GRANT USAGE ON *.* TO monitor@'%';

-- 刷新权限
FLUSH PRIVILEGES;

3、准备配置文件

mkdir /home/admin/proxysql

然后在该文件夹下创建配置文件:proxysql.cnf

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 = "0.0.0.0:6033"
    default_schema = "information_schema"
    stacksize = 1048576
    server_version = "8.0.23"

    monitor_history=60000
    monitor_connect_interval=200000
    monitor_ping_interval=200000
}

mysql_servers = (
    { address = "mysql-1", port = 3306, hostgroup = 0,weight=1, max_connections = 1000 },
    { address = "mysql-2", port = 3306, hostgroup = 1, weight=1,max_connections = 1000 }
)

mysql_users = (
    { username = "work", password = "123456", default_hostgroup = 0, active = 1 }
)

mysql_query_rules = (
    { rule_id = 1, active = 1, match_digest = "^SELECT.*", destination_hostgroup = 1, apply = 1 },
    { rule_id = 2, active = 1, match_digest = "^(INSERT|UPDATE|DELETE|REPLACE).*", destination_hostgroup = 0, apply = 1 }
)

4、创建 docker 容器

跟mysql的主库、从库共用一个docker网络:mysql-tier。详见上一篇《设置mysql的主从复制模式》

sudo docker run -d \
  --name proxysql \
  --network mysql-tier \
  -p 6032:6032 \
  -p 6033:6033 \
  -v /home/admin/proxysql/proxysql.cnf:/etc/proxysql.cnf \
  -v /home/admin/proxysql/data:/var/lib/proxysql \
  proxysql/proxysql \
  proxysql --initial -f -c /etc/proxysql.cnf

5、操作连接

在这里插入图片描述
在这里插入图片描述
可读可写,very good。

但是,可别高兴得太早。我在里面遇到了一些坑:

二、遇到的坑

1、监控账号

proxysql为了监控mysql,需要mysql提供一个监控账号,该账号权限不用太多,据说只需USAGE即可(见前面脚本)。问题是,这个监控账号,最好是与默认保持一致,即账号名和密码都是monitor。如果改成其他,真不知道在哪里设置。豆包信誓旦旦地说在配置文件里设置,而通义千问则说配置文件里设不了,应该在命令行里写。结果两个都无效,proxysql总是提示无法连接mysql。搞来搞去,我只好将monitor账号的密码改为"monitor",与默认保持一致,就好了。

2、mysql版本问题

配置文件中,对标mysql的版本号(mysql_variables:server_version)一定要写对。比如我的mysql是mysql8,但配置文件内容是从网上抄过来的,里面写的是5.0.9,结果运行的时候就报错了:unknown system variable ‘query_cache_size’。这是因为
mysql8之后,取消了"query_cache_size"这个属性,由于配置文件指明是mysql5,proxysql仍然使用了这个属性,所以就报错了。把配置文件提交给AI,它也看不出问题所在。

在这里插入图片描述

3、一个库故障后整个proxysql无法使用

在主库、从库都正常的情况下,用了一下,好像没啥问题。

但为了测试,我手动将从库关停后,结果整个proxysql都没办法使用了。proxysql其实已经检测到某个库出了问题,但不知道为什么,它没有将该库的状态设为离线或停止,仍然显示为"ONLINE"。

我在AI上问来问去,通义千问也,豆包也,chatGPT也,都问不出一个子丑寅卯。它们总喜欢穷举一些原因,我不得不一再强调,网络没有问题,在主从库都正常的情况下一切正常,然后它就说,既然如此,那问题很有可能出在proxysql的配置上,巴拉巴拉巴拉,吐出一大堆文字。并且不是一下子吐出,而是装叉地一行一行地输出,以为在拍黑客电影。

革命尚未成功,先记录下来。

三、附录 proxysql配置文件模板

proxysql最大的问题,根本不知道它的配置文件应该怎么写,怎么设置参数,官网上也找不到一个例子。好不容易从github上找到一个模板:

#file proxysql.cfg

# This config file is parsed using libconfig , and its grammar is described in:
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar
# Grammar is also copied at the end of this file



datadir="/var/run/proxysql"

admin_variables=
{
	admin_credentials="admin:admin"
	mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock"
#	refresh_interval=2000
#	debug=true
}

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
	ping_interval_server=10000
	ping_timeout_server=200
	commands_stats=true
	sessions_sort=true
}


# defines all the MySQL servers
mysql_servers =
(
#	{
#		address = "127.0.0.1" # no default, required . If port is 0 , address is interpred as a Unix Socket Domain
#		port = 3306           # no default, required . If port is 0 , address is interpred as a Unix Socket Domain
#		hostgroup = 0	        # no default, required
#		status = "ONLINE"     # default: ONLINE
#		weight = 1            # default: 1
#		compression = 0       # default: 0
#   max_replication_lag = 10  # default 0 . If greater than 0 and replication lag passes such threshold, the server is shunned
#	},
#	{
#		address = "/var/lib/mysql/mysql.sock"
#		port = 0
#		hostgroup = 0
#	},
#	{
#		address="127.0.0.1"
#		port=21891
#		hostgroup=0
#		max_connections=200
#	},
#	{ address="127.0.0.2" , port=3306 , hostgroup=0, max_connections=5 },
#	{ address="127.0.0.1" , port=21892 , hostgroup=1 },
#	{ address="127.0.0.1" , port=21893 , hostgroup=1 }
#	{ address="127.0.0.2" , port=3306 , hostgroup=1 },
#	{ address="127.0.0.3" , port=3306 , hostgroup=1 },
#	{ address="127.0.0.4" , port=3306 , hostgroup=1 },
#	{ address="/var/lib/mysql/mysql.sock" , port=0 , hostgroup=1 }
)


# defines all the MySQL users
mysql_users:
(
#	{
#		username = "username" # no default , required
#		password = "password" # default: ''
#		default_hostgroup = 0 # default: 0
#		active = 1            # default: 1
#	},
#	{
#		username = "root"
#		password = ""
#		default_hostgroup = 0
#		max_connections=1000
#		default_schema="test"
#		active = 1
#	},
#	{ username = "user1" , password = "password" , default_hostgroup = 0 , active = 0 }
)



#defines MySQL Query Rules
mysql_query_rules:
(
#	{
#		rule_id=1
#		active=1
#		match_pattern="^SELECT .* FOR UPDATE$"
#		destination_hostgroup=0
#		apply=1
#	},
#	{
#		rule_id=2
#		active=1
#		match_pattern="^SELECT"
#		destination_hostgroup=1
#		apply=1
#	}
)


# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar
#
# Below is the BNF grammar for configuration files. Comments and include directives are not part of the grammar, so they are not included here. 
#
# configuration = setting-list | empty
#
# setting-list = setting | setting-list setting
#     
# setting = name (":" | "=") value (";" | "," | empty)
#     
# value = scalar-value | array | list | group
#     
# value-list = value | value-list "," value
#     
# scalar-value = boolean | integer | integer64 | hex | hex64 | float
#                | string
#     
# scalar-value-list = scalar-value | scalar-value-list "," scalar-value
#     
# array = "[" (scalar-value-list | empty) "]"
#     
# list = "(" (value-list | empty) ")"
#     
# group = "{" (setting-list | empty) "}"
#     
# empty =

相关文章:

  • springboot中通过@Autowired依赖注入关联@RestControl@Service @Mapper @Data@TableName实现接口服务
  • React - 组件之props属性
  • 《Python 中 JSON 的魔法秘籍:从入门到精通的进阶指南》
  • vue中使用lodash的debounce(防抖函数)
  • spring boot和spring cloud的关系
  • Django 操作表中的数据(增删改查)
  • 用python写一个聊天室程序
  • 【二分搜索 C/C++】洛谷P1024 一元三次方程求解
  • 【deepseek 部署中的常见问题及解决方案--亲测有效】
  • 机器视觉中的3d和2d的区别
  • Unity实现UI拖拽
  • 《深度LSTM vs 普通LSTM:训练与效果的深度剖析》
  • 在 UniApp 中封装并连接 WebSocket 及重连机制实现
  • AcWing 798. 差分矩阵
  • 华为小艺支持DeepSeek
  • Python教学-最常用的标准库之一——OS库
  • golang基础库
  • 【SpringBoot苍穹外卖】debugDay03.5
  • Java 设计模式之备忘录模式
  • 2.11学习
  • 普京:俄中关系是国家间关系的真正典范
  • 刘元春在《光明日报》撰文:以法治护航民营经济高质量发展
  • 伊朗外长称正与美国进行“善意”的会谈
  • 国家出口管制工作协调机制办公室部署开展打击战略矿产走私出口专项行动
  • 重温经典|《南郭先生》:不模仿别人,不重复自己
  • 中国以优化营商环境为支点,为全球企业提供可预期市场环境