一、复制的常用拓扑结构
复制的体系结构有以下一些基本原则:
(1) 每个slave只能有一个master;
(2) 每个slave只能有一个唯一的服务器ID;
(3) 每个master可以有很多slave;
(4) 如果你设置log_slave_updates,slave可以是其它slave的master,从而扩散master的更新。
MySQL不支持多主服务器复制(Multimaster Replication)——即一个slave可以有多个master。但是,通过一些简单的组合,我们却可以建立灵活而强大的复制体系结构。
1.1 单一master和多slave
在实际应用场景中,MySQL复制90%以上都是一个Master复制到一个或者多个Slave的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只要Master和Slave的压力不是太大(尤其是Slave端压力)的话,异步复制的延时一般都很少很少。尤其是自从Slave端的复制方式改成两个线程处理之后,更是减小了Slave端的延时问题。
当slave增加到一定数量时,slave对master的负载以及网络带宽都会成为一个严重的问题
这种结构虽然简单,但是,它却非常灵活,足够满足大多数应用需求。一些建议:
(1) 不同的slave扮演不同的作用(例如使用不同的索引,或者不同的存储引擎);
(2) 用一个slave作为备用master,只进行复制;
(3) 用一个远程的slave,用于灾难恢复;
1.2 主动模式的Master-Master
这样搭建复制环境之后,难道不会造成两台MySQL之间的循环复制么?实际上MySQL自己早就想到了这一点,所以在MySQL的BinaryLog中记录了当前MySQL的server-id,而且这个参数也是我们搭建MySQLReplication的时候必须明确指定,而且Master和Slave的server-id参数值比需要不一致才能使MySQLReplication搭建成功。一旦有了server-id的值之后,MySQL就很容易判断某个变更是从哪一个MySQLServer最初产生的,所以就很容易避免出现循环复制的情况。
主动的Master-Master复制有一些特殊的用处。例如,地理上分布的两个部分都需要自己的可写的数据副本。这种结构最大的问题就是更新冲突。假设一个表只有一行(一列)的数据,其值为1,如果两个服务器分别同时执行如下语句:
在第一个服务器上执行:
mysql> UPDATE tbl SET col=col + 1;
在第二个服务器上执行:
mysql> UPDATE tbl SET col=col * 2;
那么结果是多少呢?一台服务器是4,另一个服务器是3,但是,这并不会产生错误。
实际上,MySQL并不支持其它一些DBMS支持的多主服务器复制(Multimaster Replication),这是MySQL的复制功能很大的一个限制(多主服务器的难点在于解决更新冲突),但是,如果你实在有这种需求,你可以采用MySQL Cluster,以及将Cluster和Replication结合起来,可以建立强大的高性能的数据库平台。但是,可以通过其它一些方式来模拟这种多主服务器的复制。
1.3 主动-被动模式的Master-Master
1.4 级联复制架构 Master –Slaves -Slaves
在有些应用场景中,可能读写压力差别比较大,读压力特别的大,一个Master可能需要上10台甚至更多的Slave才能够支撑注读的压力。这时候,Master就会比较吃力了,因为仅仅连上来的SlaveIO线程就比较多了,这样写的压力稍微大一点的时候,Master端因为复制就会消耗较多的资源,很容易造成复制的延时。
遇到这种情况如何解决呢?这时候我们就可以利用MySQL可以在Slave端记录复制所产生变更的BinaryLog信息的功能,也就是打开—log-slave-update选项。然后,通过二级(或者是更多级别)复制来减少Master端因为复制所带来的压力。也就是说,我们首先通过少数几台MySQL从Master来进行复制,这几台机器我们姑且称之为第一级Slave集群,然后其他的Slave再从第一级Slave集群来进行复制。从第一级Slave进行复制的Slave,我称之为第二级Slave集群。如果有需要,我们可以继续往下增加更多层次的复制。这样,我们很容易就控制了每一台MySQL上面所附属Slave的数量。这种架构我称之为Master-Slaves-Slaves架构
这种多层级联复制的架构,很容易就解决了Master端因为附属Slave太多而成为瓶颈的风险,当然,如果条件允许,我更倾向于建议大家通过拆分成多个Replication集群来解决
上述瓶颈问题。毕竟Slave并没有减少写的量,所有Slave实际上仍然还是应用了所有的数据变更操作,没有减少任何写IO。相反,Slave越多,整个集群的写IO总量也就会越多,我们没有非常明显的感觉,仅仅只是因为分散到了多台机器上面,所以不是很容易表现出来。
此外,增加复制的级联层次,同一个变更传到最底层的Slave所需要经过的MySQL也会更多,同样可能造成延时较长的风险。
而如果我们通过分拆集群的方式来解决的话,可能就会要好很多了,分拆集群也需要更复杂的技术和更复杂的应用系统架构。
1.5 带从服务器的Master-Master结构(Master-Master with Slaves)
级联复制在一定程度上面确实解决了Master因为所附属的Slave过多而成为瓶颈的问题,但是他并不能解决人工维护和出现异常需要切换后可能存在重新搭建Replication的问题。这样就很自然的引申出了DualMaster与级联复制结合的Replication架构,我称之为Master-Master-Slaves架构
和Master-Slaves-Slaves架构相比,区别仅仅只是将第一级Slave集群换成了一台单独的Master,作为备用Master,然后再从这个备用的Master进行复制到一个Slave集群。
这种DualMaster与级联复制结合的架构,最大的好处就是既可以避免主Master的写入操作不会受到Slave集群的复制所带来的影响,同时主Master需要切换的时候也基本上不会出现重搭Replication的情况。但是,这个架构也有一个弊端,那就是备用的Master有可能成为瓶颈,因为如果后面的Slave集群比较大的话,备用Master可能会因为过多的SlaveIO线程请求而成为瓶颈。当然,该备用Master不提供任何的读服务的时候,瓶颈出现的可能性并不是特别高,如果出现瓶颈,也可以在备用Master后面再次进行级联复制,架设多层Slave集群。当然,级联复制的级别越多,Slave集群可能出现的数据延时也会更为明显,所以考虑使用多层级联复制之前,也需要评估数据延时对应用系统的影响。
二、mysql主从复制
主从复制的原理
分为同步复制和异步复制,实际复制架构中大部分为异步复制。 复制的基本过程如下:
1).Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
2).Master接收到来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取制定日志指定位置之后的日志信息,返回给Slave 的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置;
3).Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”;
4).Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,然后回放。
安装配置
主服务器master:192.168.1.30
从服务器slave:192.168.1.25
master配置
my.cnf
#bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=7 binlog-ignore-db = mysql,information_schema,performance_schema server_id=1 binlog-do-db=abc
授权
GRANT REPLICATION SLAVE ON abc.* to 'sync'@'192.168.1.30' identified by '123456'
slave配置
server-id=131 #从服务器ID号,不要和主ID相同 master-host=192.168.1.30 #指定主服务器IP地址 master-user=sync #指定在主服务器上可以进行同步的用户名 master-password=123456 #密码 master-port=3306 # 同步所用端口 master-connect-retry=60 #断点从新连接时间 replicate-ignore-db=information_schema,mysql,performance_schema #屏蔽对mysql库的同步 replicate-do-db=abc #同步的数据库的名称 replicate_do_table = tt #同步的数据表的名称
授权
change master to master_host='192.168.1.30', master_port=3306, master_user='sync', master_password='123456', master_log_file='mysql_bin.000041', master_log_pos=538;
启动slave
mysql> start slave; mysql> show slave statusG *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.30 Master_User: sync Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql_bin.000042 Read_Master_Log_Pos: 120 Relay_Log_File: mysql-relay-bin.000004 Relay_Log_Pos: 283 Relay_Master_Log_File: mysql_bin.000042 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 120 Relay_Log_Space: 710 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: 7789d104-20d3-11e5-a394-0050563accdf Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (0.00 sec)
mysql replication单表或多表复制时需注意的几个问题
1.主库和从库的数据库名必须相同;
2.主库和从库的复制可以精确到表,但是在需要更改主库或从库的数据结构时需要立刻重启slave;
3.不能在mysql配置文件里直接写入master的配置信息,需要用change master命令来完成;
4.指定replicate_do_db必须在my.cnf里配置,不能用change master命令来完成;
5.如果不及时清理,日积月累二进制日志文件可能会把磁盘空间占满,可以在配置文件里加上expire_logs_days=7,只保留最近7天的日志,建议当slave不再使用时,通过reset slave来取消relaylog;
最后,编写一shell脚本,用nagios监控slave的两个“yes”,如发现只有一个或零个“yes”,就表明主从有问题了,发报警短信
三、MySQL-MMM
工作原理
MMM(Master-Master replication managerfor Mysql,Mysql主主复制管理器)是一套灵活的脚本程序,基于perl实现,用来对mysql replication进行监控和故障迁移,并能管理mysql Master-Master复制的配置(同一时间只有一个节点是可写的)。
-
mmm_mond:监控进程,负责所有的监控工作,决定和处理所有节点角色活动。此脚本需要在监管机上运行
-
mmm_agentd:运行在每个mysql服务器上的代理进程,完成监控的探针工作和执行简单的远端服务设置。此脚本需要在被监管机上运行
-
mmm_control:一个简单的脚本,提供管理mmm_mond进程的命令
mysql-mmm的监管端会提供多个虚拟IP(VIP),包括一个可写VIP,多个可读VIP,通过监管的管理,这些IP会绑定在可用mysql之上,当某一台mysql宕机时,监管会将VIP迁移至其他mysql。
在整个监管过程中,需要在mysql中添加相关授权用户,以便让mysql可以支持监理机的维护。授权的用户包括一个mmm_monitor用户和一个mmm_agent用户,如果想使用mmm的备份工具则还要添加一个mmm_tools用户。
优缺点
-
优点:高可用性,扩展性好,出现故障自动切换,对于主主同步,在同一时间只提供一台数据库写操作,保证的数据的一致性
-
缺点:Monitor节点是单点,可以结合Keepalived实现高可用
数据库分配
monitor 192.168.1.29 master-1 192.168.1.25 master-2 192.168.1.26 slave 1 192.168.1.27 slave 2 192.168.1.28 VIP writer 192.168.0.31 reader 192.168.0.32 reader 192.168.0.33
统一授权
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'192.168.1.%' IDENTIFIED BY 'replication';
master-1配置192.168.1.25
[mysqld] #bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=0 log_slave_updates #当一个主故障,另一个立即接管 sync-binlog=1 #每条自动更新,安全性高,默认是0 #relay_log relay_log = mysql-relay-bin #replicate server_id=1 binlog-do-db=abc #需要记录二进制日志的数据库,多个用逗号隔开 binlog-ignore-db=mysql,information_schema,performance_schema #不需要记录二进制日志的数据库,多个用逗号隔开 auto_increment_increment=1 #字段一次递增多少 auto_increment_offset=1 #自增字段的起始值,值设置不同 replicate-do-db=abc #同步的数据库,多个写多行 replicate-ignore-db = information_schema #不同步的数据库,多个写多行 replicate-ignore-db = mysql #不同步的数据库,多个写多行
授权
change master to master_host='192.168.1.26', master_user='replication', master_password='replication', master_log_file='mysql-bin.000006', master_log_pos=120;
master-2配置192.168.1.26
[mysqld] #bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=0 log_slave_updates #当一个主故障,另一个立即接管 sync-binlog=1 #每条自动更新,安全性高,默认是0 #relay_log relay_log = mysql-relay-bin #replicate server_id=2 binlog-do-db=abc #需要记录二进制日志的数据库,多个用逗号隔开 binlog-ignore-db=mysql,information_schema,performance_schema #不需要记录二进制日志的数据库,多个用逗号隔开 auto_increment_increment=1 #字段一次递增多少 auto_increment_offset=1 #自增字段的起始值,值设置不同 replicate-do-db=abc #同步的数据库,多个写多行 replicate-ignore-db = information_schema #不同步的数据库,多个写多行 replicate-ignore-db = mysql #不同步的数据库,多个写多行
授权
change master to master_host='192.168.1.25', master_user='replication', master_password='replication', master_log_file='mysql-bin.000009', master_log_pos=220;
可能会出现的问题
1、Slave_IO_Running = NO ,Slave I/O: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file', Error_code: 1236
2、Slave_SQL_Running=NO ,Error 'Can't create database 'abc'; database exists' on query. Default database: 'abc'. Query: 'create database abc'
3、授权失败
主主同步配置完毕,查看同步状态Slave_IO和Slave_SQL是YES说明主主同步成功
slave-1和slave-2做为master-1的从库
change master to master_host='192.168.1.25', master_user='replication', master_password='replication', master_log_file='mysql-bin.000002', master_log_pos=434;
在slave1和slave2查看如下说明主从复制成功。但是数据没过来,这是因为主从复制原理只同步配置完后的增删改记录,以前的数据是不能同步的,我们可以把主的数据库备份了,然后再还原
mysql> show slave status G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.25 Master_User: replication Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql_bin.000009 Read_Master_Log_Pos: 410 Relay_Log_File: mysql-relay-bin.000012 Relay_Log_Pos: 283 Relay_Master_Log_File: mysql_bin.000009 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: abc Replicate_Ignore_DB: information_schema,mysql Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 410 Relay_Log_Space: 725 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 2 Master_UUID: fc4e74ed-563f-11e5-bff1-000c29ee3b5c Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0
MySQL-MMM安装配置
CentOS 默认没有 mysql-mmm 软件包,官方推荐使用 epel 的网络源,五台都安装epel:
rpm -ivh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
monitor节点安装
yum -y install mysql-mmm-monitor
db节点安装
yum -y install mysql-mmm-agent
db节点授权monitor访问
GRANT REPLICATIONCLIENT ON *.* TO 'mmm_monitor'@'192.168.1.%' IDENTIFIED BY '123456'; GRANT SUPER,REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'192.168.1.%' IDENTIFIED BY '123456';
mmm_common.conf文件(五台相同)
active_master_role writer <host default> cluster_interface eth0 pid_path /var/run/mysql-mmm/mmm_agentd.pid bin_path /usr/libexec/mysql-mmm/ replication_user replication replication_password replication agent_user mmm_agent agent_password agent </host> <host db1> ip 192.168.1.25 mode master peer db2 </host> <host db2> ip 192.168.0.26 mode master peer db1 </host> <host db3> ip 192.168.0.27 mode slave </host> <host db4> ip 192.168.0.28 mode slave </host> <role writer> hosts db1, db2 ips 192.168.1.31 mode exclusive #只有一个host可以writer </role> <role reader> hosts db3, db4 ips 192.168.1.32,192.168.1.33 mode balanced #多个host可以reader </role>
db端 mmm_agent.conf
include mmm_common.conf this db1 #分别修改为本机的主机名,即db1、db2、db3和db4
管理端mmm_mon.conf文件
include mmm_common.conf <monitor> ip 127.0.0.1 pid_path /var/run/mysql-mmm/mmm_mond.pid bin_path /usr/libexec/mysql-mmm status_path /var/lib/mysql-mmm/mmm_mond.status ping_ips 192.168.1.25,192.168.1.26,192.168.1.27,192.168.0.28 #真实数据库IP,来检测网络是否正常 auto_set_online 10 #恢复后自动设置在线的时间 </monitor> <host default> monitor_user mmm_monitor monitor_password monitor </host> debug 0
启动MySQL-MMM
db代理端启动
/etc/init.d/mysql-mmm-agent start chkconfigmysql-mmm-agent on
monitor管理端启动
/etc/init.d/mysql-mmm-monitor start chkconfigmysql-mmm-monitor on
查看集群状态
[root@localhost ~]# mmm_control show
四、Master-Slave增加从库的两种方式
现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库。前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作
一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长。另一种是通过xtrabackup工具备份主库,恢复到从库,xtrabackup是物理备份,备份速度快,不锁表。为什么不锁表?因为自身会监控主库日志,如果有更新的数据,就会先写到一个文件中,然后再回归到备份文件中,从而保持数据一致性。
服务器信息:
主库:192.168.1.42
从库1:192.168.1.43
从库2:192.168.1.44(new)
1、mysqldump方式
备份主库
mysqldump --routines --single_transaction --master-data=2 --databases test > test.sql //--routines:导出存储过程和函数 //--single_transaction:导出开始时设置事务隔离状态,并使用一致性快照开始事务,然后unlock tables;而lock-tables是锁住一张表不能写操作,直到dump完毕。 //--master-data:默认等于1,将dump起始(change master to)binlog点和pos值写到结果中,等于2是将change master to写到结果中并注释。
从库配置
mysql -e'create database test' mysql test < test.sql //在备份文件test.sql查看binlog和pos值 head -25 test.sql //--CHANGEMASTERTOMASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=107; 从库设置从这个日志点同步,并启动 mysql>change master to master_host='192.168.1.42', ->master_user='replication', ->master_password='replication', ->master_log_file='mysql-bin.000001', ->master_log_pos=107; mysql>start slave; mysql>show slave status G 看到IO和SQL线程均为YES,说明主从配置成功。
2、xtrabackup方式
使用xtrabackup备份主库
innobackupex ./ //生成一个以时间为命名的备份目录:2015-11-01_15-49-43 //把备份目录拷贝到从库上
从库配置
//先删除掉从库配置 mysql>stop slave; mysql>reset slave; mysql>drop database test; //从库上把MySQL服务停掉,删除datadir目录,将备份目录重命名为datadir目录 //从备份目录中xtrabackup_info文件获取到binlog和pos位置 cat xtrabackup_info //从库设置从这个日志点同步,并启动
参考文章
http://lizhenliang.blog.51cto.com/7876557/1612800
http://www.kuqin.com/shuoit/20151130/349215.html