Mysql实现数据库主从复制架构
原创
©著作权归作者所有:来自51CTO博客作者一号花匠的原创作品,请联系作者获取转载授权,否则将追究法律责任
1. 项目背景
随着公司发展,用户数据已成为公司核心,为防止数据丢失或被误删,要求对数据库进行改造,提升其承载能力。
2. 项目规划
经过分析,使用高可用技术搭建从服务器可以提满足需求。
3. 架构图
MySQL 的原生复制架构原理如上图所示。从库的 I/O Thread 线程负责不断读取主库的 binlog 日志文件并写入本地的 Relay log 临时缓存。从库的 SQL Thread 线程则不断读取 Relay log 重放事件入库。整个过程看起来是比较简单清晰的,但其中有几个点对主从数据一致性有关键影响,我们下面逐一分析。
4. 技术分析
主从复制的场景下,需要注意产生数据不一致,导致数据不一致的现象有两种:
数据丢失:从库的 I/O Thread 是通过网络读取主库的 binlog 的,若出现网络故障,有可能产生数据丢失。为避免网络故障导致的数据丢失,网络恢复后从库重新连接上来需要知道从主库 binlog 的哪个位置重新传输数据。从库需要记住中断发生时 binlog 的位置,并从该断点处重新读取,这个断点我们称为从库的重传检查点。一个可靠的重传检查点必须是在从库读到数据并写入到本地 Relay log 持久化之后才可建立,否则都有丢失数据的可能。
数据重复:由于主从复制过程的特征,需要保证复制过程不会重复复制数据,也就是重复复制同一条数据最终不会产生重复的数据。防重策略是必须的,一般符合范式特征的数据库表设计通过主键来防重,而无主键表数据可以通过所有字段联合唯一索引来防重。有了防重策略就可以任意回溯复制过程,而不必考虑从库产生重复数据。
5.项目实施
1、在Master的数据库中建立一个备份帐户:每个slave使用标准的MySQL用户名和密码连接master。进行复制操作的用户会授予REPLICATION SLAVE权限。用户名的密码都会存储在文本文件master.info中:mysql > GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.*TObackup@’ip’ IDENTIFIED BY ‘1234’;建立一个帐户backup,并且只能允许从ip这个地址上来登陆,密码是1234。
2、拷贝数据
关停Master服务器,将Master中的数据拷贝到B服务器中,使得Master和slave中的数据同步,并且确保在全部设置操作结束前,禁止在Master和slave服务器中进行写操作,使得两数据库中的数据一定要相同!
3、配置master
接下来对master进行配置,包括打开二进制日志,指定唯一的servr ID。例如,在配置文件加入如下值:
server-id=1
log-bin=mysql-bin
server-id:为主服务器A的ID值
log-bin:二进制变更日值
重启master,运行SHOW MASTER STATUS,输出如下:
4、配置slave
Slave的配置与master类似,你同样需要重启slave的MySQL。如下:
log_bin = mysql-bin
server_id = 2
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1
server_id是必须的,而且唯一。slave没有必要开启二进制日志,但是在一些情况下,必须设置,例如,如果slave为其它slave的master,必须设置bin_log。在这里,我们开启了二进制日志,而且显示的命名(默认名称为hostname,但是,如果hostname改变则会出现问题)。
relay_log配置中继日志,log_slave_updates表示slave将复制事件写进自己的二进制日志(后面会看到它的用处)。
有些人开启了slave的二进制日志,却没有设置log_slave_updates,然后查看slave的数据是否改变,这是一种错误的配置。所以,尽量使用read_only,它防止改变数据(除了特殊的线程)。但是,read_only并是很实用,特别是那些需要在slave上创建表的应用。
5、启动slave
接下来就是让slave连接master,并开始重做master二进制日志中的事件。使用CHANGE MASTER TO语句,它可以为slave指定不同的master,而不需要停止服务器。如下:
mysql> CHANGE MASTER TO MASTER_HOST='server1',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='p4ssword',
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=0;
MASTER_LOG_POS的值为0,因为它是日志的开始位置。
你可以用SHOW SLAVE STATUS语句查看slave的设置是否正确:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: server1
Master_User: repl
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: No
Slave_SQL_Running: No
...omitted...
Seconds_Behind_Master: NULL
Slave_IO_State, Slave_IO_Running, 和Slave_SQL_Running是No
表明slave还没有开始复制过程。日志的位置为4而不是0,这是因为0只是日志文件的开始位置,并不是日志位置。实际上,MySQL知道的第一个事件的位置是4。
为了开始复制,你可以运行:
mysql> START SLAVE;
运行SHOW SLAVE STATUS查看输出结果:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: server1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 164
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 164
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...omitted...
Seconds_Behind_Master: 0
在这里主要是看:
Slave_IO_Running=Yes
Slave_SQL_Running=Yes
slave的I/O和SQL线程都已经开始运行,而且Seconds_Behind_Master不再是NULL。日志的位置增加了,意味着一些事件被获取并执行了。如果你在master上进行修改,你可以在slave上看到各种日志文件的位置的变化,同样,你也可以看到数据库中数据的变化。