首页 > 技术文章 > docker搭建mysql主从复制

will-xz 2018-10-29 21:44 原文

mysql复制策略

架构变化的同时,业务也在不断地发展,可能很快就会发现,随着访问量的不断增加,拆分后的(业务拆分)某个数据库压力越来越大,马上就要达到能力的瓶颈,数据库的架构不得不再次进行变更,这是可以使用MySqld replication(复制)策略来对系统进行扩展。

通过数据库的复制策略,可以将一台MySQL数据库服务器中的数据复制到其他MySQL数据库服务器上。当各台数据库服务器上都包含相同数据时,前端应用通过访问MySQL集群中任意一台服务器,都能够读取到相同的数据,这样每台MySQL服务器所需要承担的负载就会大大降低,从而提高整个系统的承载能力,达到系统扩展的目的。

要实现数据库的复制,需要开启Master服务器端的Binary log。数据复制的过程实际上就是Slave从master获取binary log,然后再在本地镜像的执行日志中记录的操作。由于复制过程是异步的,因此Master和Slave之间的数据可能存在延迟的现象,此时只能保证数据最终的一致性。

MySQL的复制可以基于一条语句(statement level),也可以基于一条记录(row level)。通过row level复制,可以不记录仪执行的SQl语句相关联的上下文信息,只需要记录数据变更的内容即可。但由于每行的变更都会被记录,这样可能会产生大量的日志内容,而使用statement level则只是记录修改数的SQL语句,减少binary log的日志量,节约I/O成本。但是,所有语句在Slave端执行时能够得到在Master端执行的相同结果。

前端服务器通过Master来执行写入操作,数据的更变通过binary log通过到slave集群,而对于数据读取的请求,则交由slave来处理,这样集群可以分担数据库读的压力,比写数据库操作更为密集。如果读的压力较大,还可以新增slave来进行系统的扩展,因此,Master-Slave的架构能够显著地减轻前面所提到的单库读的压力。毕竟在大多数应用中,读的压力要比写的压力大得多。

Master-Slave复制架构存在一个问题,即所谓的单点故障。当Master宕机时,系统将无法写入,而在某些特定的场景下,也可能需要Master停机,以便进行系统 维护、优化或者升级。同样的道理,Master挺即将导致整个系统都无法写入,直到Master恢复,大部分情况下这显然是无法接受的。为了尽可能地降低系统停止写入的时间,最佳的方式就是采用Dual-Master架构,即Master-Master架构。

所谓的Dual Master。实际上就是两台MySql服务器互相将对方作为自己的Master,自己作为对方的Slave,这样任何一台服务器上的数据变更,都会通过Mysql的复制机制同步到另一台服务器。当然,有的㐉可能会担心,这样不会导致两台互为Master的Mysql之间循环复制吗?当然不会,这是由于Mysql在记录binary log日志时,记录了当前的server-id,server-id在外面配置Mysql复制时已经设置好了。一旦有了server-id,MySQL就很容易判断最初的写入是哪台服务器上发生的,MySQL不会将复制所产生的变更记录到binary log,这样就避免了服务器间数据的循环复制。

在搭建Dual-Master架构,并不是为了让两个Master能够同时提供写入服务,这样会导致很多问题。举例来说,假如MasterA与MasterB几乎同时对一条数据进行了更新,对MasterA的更新比MasterB的更新早,当对MasterA的更新最终同步到MasterB时,老版本的数据将会把版本更新的数据覆盖,并且不会抛出任何异常,从而导致数据不一致的现象发生。在通常情况下,我们仅开启一台Master的写入,另外一台Master仅仅stand by或者作为读库开放,这样可以避免数据写入的冲突,防止数据不一致情况的发生。

在正常的情况下,如需要进行停机维护,可按如下步骤执行Master的切换操作

  • 停止当前Master的所有写操作
  • 在Master上执行set global read_only=1,同时更新MySQL配置文件中相应的配置,避免重启时失效
  • 在Master上执行show Master status,已记录Binary log坐标
  • 使用Master上的Binary log坐标,在stand by的Master上执行select Master_pos_wait(),等待stand by Master的Binary log跟上Master的Binary log
  • 在stand by Master开启写入时,设置read_only=0
  • 修改应用程序的配置,使其写入到新的Master

假如Master意外宕机,处理过程要稍微复杂一点,因此此时Master与stand by Master 上的数据并不一定同步,需要将Master上没有同步到的stand by Master的Binary log复制到Master上进行replay,直到stand by Master与原Master的Binary log同步,才能开启写入;否则这一部分不同步的数据有可能导致数据不一致

实践主从复制

环境准备

  •  这里采用docker搭建主从复制。注:如果对docker不熟悉的请自行搜索资料,后面我会专门对docker做一些分享。
  • 主:172.17.0.2。
  • 从:172.17.0.3。

实践

1. 通过docker启用mysql,分别启动一个master(主)和一个slave(从),这里将宿主机的3307,3308端口映射到docker容器的3306端口,并设置同样的root密码为123456。

docker run -tid -p 3307:3306 --name mysql_master -e MYSQL_ROOT_PASSWORD=123456 mysql:5.6
docker run -tid -p 3308:3306 --name mysql_slave -e MYSQL_ROOT_PASSWORD=123456 mysql:5.6

2. 分别在主、从的mysqld.cnf中开启binlog,注意:这里的server_id必须是唯一的,这里我设置主的server_id为128,从的server_id为129。

log_bin=mysql-bin
server_id=128 # 唯一

3. 进入主mysql,查看主MYSQL的binlog,以及位置,记录mysql-bin,以及对应的位置,如:mysql-bin.000001,407,用于从mysql服务器的配置

SHOW MASTER STATUS;

4. 在主mysql中,创建从服务器复制的连接用户。

GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' IDENTIFIED BY 'slave';

5. 进入从服务器配置。

mysql> CHANGE MASTER TO 
    -> MASTER_HOST='172.17.0.2',
    -> MASTER_USER='slave',
    -> MASTER_PASSWORD='slave',
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=407;

6. 从服务器开启复制,并查看是否成功。

START SLAVE;
SHOW SLAVE STATUS \G
# 若以下两项均为Yes,即配置成功。
#Slave_IO_Running: Yes
#Slave_SQL_Running: Yes

7. 配置完成。然后在主服务器中,创建数据库,在从服务器中查看对应的数据库有没有同步完成,确认。

推荐阅读