介绍
随着现在互联网的应用越来越大,数据库会频繁的成为整个应用的性能瓶颈。而我们经常使用的MySQL数据库,也会不断面临数据量太大、数据访问太频繁、数据读写速度太快等一系列的问题。
要提升数据库的性能,首先要对单机Mysql计划,例如对MySQL进行优化配置,索引优化等;然后就是跟微服务架构的思路一样,从单体架构升级到集群架构,这样才能真正全方位解放数据库的性能瓶颈。
Mysql主从
如果要保证数据能够实时同步,对于MySQL,通常就要用到他自身提供的一套通过Binlog日志在多个MySQL服务之间进行同步的集群方案。基于这种集群方案,一方面可以提高数据的安全性,另外也可以以此为基础,提供读写分离、故障转移等其他高级的功能。
原理
主从同步过程:
- 主库打开
binlog日志,记录数据操作;从库打开RelayLog日志,用来重放操作 - slave的
I/O thread与master建立tcp连接,I/O thread读取主库的binlog,并写到relay log(中继日志)文件中 - slave通过
sql thread读取relay log,重放操作,达到数据最终一致性
主库创建一个log dump线程,用于发送binlog 的内容
搭建主从
注意:
1、MySQL版本必须一致。
2、集群中各个服务器的时间需要同步。
传统方式同步
配置master主服务
修改/etc/my.cnf
[mysqld]
# 指定服务节点的唯一标识
server-id=1
#开启binlog
log_bin=master-bin # 日志文件
log_bin_index=master-bin.index # 当前日志记录的位置
-------------------------------------------------------------------------
#需要同步的数据库名
binlog-do-db=user
#只保留7天的二进制日志,以防磁盘被日志占满(可选)
expire-logs-days = 7
#不备份的数据库
binlog-ignore-db=information_schema
binlog-ignore-db=performation_schema
binlog-ignore-db=sys
----------------------------------------------------------------
# 基础配置
# 设置连接端口
port=3306
# 设置mysql的安装目录
basedir=/usr/local/mysql
# 设置mysql数据库的数据的存放目录
datadir=/usr/local/mysql/mysql-files
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为UTF8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
重启服务即可生效
# 查看日志配置情况
show variables like '%bin%'
# 查看主节点同步状态
show master status
这个指令结果中的
File和Position记录的是当前日志的binlog文件以及文件中的索引。配置从服务时,就需要通过这个File和Position通知从服务从哪个地方开始记录binLog
Binlog_Do_DB,表示需要记录binlog文件的库
Binlog_Ignore_DB,不需要记录binlog文件的库。
这两个字段目前没有值,表明所有库都记录
配置slave服务
[mysqld]
#主库和从库需要不一致
server-id=2
#打开MySQL中继日志
relay-log-index=slave-relay-bin.index
relay-log=slave-relay-bin
#打开从服务二进制日志
log-bin=mysql-bin
#使得更新的数据写进二进制日志中
log-slave-updates=1
# 设置只读权限
read-only=1
-------------------------------------------------------
#如果salve库名称与master库名相同,使用本配置
replicate-do-db = masterdemo
#如果master库名[user]与salve库名[user_slave]不同,使用以下配置[需要做映射]
replicate-rewrite-db = user -> user_slave
#如果不是要全部同步[默认全部同步],则指定需要同步的表
replicate-wild-do-table=user_slave.table1
replicate-wild-do-table=user_slave.table2
重启服务
#设置同步主节点:
CHANGE MASTER TO
MASTER_HOST='192.168.232.128',
MASTER_PORT=3306,
MASTER_USER='root',
MASTER_PASSWORD='root',
MASTER_LOG_FILE='master-bin.000004',
MASTER_LOG_POS=156;
#开启slave
start slave;
#查看主从同步状态
show slave status;
连接失败,需要打通网络
更新失败,重新导入数据,设置更新点
GTID同步集群
MySQL5.6版本引入
GTID的本质也是基于Binlog来实现主从同步,只是他会基于一个全局的事务ID来标识同步进度。
GTID即全局事务ID,全局唯一并且趋势递增,他可以保证为每一个在主节点上提交的事务在复制集群中可以生成一个唯一的ID 。数据一致性相对传统方式更高;
在基于GTID的复制中,首先从服务器会告诉主服务器已经在从服务器执行完了哪些事务的GTID值,然后主库会有把所有没有在从库上执行的事务,发送到从库上进行执行,并且使用GTID的复制可以保证同一个事务只在指定的从库上执行一次,这样可以避免由于偏移量的问题造成数据不一致。
master配置
# 开启GTID复制
gtid_mode=on
# 跳过一些可能导致执行出错的SQL语句
enforce_gtid_consistency=on
log_bin=on
server_id=1
binlog_format=row
slave配置
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=1
server_id=2
---------------------------
change master to master_host='192.168.12.111',
master_user='slave',
master_password='123456',
master_port=3306,
master_auto_position=1;
---------------------------------
#开启slave
start slave;
原本需要通过master_log_file='mysql-bin-log.000001', master_log_pos=123指定同步的日志文件和同步点,但在GTID复制模式中,只需要设置一个master_auto_position=1即可,接下来它会自动寻找同步点
双主
在slave上开启binlog,重复做master上的配置,可以将slave的数据同步到master,提高可用性;
双主是否会存在主键冲突,如果主键为自增id,可以设置步长,A节点1,3,5;B节点2,4,6; 使用uuid、雪花算法等不存在主键冲突问题
迁移数据
master
mysqldump -u root -p --all-databases > backup.sql
slave
mysql -u root -p < backup.sql
如果是大数据量迁移,
vim /etc/my.cnf
max_allowed_packet=2G
进入mysql
souce backup.sql
上面效率还是优点慢,我们项目有一个表29G,导入数据导入了一晚上,,
可以拷贝data目录下需要同步的库和ibd文件,放到从库上,重启加载,亲测好使
半同步复制
MySQL主从集群默认采用的是一种异步复制的机制。主服务在执行用户提交的事务后,写入binlog日志,然后就给客户端返回一个成功的响应了。而binlog会由一个dump线程异步发送给Slave从服务。
由于这个发送binlog的过程是异步的。主服务在向客户端反馈执行结果时,是不知道binlog是否同步成功了的。这时候如果主服务宕机了,而从服务还没有备份到新执行的binlog,那就有可能会丢数据。
半同步复制机制是一种介于异步复制和全同步复制之间的机制。主库在执行完客户端提交的事务后,并不是立即返回客户端响应,而是等待至少一个从库接收并写到relay log中,才会返回给客户端。MySQL在等待确认时,默认会等10秒,如果超过10秒没有收到ack,就会降级成为异步复制。
半同步复制能够有效的提高数据的安全性。但是这种安全性也不是绝对的,他只保证事务提交后的binlog至少传输到了一个从库,并且并不保证从库应用这个事务的binlog是成功的。
另一方面,半同步复制机制也会造成一定程度的延迟,这个延迟时间最少是一个TCP/IP请求往返的时间。整个服务的性能是会有所下降的。而当从服务出现问题时,主服务需要等待的时间就会更长,要等到从服务的服务恢复或者请求超时才能给用户响应。
依赖这两个模块
master
install plugin rpl_semi_sync_master soname 'semisync_master.so';
show global variables like 'rpl_semi%';
set global rpl_semi_sync_master_enabled=ON;
slave
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
set global rpl_semi_sync_slave_enabled = on;
stop slave;
start slave;
读写分离
首先需要保证数据只在主服务上写,而从服务只进行数据读取;因为一旦有数据写入,就会造成数据不一致,并且从服务在执行事务期间还很容易造成数据同步失败。
在从服务中将read_only参数的值设为1
- read_only=1设置的只读模式,不会影响slave同步复制的功能
- read_only=1设置的只读模式, 限定的是普通用户进行数据修改的操作,但不会限定具有super权限的用户的数据修改操作。
延迟问题
数据往主服务写,而读数据在从服务读。这时候这个主从复制延迟就有可能造成主库上刚插入了数据但是从库查不到
出现这个问题的根本在于:面向业务的主服务数据都是多线程并发写入的,而从服务是单个线程慢慢拉取binlog,这中间就会有个效率差。所以解决这个问题的关键是要让从服务也用多线程并行复制binlog数据。
解决办法
-
网络方面:尽量保证主库和从库之间的网络稳定,延迟较小;
-
硬件方面:从库配置更好的硬件,提升随机写的性能;
-
配置方面:尽量使 MySQL 的操作在内存中完成,减少磁盘操作。或升级 MySQL5.7 版本使用并行复制;
-
建构方面:在事务中尽量对主库读写,其它非事务的读在从库。消除一部分延迟带来的数据库不一致。增加缓存降低一些从库的负载。
主从扩展
一主多从:提高读能力;同时会造成主节点同步压力,又扩展出多级从
互主集群:两个服务互为主从,分担写压力
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第4天,点击查看活动详情