该过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。mysql将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。
下一步就是slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——i/o线程。i/o线程在master上打开一个普通的连接,然后开始binlog dump process。binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。i/o线程将这些事件写入中继日志。
sqlslave thread(sql从线程)处理该过程的最后一步。sql线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与i/o线程保持一致,中继日志通常会位于os的缓存中,所以中继日志的开销很小。
此外,在master中也有一个工作线程:和其它mysql的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制 过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。
2,mysql主从同步应用场景(1):数据分布
(2):负载均衡
(3):备份
(4):高可用和容错
3,搭建mysql主从的环境要求主从系统要保持一致:包括数据库版本,操作系统版本,磁盘io磁盘容量,网络带宽等。
[root@data02 ~]# cat /etc/redhat-release
centos release 6.2 (final)
[root@data02 ~]#
主库master
从库slave
os系统版本
centos release 6.2 (final)
centos release 6.2 (final)
数据库版本
5.6.12-log
5.6.12-log
磁盘容量
50g
30g
主机ip地址
192.168.52.129
192.168.52.130
端口
3306
3306
内存
1g
1g
服务器类型
虚拟机
虚拟机
4,开始搭建mysql主从复制4.1建立复制账号
grant replication slave,reload,super on *.*to repl@'192.168.52.130' identified by 'repl_1234';
建立一个复制账号,只允许从192.168.52.130上来访问登录主库进行二进制日志传输同步。ps:如果mysql版本新旧密码算法不同,可以设置set password for 'backup'@'10.100.0.200'=old_password('1234'))
4.2 手动同步数据因为当开始搭建的时候,主库上已经有了数据,所以要先把主库已经存在的数据先手动同步迁移到从库上面去。搭建过程中,禁止在主库从库上进行任何对数据库的ddl、dml等数据操作。
这里可以用mysqldump也可以用xtrabackup导出主库上面的数据:
(4.2.1):xtrabackup方式在主库上192.168.52.129上面进行数据备份,备份命令,要添加--safe-slave-backup参数:
innobackupex --user=backup--password=123456 --host=192.168.52.129 --socket=/tmp/mysql.sock--defaults-file=/etc/my.cnf /data/backups/mysql/repl/backup_slave --parallel=3--safe-slave-backup --no-timestamp
去备份目录/data/backups/mysql/repl/backup_slave查看备份时候的主库二进制信息,需要根据这个二进制信息来进行数据同步,如下所示:
[root@data01 test]# cd/data/backups/mysql/repl/backup_slave
[root@data01 backup_slave]# more xtrabackup_binlog_info
mysql-bin.000147 120
[root@data01 backup_slave]#
压缩备份文件并且传输到从库192.168.52.130上面:
tar -zcvf backup_slave.tar.gz backup_slave/
scp backup_slave.tar.gz192.168.52.130:/tmp/
(4.2.2)mysqldump方式在主库上192.168.52.129上做基于主库做数据备份
/usr/local/mysql/bin/mysqldump -ubackup--password=123456 --host=192.168.52.129 --single-transaction --flush-logs --master-data=2 --add-drop-table--create-option --quick --extended-insert=false --set-charset --disable-keys -a> /tmp/alldb.sql
压缩备份文件,传输到从库192.168.52.130上面去。
gzip /tmp/alldb.sql
scp /tmp/alldb.sql.gz 192.168.52.130:/tmp/
4.3 配置master库(192.168.52.129)vim /etc/my.cnf
server-id=129 # server id
log-bin =/home/data/mysql/binlog/mysql-bin
binlog-ignore-db=mysql # no sync databases
binlog-ignore-db=test # no sync databases
binlog-ignore-db=information_schema # no sync databases
binlog-ignore-db=performance_schema
binlog-do-db=user_db
保存退出,重启mysql主库,可以查看主库的状态,如下:
mysql> show master status;+------------------+----------+--------------+--------------------------------------------------+-------------------+| file | position | binlog_do_db |binlog_ignore_db | executed_gtid_set |+------------------+----------+--------------+--------------------------------------------------+-------------------+| mysql-bin.000151 | 120 | user_db |mysql,test,information_schema,performance_schema | |+------------------+----------+--------------+--------------------------------------------------+-------------------+1 row in set (0.00 sec)mysql>mysql> show master status\g;*************************** 1. row***************************file: mysql-bin.000151position: 120binlog_do_db: user_dbbinlog_ignore_db:mysql,test,information_schema,performance_schemaexecuted_gtid_set:1 row in set (0.00 sec)error:no query specifiedmysql>
4.4 配置slave从库(192.168.52.130)slave的配置与master库类似,如下所示:
vim /etc/my.cnf#------------------master-slaveconfig-----------------log-slave-updates=1replicate-same-server-id=0server-id=230 # server idlog-bin=/home/data/mysql/binlog/mysql-bin.logrelay-log=mysql-relay-binmaster-info-repository=tablerelay-log-info-repository=tablebinlog-ignore-db=mysql # no sync databasesbinlog-ignore-db=test # no sync databasesbinlog-ignore-db=information_schema # no sync databasesbinlog-ignore-db=performance_schemabinlog-do-db=user_dbexpire-logs-days=10max_binlog_size = 10485760
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上创建表的应用。
配置玩,重启slave数据库
mysql> show slave status;empty set (0.05 sec)mysql>
没有记录,需要设置一些主从配置。
4.5 设置主从连接复制生成change master语句,然后在从上执行,master信息,从备份集合里面获取:
xtrabackup备份的话,从xtrabackup_binlog_info里面获取,如下所示:
[root@data02 tmp]#tar -xvfbackup_slave.tar.gz[root@data02 tmp]#cd backup_slave[root@data02 backup_slave]# morextrabackup_binlog_infomysql-bin.000141 120[root@data02 backup_slave]#
mysqldump的啊,从sql文件的头几列获取,如下所示:
[root@data02 tmp]#cd /tmp/[root@data02 tmp]#gunzip alldb.sql.gz[root@data02 tmp]# more alldb.sql |grepchange master to master_log_file |grep master_log_pos|more-- change master to master_log_file='mysql-bin.000141',master_log_pos=120;
生成changemaster语句,如下:
change master to master_host='192.168.52.129',
master_user='repl',
master_password='repl_1234',
master_log_file='mysql-bin.000141',
master_log_pos=120;
有报错信息:
mysql> change master to master_host='192.168.52.129',
-> master_user='repl',
-> master_password='repl_1234',
-> master_log_file='mysql-bin.000141',
-> master_log_pos=120;
error 1794 (hy000): slave is not configuredor failed to initialize properly. you must at least set --server-id to enableeither a master or a slave. additional error messages can be found in the mysqlerror log.
mysql>
具体原因目前不详,网上查找到的资料:数据库打开这几张表的默认引擎为myisam,但是这几张表在建表时的引擎为innodb
但是能确定的,这几张表确实是在mysql5.6中新入的
innodb_index_stats,
innodb_tables_stats,
slave_master_info,
slave_relay_log_info,
slave_worker_info
解决方法:
登录数据库,进入mysql库,执行如下sql删除5张表
记住,一定要是drop table if exists
drop table if exists innodb_index_stats;
drop table if exists innodb_table_stats;
drop table if exists slave_master_info;
drop table if exists slave_relay_log_info;
drop table if exists slave_worker_info;
执行完后,可以用show tables查看一下,看表的数据是否已经比删除之前减少了,如果减少了,说明你成功了!
[root@data02 test] cd/home/data/mysql/data/mysql
[root@data02 mysql]# ll *.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 innodb_index_stats.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 innodb_table_stats.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_master_info.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_relay_log_info.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_worker_info.ibd
[root@data02 mysql]#
强行删除ibd文件:
[root@data02 mysql]# rm -f *.ibd
重启数据库,登录mysql
source/usr/test/mysql/share/mysql_system_tables.sql
show tables;
发现表已经回来了,表数据大概总数量为28个。
之后执行change master to,ok,搞定,如下所示:
mysql> stop slave;
query ok, 0 rows affected, 1 warning (0.03sec)
mysql> change master tomaster_host='192.168.52.129',master_user='repl',master_password='repl_1234',master_log_file='mysql-bin.000141',master_log_pos=120;
query ok, 0 rows affected, 2 warnings (0.07sec)
mysql>
启动slave
mysql> start slave;
query ok, 0 rows affected (0.02 sec)
mysql>
4.6 验证主从复制状态在slave服务器上查看slave状态:
mysql> show slave status\g
*************************** 1. row***************************
slave_io_state: waiting formaster to send event
master_host: 192.168.52.129
master_user: repl
master_port: 3306
connect_retry: 60
master_log_file: mysql-bin.000151
read_master_log_pos: 346
relay_log_file:mysql-relay-bin.000018
relay_log_pos: 509
relay_master_log_file: mysql-bin.000151
slave_io_running: yes
slave_sql_running: yes
replicate_do_db:business_db,user_db,plocc_system
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: 346
relay_log_space: 845
until_condition: none
这里主要看:
slave_io_running: yes
slave_sql_running: yes
seconds_behind_master: 0
io和sql线程都是yes以及seconds_behind_master是0就表示从库正常运行了。
在master服务器上查看:
mysql> show full processlist;
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
| id | user | host | db | command | time | state |info |
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
| 1| event_scheduler | localhost | null | daemon | 5874 |waiting on empty queue | null |
| 21 | root | localhost | null | query | 0 | init | show full processlist |
| 24 | repl | 192.168.52.130:45665 | null |binlog dump | 88 | master has sent allbinlog to slave; waiting for binlog to be updated | null |
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
3 rows in set (0.03 sec)
mysql>
看到有192.168.52.130:45665的线程在同步二进制数据
4.7 master添加数据验证去master(192.168.52.129)上操作,添加表记录:
mysql> create table master_test select 1as a,'a' as b;
query ok, 1 row affected (0.72 sec)
records: 1 duplicates: 0 warnings: 0
mysql>
去slave(192.168.52.130)上查询下,看表数据是否同步过来,看到数据已经同步过来了,如下所示:
mysql> select * fromuser_db.master_test;
+---+---+
| a | b |
+---+---+
| 1 | a |
+---+---+
1 row in set (0.06 sec)
mysql>
5,如何添加新的slave服务器总结如果master运行很久了,需要添加新的slave服务器,那么搭建新的slave,此时,有几种方法可以使slave从另一个服务开始,例如,从master拷贝数据,从另一个slave克隆,从最近的备份开始一个slave。slave与master同步时,需要三样东西:
(1)master的某个时刻的数据快照;
(2)master当前的日志文件、以及生成快照时的字节偏移。这两个值可以叫做日志文件坐标(log file coordinate),因为它们确定了一个二进制日志的位置,你可以用show master status命令找到日志文件的坐标;
(3)master的二进制日志文件。
也可以通过以下几中方法来克隆一个slave:
(1) 冷拷贝(cold copy)
停止master,将master的文件拷贝到slave;然后重启master。缺点很明显。
(2) 热拷贝(warm copy)
如果你仅使用myisam表,你可以使用mysqlhotcopy拷贝,即使服务器正在运行。
如果有myisam和innodb表,可以在业务低峰期用tar包的方式来热拷贝。
(3) 使用mysqldump
使用mysqldump来得到一个数据快照可分为以下几步:
锁表:如果你还没有锁表,你应该对表加锁,防止其它连接修改数据库,否则,你得到的数据可以是不一致的。如下:
mysql> flush tables with read lock;
在另一个连接用mysqldump创建一个你想进行复制的数据库的转储:
见4.2.1小节
对表释放锁。
mysql> unlock tables;
(4) 使用xtrabackup
使用xtrabackup得到数据快照,见4.2.2小节
6,如何实现mss当设置log_slave_updates时,你可以让slave扮演其它slave的master。此时,slave把sql线程执行的事件写进行自己的二进制日志(binary log),然后,它的slave可以获取这些事件并执行它。如下图6.png所示:
7,复制过滤复制过滤可以让你只复制服务器中的一部分数据,有两种复制过滤:在master上过滤二进制日志中的事件;在slave上过滤中继日志中的事件。如下图7.png所示:
8,常用的mysql主从拓扑结构复制的体系结构有以下一些基本原则:
(1) 每个slave只能有一个master;
(2) 每个slave只能有一个唯一的服务器id;
(3) 每个master可以有很多slave;
(4) 如果你设置log_slave_updates,slave可以是其它slave的master,从而扩散master的更新。
mysql不支持多主服务器复制(multimasterreplication)——即一个slave可以有多个master。但是,通过一些简单的组合,我们却可以建立灵活而强大的复制体系结构。
9,mysql主从同步之间的管理介绍一下基本的mysql主从的管理操作命令:
9.1 停止mysql从服务stop slave io_thread; #停止io进程
stop slave sql_thread; #停止sql进程
stop slave; #停止io和sql进程
9.2 开启mysql主从同步服务start slave io_thread; #启动io进程
start slave sql_thread; #启动sql进程
start slave; #启动io进程和sql进程
9.3 重置mysql主从同步reset slave;
#用于让从属服务器忘记其在主服务器的二进制日志中的复制位置, 它会删除master.info和relay-log.info文件,以及所有的中继日志,并启动一个新的中继日志,当你不需要主从的时候可以在从上执行这个操作。不然以后还会同步,可能会覆盖掉你的数据库。
9.4 查看主从同步状态show slave status;
#这个命令主要查看slave_io_running、slave_sql_running、seconds_behind_master、last_io_error、last_sql_error这些值来把握复制的状态。
9.5 临时跳过mysql同步错误#经常会朋友mysql主从同步遇到错误的时候,比如一个主键冲突等,那么我就需要在确保那一行数据一致的情况下临时的跳过这个错误,那就需要使用sql_slave_skip_counter = n命令了,n是表示跳过后面的n个事件,比如我跳过一个事件的操作如下:
stop slave;
set global sql_slave_skip_counter=1;
start slave;
9.6 从指定位置重新同步数据#有的时候主从同步有问题了以后,需要从log位置的下一个位置进行同步,相当于跳过那个错误,这时候也可以使用change master命令来处理,只要找到对应的log位置就可以,比如:
change master tomaster_host='10.1.1.75',master_user='replication',master_password='123456',master_log_file='mysql-bin.000006',master_log_pos=106;
start slave;
ps:生产环境中这种操作尽量能避免就避免。
10,线上维护mysql主从需要注意的事项1. 不要乱使用sql_slave_skip_counter命令。
这个命令跳过之后很可能会导致你的主从数据不一致,一定要先将指定的错误记录下来,然后再去检查数据是否一致,尤其是核心的业务数据。
2. 结合percona-toolkit工具pt-table-checksum定期查看数据是否一致。
这个是dba必须要定期做的事情,呵呵,有合适的工具何乐而不为呢?另外percona-toolkit还提供了对数据库不一致的解决方案,可以采用pt-table-sync,这个工具不会更改主的数据。还可以使用pt-heartbeat来查看从服务器的复制落后情况。
3. 使用replicate-wild-ignore-table选项而不要使用replicate-do-db或者replicate-ignore-db。
原因已经在上面做了说明。
4. 将主服务器的日志模式调整成mixed。
5. 每个表都加上主键,主键对数据库的同步会有影响尤其是居于row复制模式。
