首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

mysql 读写分离实战操作讲解

一、概述

MySQL 读写分离是指将 MySQL 数据库的读操作和写操作分别分配到不同的服务器上进行处理,以提高数据库的并发性能和可靠性。

具体来说,MySQL 读写分离通常涉及一个主服务器(Master)和多个从服务器(Slave)。所有写操作都由主服务器处理,而读操作则由从服务器处理。主服务器负责写操作的数据更新,并将更新操作同步到所有从服务器上。从服务器则负责读操作,返回最新的数据给客户端。

在 MySQL 读写分离中,可以使用以下两种方式来实现主从同步:

基于 MySQL 内置的复制功能实现主从同步,称为 MySQL Replication。在这种情况下,主服务器会将更新操作写入二进制日志文件(binlog),从服务器会从主服务器上获取这些日志,并将其应用于自己的数据中,从而实现数据同步。这种方式需要配置主服务器和从服务器的连接信息和权限等,以确保数据安全和一致性。

基于第三方工具实现主从同步,如 Tungsten Replicator 和 MaxScale 等。这些工具提供了更多的功能和灵活性,例如故障切换、读写分离策略、负载均衡等。

在 MySQL 读写分离中,需要注意以下几点:

写操作可能会有延迟,因为更新操作必须先在主服务器上进行,然后才能同步到从服务器上。因此,在读写分离中,需要确保从服务器上的数据与主服务器上的数据保持一致,避免数据不一致的情况。

在高并发环境下,需要根据负载情况和服务器性能调整读写分离的策略,以实现最佳的性能和可靠性。

在进行数据库备份和恢复时,需要考虑主从服务器之间的数据同步和备份一致性。

二、要实现读写分离必须是主从同步

2.1、环境设定

2.2、实现主从同步

2.2.1、原理:

1)主从同步过程中主服务器有一个工作线程I/O dump thread从服务器有两个工作线程I/O thread和SQL thread

2)主库把外界接收的SQL请求记录到自己的binlog日志中,从库的I/O thread去请求主库的binlog日志,并将binlog日志写到中继日志中,然后从库重做中继日志的SQL语句。主库通过I/O dump thread从库I/O thread传送binlog日志。

3)异步复制是MySQL默认的复制方式,主库写入binlog日志后即可成功返回客户端,无须等待binlog日志传递给从库的过程,但是一旦主库宕机,就有可能出现丢失数据的情况。

4)复制原理

4.1 )异步复制

异步复制是MySQL默认的复制方式,主库写入binlog日志后即可成功返回客户端,无须等待binlog日志传递给从库的过程,但是一旦主库宕机,就有可能出现丢失数据的情况。

4.2) 半同步复制

MySQL默认的复制方式是异步复制,但是当主库宕机,在高可用架构坐准备切换,就会造成新的主库丢失数据的现象。

MySQL5.5版本之后引入了半同步复制,但是主从服务器必须同时安装半同步复制插件。在该功能下,确保从库接收完成主库传递过来的binlog内容已经写入到自己的relay log后才会通知主库上面的等待线程。如果等待超时(超时参数:rpl_semi_sync_master_timeout),则关闭半同步复制,并自动转换为异步复制模式,直到至少有一台从库通知主库已经接收到binlog信息为止。

半同步复制提升了主从之间数据的一致性,让复制更加安全可靠,在5.7 版本中又增加了rpl_semi_sync_master_wait_point参数,用来控制半同步模式下主库返回给session事务成功之前的事务提交方式。

该参数有两个值:

1)AFTER_COMMIT5.6版本的默认值,主库将每个事务写入binlog,并传递给从库,刷新到中继日志中,同时主库提交事务。之后主库开始等待从库的反馈,只有收到从库的回复之后,master才将commit OK的结果反馈给客户端。

2)AFTER_SYNC5.7版本新增,也是默认的半同步复制方式。主库将每个事务写入binlog并传递给从库,刷新到中继日志中,主库开始等待从库的反馈,接收到从库的回复之后,再提交事务并且返回commit OK结果给客户端。

注意:可以通过rpl_semi_sync_master_wait_for_slave_count参数来控制主库接收多少个从库写事务成功反馈,才返回成功给客户端。生产环境中使用半同步复制方式,当从库出现故障,等待超时的时间又很长,导致主库无法接收从库信息而无法正常写入时,可通过该参数剔除故障从库。另外rpl_semi_sync_master_timeout单位是毫秒,它表示如果主库等待从库回复消息的时间超过该值,就自动切换为异步复制模式,建议调整为很大,禁止向异步复制切换来保证数据复制的安全性。MySQL 5.7默认的半同步复制方式是after_sync模式。

AFTER_SYNC模式下,即使主库宕机,所有在主库上已经提交的事务都能保证已经同步到从库的中继日志中,不会丢任何数据。

原理图:

2.2.2、主从配置:

注意:这里使用的是mysql5.6版本,如果其它版本的话,配置可能会有点不一样,例如:"log_bin" 对应 "log-bin",只是把"_"换成了"-"了,区别不大,注意一下就行

#=======================master配置(my.cnf)=====================

# 设置优先级,主必须小于从

server-id=1

# bin log文件前缀

log_bin=mysql-bin

# 对应要同步的数据库

binlog_do_db=tuling

binlog_do_db=zabbix

# 不需要同步的数据库

binlog_ignore_db=information_schema

binlog_ignore_db=mysql

binlog_ignore_db=performance_schema

binlog_ignore_db=test

#=======================slave配置(my.cnf)=====================

# 实例ID,不能喝集群忠的其它mysql实例相同,唯一性

server-id=2

# 对应要同步的数据库,如果没有向其它数据库同步的要求的话,可以不写

# log_bin=mysql-bin

# 需要同步的数据库

replicate_do_db=tuling

replicate_do_db=zabbix

# 设定需要复制的表

# replicate_do_table=tuling.tab1

# 设定需要忽略的复制表

# replicate_ignore_table=tuling.tab2

# 增加通配符的两个配置

# replicate_wild_do_table=tuling.%   只复制哪个库的哪个表

# replicate_wild_ignore_table=tuling.%   忽略哪个库的哪个表

# replicate_do_table 跟 replicate_wild_do_table 一样,只不过replicate_wild_do_table可以加通配符

# replicate_ignore_table 跟 replicate_wild_ignore_table 一样,只不过replicate_wild_ignore_table可以加通配符

# 不需要同步的数据库

replicate_ignore_db=information_schema

replicate_ignore_db=mysql

replicate_ignore_db=performance_schema

replicate_ignore_db=test

#在master上创建一个同步权限的账户 用来同步数据

grant replication slave on *.* to 'master'@'%' identified by '123456';

show master status\G;

# 配置从库

stop slave

reset slave;

change master to master_host='192.168.182.129',master_user='master',master_password='123456',master_port=3306,master_log_file='mysql-bin.000018',master_log_pos=326;

start slave;

show slave status\G;

# 当Slave_IO_Running和Slave_SQL_Running线程都为yes是主从复制配置成功!

2.3、错误及解决办法

问题: 从数据库无法同步

Slave_SQL_Running 值为 NO,或 Seconds_Bebind_Master 值为 Null

原因:

1. 程序有可能在 slave 上进行了写操作

2. 也有可能是 slave 机器重启后,事务回滚造成的

解决方法一:

msyql> stop slave;

msyql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;

msyql> start slave;

解决方法二:

msyql> stop slave;

#查看主服务器上当前的 bin-log 日志名和偏移量

msyql> show master status;

#获取到如下内容:

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

| File           | Position | Binlog_Do_DB | Binlog_Ignore_DB |

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

| mysql-bin.000005 |     286 |             |                 |

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

#然后到从服务器上执行手动同步

msyql> change master to

  ->master_host="192.168.10.1",

  ->master_user="user",

  ->master_password="123456",

  ->master_post=3306,

  ->master_log_file="mysql-bin.000005",

  ->master_log_pos=286;msyql> start slave;三、通过Atlas实现读写分离

Atlas 是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。3.1、Atlas配置

下载Atlas会有两个版本,其中有个分表的版本,但是这个需要其他的依赖,我这边不需要分表这种需求,所以安装普通的版本

Atlas (普通) : Atlas-2.2.1.el6.x86_64.rpm

Atlas (分表) : Atlas-sharding_1.0.1-el6.x86_64.rpm

首先进入Linux的Home目录下,下载非分表的安装包

[root@localhost ~]# cd /home/

[root@localhost home]# wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm

下载好了之后,进行安装

[root@localhost home]# rpm -ivh Atlas-2.2.1.el6.x86_64.rpm

Preparing...               ########################################### [100%]

  1:Atlas                 ########################################### [100%]

安装好了,它会默认在”/usr/local/mysql-proxy”下给你生成4个文件夹,以及需要配置的文件,如下:

[root@localhost home]# ll /usr/local/mysql-proxy/

total 16

drwxr-xr-x. 2 root root 4096 Dec 28 10:47 bin

drwxr-xr-x. 2 root root 4096 Dec 28 10:47 conf

drwxr-xr-x. 3 root root 4096 Dec 28 10:47 lib

drwxr-xr-x. 2 root root 4096 Dec 17 2014 log

bin目录下放的都是可执行文件

1. “encrypt”是用来生成MySQL密码加密的,在配置的时候会用到

2. “mysql-proxy”是MySQL自己的读写分离代理

3. “mysql-proxyd”是360弄出来的,后面有个“d”,服务的启动、重启、停止。都是用他来执行的

conf目录下放的是配置文件

1. “test.cnf”只有一个文件,用来配置代理的,可以使用vim来编辑

lib目录下放的是一些包,以及Atlas的依赖

log目录下放的是日志,如报错等错误信息的记录

进入bin目录,使用encrypt来对数据库的密码进行加密,我的MySQL数据的用户名是root,密码是root,我需要对密码进行加密

[root@localhost bin]# ./encrypt root

DAJnl8cVzy8=

配置Atlas,使用vim进行编辑

[root@localhost conf]# cd /usr/local/mysql-proxy/conf/

[root@localhost conf]# vim test.cnf

进入后,可以在Atlas进行配置,360写的中文注释都很详细,根据注释来配置信息,其中比较重要,需要说明的配置如下:

这是用来登录到Atlas的管理员的账号与密码,与之对应的是“#Atlas监听的管理接口IP和端口”,也就是说需要设置管理员登录的端口,才能进入管理员界面,默认端口是2345,也可以指定IP登录,指定IP后,其他的IP无法访问管理员的命令界面。方便测试,我这里没有指定IP和端口登录。

#管理接口的用户名

admin-username = user

#管理接口的密码

admin-password = pwd

这是用来配置主数据的地址与从数据库的地址,这里配置的主数据库是135,从数据库是134

#Atlas后端连接的MySQL主库的IP和端口,可设置多项,用逗号分隔

proxy-backend-addresses = 192.168.182.129:3306

#Atlas后端连接的MySQL从库的IP和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认为1,可设置多项,用逗号分隔

proxy-read-only-backend-addresses = 192.168.182.130:3306@1

这个是用来配置MySQL的账户与密码的,我的MySQL的用户是root,密码是root,刚刚使用Atlas提供的工具生成了对应的加密密码

#用户名与其对应的加密过的MySQL密码,密码使用PREFIX/bin目录下的加密程序encrypt加密,下行的user1和user2为示例,将其替换为你的MySQL的用户名和加密密码!

pwds = root:DAJnl8cVzy8=

这是设置工作接口与管理接口的,如果ip设置的”0.0.0.0”就是说任意IP都可以访问这个接口,当然也可以指定IP和端口,方便测试我这边没有指定,工作接口的用户名密码与MySQL的账户对应的,管理员的用户密码与上面配置的管理员的用户密码对应。

#Atlas监听的工作接口IP和端口

proxy-address = 0.0.0.0:1234

#Atlas监听的管理接口IP和端口

admin-address = 0.0.0.0:2345

启动Atlas

[root@localhost bin]# ./mysql-proxyd test start

OK: MySQL-Proxy of test is started

测试一下Atlas服务器的MySQL状态,要确认它是关闭状态,并且使用mysql命令,进不去数据库

[root@localhost bin]# /etc/init.d/mysqld status

mysqld is stopped

[root@localhost bin]# mysql

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

确认系统中自带的MySQL进不去了,使用如下命令,进入Atlas的管理模式“mysql -h127.0.0.1 -P2345 -uuser -ppwd ”,能进去说明Atlas正常运行着呢,因为它会把自己当成一个MySQL数据库,所以在不需要数据库环境的情况下,也可以进入到MySQL数据库模式。

[root@localhost bin]# mysql -h127.0.0.1 -P2345 -uuser -ppwd

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 1

Server version: 5.0.99-agent-admin

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

可以访问“help”表,来看MySQL管理员模式都能做些什么。可以使用SQL语句来访问

mysql> select * from help;

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

| command                   | description                                             |

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

| SELECT * FROM help         | shows this help                                         |

| SELECT * FROM backends     | lists the backends and their state                     |

| SET OFFLINE $backend_id   | offline backend server, $backend_id is backend_ndx's id |

| SET ONLINE $backend_id     | online backend server, ...                             |

| ADD MASTER $backend       | example: "add master 127.0.0.1:3306", ...               |

| ADD SLAVE $backend         | example: "add slave 127.0.0.1:3306", ...               |

| REMOVE BACKEND $backend_id | example: "remove backend 1", ...                       |

| SELECT * FROM clients     | lists the clients                                       |

| ADD CLIENT $client         | example: "add client 192.168.1.2", ...                 |

| REMOVE CLIENT $client     | example: "remove client 192.168.1.2", ...               |

| SELECT * FROM pwds         | lists the pwds                                         |

| ADD PWD $pwd               | example: "add pwd user:raw_password", ...               |

| ADD ENPWD $pwd             | example: "add enpwd user:encrypted_password", ...       |

| REMOVE PWD $pwd           | example: "remove pwd user", ...                         |

| SAVE CONFIG               | save the backends to config file                       |

| SELECT VERSION             | display the version of Atlas                           |

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

16 rows in set (0.00 sec)

mysql>

也可以使用工作接口来访问,使用命令“mysql -h127.0.0.1 -P1234 -uroot -proot”

[root@localhost bin]# mysql -h127.0.0.1 -P1234 -uroot -proot

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 1

Server version: 5.0.81-log

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

如果工作接口可以进入了,就可以在Windows平台下,使用Navicat来连接数据库,填写对应的host,Port,用户名,密码就可以

3.2、读写分离测试

这里测试读写分离需要使用到Jmeter了,它是Java写第一套开源的压力测试工具,因为这个比较方便。他有专门测试MySQL的模块,需要使用MySQL的JDBC驱动jar包,配置很简单,东西很好很强大很好用。

MySQL的JDBC :http://dev.mysql.com/downloads/connector/j/

下载下来后,分别都解压开来,打开Jmeter ( 在bin路面下的jmeter.bat ) ,在测试计划中,导致JDBC的jar包

配置JDBC的驱动

分别做查询与插入语句

配置好了以后,就先运行查询操作,然后分别监控主数据库与从数据库所在机器的流量,来确定是否读写,使用在主备Linux命令行输入“sar -n DEV 1 10000”命令来监控读写

先来测试写,目前数据库里面一条信息都没有,开启配置好了的Jmeter,进行写入数据测试

sar命令查看网卡流量

sar这个工具RHEL5自带有,默认也安装。

一个强大的工具(好像这些工具都蛮强的),参数很多,有时间man一下。

-n参数很有用,他有6个不同的开关:DEV | EDEV | NFS | NFSD | SOCK | ALL 。DEV显示网络接口信息,EDEV显示关于网络错误的统计数据,NFS统计活动的NFS客户端的信息,NFSD统计NFS服务器的信息,SOCK显示套 接字信息,ALL显示所有5个开关。它们可以单独或者一起使用。我们现在要用的就是-n DEV了。

输入命令:sar –n DEV 1 4命令后面 1 4 意思是:每一秒钟取一次值,取四次。

主数据库 ( 192.168.182.129 )

从数据库 ( 192.168.182.130)

批量插入数据语句

delimiter //

DROP PROCEDURE IF EXISTS proc_batch_insert;

CREATE PROCEDURE proc_batch_insert()

BEGIN

DECLARE pre_name BIGINT;

DECLARE ageVal INT;

DECLARE i INT;

SET pre_name=187635267;

SET ageVal=100;

SET i=1;

WHILE i

      INSERT INTO tt(descpro) VALUES(NOW());

SET pre_name=pre_name+100;

SET i=i+1;

END WHILE;

END //

delimiter ;

call proc_batch_insert();

可以看到测试插入数据的操作时,主(192.168.182.129)数据库的网卡有些指标流量很大而从数据库的流量很小,是应为主数据是主要负责写入的,而从(192.168.182.130)数据库主要是负责同步的。

参数说明:

IFACE:LAN接口

rxpck/s:每秒钟接收的数据包

txpck/s:每秒钟发送的数据包

rxbyt/s:每秒钟接收的字节数

txbyt/s:每秒钟发送的字节数

rxcmp/s:每秒钟接收的压缩数据包

txcmp/s:每秒钟发送的压缩数据包

rxmcst/s:每秒钟接收的多播数据包

rxerr/s:每秒钟接收的坏数据包

txerr/s:每秒钟发送的坏数据包

coll/s:每秒冲突数

rxdrop/s:因为缓冲充满,每秒钟丢弃的已接收数据包数

txdrop/s:因为缓冲充满,每秒钟丢弃的已发送数据包数

txcarr/s:发送数据包时,每秒载波错误数

rxfram/s:每秒接收数据包的帧对齐错误数

rxfifo/s:接收的数据包每秒FIFO过速的错误数

txfifo/s:发送的数据包每秒FIFO过速的错误数

查看数据库,发现已经插入了100w条数据了

进行读取数据的测试,只需要执行查询就好,执行“select *from tt;”来查询数据表

主数据库 ( 192.168.182.129 )

从数据库 ( 192.168.182.130 )

可以看到130数据库的流量非常大,129没有什么流量,这下就可以确定了数据是从数据库读取的。已经实现了读写分离。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230412A000J400?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券