MySQL主从复制原理
主服务器数据库的每次操作都会记录在其二进制文件mysql-bin.xxx(该文件可以在mysql目录下的data目录中看到)中,从服务器的I/O线程使用专用账号登录到主服务器中读取该二进制文件,并将文件内容写入到自己本地的中继日志relay-log文件中,然后从服务器的SQL线程会根据中继日志中的内容执行SQL语句
MySQL主从同步的作用
1、可以作为备份机制,相当于热备份
2、可以用来做读写分离,均衡数据库负载
项目场景
1、主服务器192.168.3.212,其中已经有数据库且库中有表,库名为test
2、从服务器192.168.3.213,空的啥也没有
准备工作
主从服务器需要有相同的初态
- 将主服务器要同步的数据库加锁,避免同步时数据发生改变
mysql>use test;
mysql>flush tables with read lock;
FLUSH TABLES WITH READ LOCK
关闭所有的表,并给所有数据库的所有表加上一个global readlock。
这对于backup操作来说很有用,加锁之后,可以防止应用修改数据库。这个是全局级别的锁,而非表锁。
- 将主服务器数据库中数据导出
mysql>mysqldump -uroot -pxxxx test > test.sql;
这个命令是导出数据库中所有表结构和数据,如果要导出函数和存储过程的话使用
mysql>mysqldump -R -ndt test -uroot -pxxxx > test.sql
- 备份完成后,解锁主服务器数据库
mysql>unlock tables;
- 将初始数据导入从服务器数据库
mysql>create database test;
mysql>use test;
mysql>source test.sql;
好了,现在主从服务器拥有一样的初态了
.
.
.
主服务器配置
1、修改MySQL配置
vi /etc/my.cnf
#主数据库端ID号
server_id = 1
log-bin = mysql-bin
#开启二进制日志
log-bin = mysql-bin
#需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可
binlog-do-db = db
2、重启MySQL,创建允许从服务器同步数据的账户
#创建slave账号account,密码123456
mysql>grant replication slave on *.* to 'account'@'192.168.3.213' identified by '123456';
#更新数据库权限
mysql>flush privileges;
3、查看主服务器状态
mysql>show master status\G
***************** 1. row ****************
File: mysql-bin.000033 #当前记录的日志
Position: 337523 #日志中记录的位置
Binlog_Do_DB:
Binlog_Ignore_DB:
执行完这个步骤后不要再操作主服务器数据库了,防止其状态值发生变化
.
.
.
从服务器配置
1、修改MySQL配置
vi /etc/my.cnf
在[mysqld]中添加
server_id = 2
log-bin = mysql-bin
# 减少记录日志的内容,只记录受影响的列
binlog_row_image = minimal
# 指定需要复制的数据库名,同步的库名一样用这个
# replicate-do-db = bi
# 如果同步到不同库名用这个
replicate-rewrite-db=bi->aoshu_data
# replicate-do-table = bi.t_time #同步的数据库名.表名
2、执行同步命令
#执行同步命令,设置主服务器ip,同步账号密码,同步位置
mysql>change master to master_host='192.168.3.212',master_user='account',master_password='123456',master_log_file='mysql-bin.000033',master_log_pos=337523;
#开启同步功能
mysql>start slave;
3、查看从服务器状态
mysql>show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.3.212
Master_User: account
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000033
Read_Master_Log_Pos: 337523
Relay_Log_File: db2-relay-bin.000002
Relay_Log_Pos: 337686
Relay_Master_Log_File: mysql-bin.000033
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
...
Slave_IO_Running及Slave_SQL_Running进程必须正常运行,即Yes状态,否则说明同步失败
若失败查看mysql错误日志中具体报错详情来进行问题定位
最后可以去主服务器上的数据库中创建表或者更新表数据来测试同步
坑:
- 只同步单表时,该表的数据来自主库的其他表,如:
同步table_a表时,table_a表的修改语句为:
如果从库没有table_b时,会报table_b不存在UPDATE table_a SET table_a.last_login_time = (SELECT MAX(login_time) FROM table_b WHERE user_id=1) where user_id=1;
可以用以下方法解决:
在主库my.cnf加上# binlog记录内容的方式,记录被操作的每一行(解决只同步单表时,该表的数据来自其他表的报错) binlog_format = ROW