分类: Mysql/postgreSQL
MYSQL管理之主从同步管理
MYSQL主从同步架构是目前使用最多的数据库架构之一,尤其是负载比较大的网站,因此对于主从同步的管理也就显得非常重要,新手往往在出现主从同步错误的时候不知道如何入手,这篇文章就是根据自己的经验来详细叙述mysql主从的管理。
MYSQL主从同步的作用
(1) 数据分布
(2) 负载平衡(load balancing)
(3) 备份
(4) 高可用性(high availability)和容错
MYSQL主从同步的原理
关于MYSQL的主从同步,最主要的是要了解MYSQL的主从同步是如何工作的也即主从同步的原理,通过下图能很明白的指导其工作的过程:
大致描述一下过程:从服务器的IO线程从主服务器获取二进制日志,并在本地保存为中继日志,然后通过SQL线程来在从上执行中继日志中的内容,从而使从库和主库保持一致。主从同步的详细过程如下:
1. 主服务器验证连接。
2. 主服务器为从服务器开启一个线程。
3. 从服务器将主服务器日志的偏移位告诉主服务器。
4. 主服务器检查该值是否小于当前二进制日志偏移位。
5. 如果小于,则通知从服务器来取数据。
6. 从服务器持续从主服务器取数据,直至取完,这时,从服务器线程进入睡眠,主服务器线程同时进入睡眠。
7. 当主服务器有更新时,主服务器线程被激活,并将二进制日志推送给从服务器,并通知从服务器线程进入工作状态。
8. 从服务器SQL线程执行二进制日志,随后进入睡眠状态。
MYSQL主从同步的搭建实战
主从同步的搭建是一项比较细的技术活,前期做好了一些事情会让你在以后的工作中减少很多工作,搭建的时候需要注意一些问题,一会搭建的时候会一边搭建一边介绍需要注意的问题,让初学者能在刚开始的时候就有效的规避掉一些潜在的问题(MYSQL安装这里不做介绍):
1. 主从同步环境介绍
操作系统环境:linux
MYSQL版本:MYSQL 5.5
主服务器的IP:10.112.142.5
从服务器的IP:10.112.142.6
2. 在主服务器上建立同步帐号
GRANT REPLICATION SLAVE,FILE ON *.* TO 'pay_center'@'10.112.142.6' IDENTIFIED BY '123456';
FLUSH PRIVILEGES;
注意:大家在设置权限的时候不要将密码设置过于简单!
3. 从服务器配置文件的更改
server-id = 2
replicate-wild-ignore-table=mysql.%
log-slave-updates #这个有需要可以开启
注意:
1) server-id这一项需要认真检查,一定不能和主服务器冲突了,不然到时候会出现莫民其妙的问题,因为同步的时候会会根据server-id做判断,如果server-id一样就不进行同步了,不然可能会导致死循环(主主同步或者环状同步的时候)。
2) 有的人会感觉奇怪我这里为什么要使用replicate-wild-ignore-table参数,而不是用replicate-do-db或者replicate-ignore-db来过滤需要同步的数据库和不需要同步的数据库。这里有几个原因:
A. replicate-wild-ignore-table参数能同步所有跨数据库的更新,比如replicate-do-db或者replicate-ignore-db不会同步类似
use mysql;
UPDATE test.aaa SET amount=amount+10;
B. replicate-wild-ignore-table=mysql.%在以后需要添加同步数据库的时候能方便添加而不需要重新启动从服务器的数据库。因为以后很可能需要同步其他的数据库。
3) auto_increment_increment和auto_increment_offset参数,这两个参数一般用在主主同步中,用来错开自增值, 防止键值冲突。
4) --slave-skip-errors参数,不要胡乱使用这些跳过错误的参数,除非你非常确定你在做什么。当你使用这些参数时候,MYSQL会忽略那些错误,这样会导致你的主从服务器数据不一致。
4. 从主服务器得到一个快照版本
如果你的是MYISAM或者既有MYISAM又有INNODB的话就在主服务器上使用如下命令导出服务器的一个快照:
mysqldump -uroot -p --lock-tables --events --triggers --routines --flush-logs --master-data=2 --databases test > db.sql
这一句是很有用的 --locl-tables :导出时所表,--events 会把所有创建的事件也倒出来,--triggers:这个是事务,--routines:这个是 存储过程和存储方法,--flush-log:意思是说导出时 先刷新下binglog日志,--master-data=2时 导出的文件里 change master 是被注视掉的 ,等于1时不是注视的,这个根据自己的要求改,一般都会选择2因为在从服务器上得 change 一下 主服务器的 ip 端口 主服务器的账号 密码
试过只有INNODB的话就是用如下命令:
mysqldump -uroot -p --single-transaction --events --triggers --routines --flush-logs --master-data=2 --databases test > db.sql
这里需要注意几个参数的使用:
--single-transaction 这个参数只对innodb适用。
--databases 后面跟除mysql以后的其他所有数据库的库名,我这里只有一个test库。
--master-data 参数会记录导出快照时候的mysql二进制日志位置,一会会用到。
5. 将快照版本还原到从服务器上
mysqldump -uroot -p -h 10.1.1.76 test < db.sql
将快照版本还原到从服务器上以后,此时从服务器上的数据和主服务器的数据是一致的。
6. 在从服务器上使用change master从主服务器上同步
使用grep命令查找到二进制日志的名称以及位置
[root@ns1 ~]# grep -i "change master" db.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=106;
生成CHANGE MASTER语句,然后在从上执行
STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='10.112.142.5',MASTER_USER='pay_cener',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=106;
START SLAVE;
这样就完成了主从同步的搭建,最后使用SHOW SLAVE STATUS\G;查看Slave_IO_Running和Slave_SQL_Running的状态,如果都为Yes,就大功告成了。
注意:不要将同步的信息写入配置文件中,不方便管理,尤其是有变动需要重启。
MYSQL主从同步的管理
这里介绍一些管理MYSQL主从同步的命令:
1. 停止MYSQL同步
STOP SLAVE IO_THREAD; #停止IO进程
STOP SLAVE SQL_THREAD; #停止SQL进程
STOP SLAVE; #停止IO和SQL进程
2. 启动MYSQL同步
START SLAVE IO_THREAD; #启动IO进程
START SLAVE SQL_THREAD; #启动SQL进程
START SLAVE; #启动IO和SQL进程
3. 重置MYSQL同步
RESET SLAVE;
用于让从属服务器忘记其在主服务器的二进制日志中的复制位置, 它会删除master.info和relay-log.info文件,以及所有的中继日志,并启动一个新的中继日志,当你不需要主从的时候可以在从上执行这个操作。不然以后还会同步,可能会覆盖掉你的数据库,我以前就遇到过这样傻叉的事情。哈哈!
4. 查看MYSQL同步状态
SHOW SLAVE STATUS;
这个命令主要查看Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master、Last_IO_Error、Last_SQL_Error这些值来把握复制的状态。
5. 临时跳过MYSQL同步错误
经常会朋友mysql主从同步遇到错误的时候,比如一个主键冲突等,那么我就需要在确保那一行数据一致的情况下临时的跳过这个错误,那就需要使用SQL_SLAVE_SKIP_COUNTER =n命令了,n是表示跳过后面的n个事件,比如我跳过一个事件的操作如下:
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
6. 从指定位置重新同步
有的时候主从同步有问题了以后,需要从log位置的下一个位置进行同步,相当于跳过那个错误,这时候也可以使用CHANGE MASTER命令来处理,只要找到对应的LOG位置就可以,比如:
CHANGE MASTER TO MASTER_HOST='10.1.1.75',MASTER_USER='replication',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=106;
START SLAVE;
MYSQL主从同步的管理经验介绍
1. 不要乱使用SQL_SLAVE_SKIP_COUNTER命令。
这个命令跳过之后很可能会导致你的主从数据不一致,一定要先将指定的错误记录下来,然后再去检查数据是否一致,尤其是核心的业务数据。
2. 结合percona-toolkit工具pt-table-checksum定期查看数据是否一致。
这个是DBA必须要定期做的事情,呵呵,有合适的工具何乐而不为呢?另外percona-toolkit还提供了对数据库不一致的解决方案,可以采用pt-table-sync,这个工具不会更改主的数据。还可以使用pt-heartbeat来查看从服务器的复制落后情况。具体的请查看:http://blog.chinaunix.net/uid-20639775-id-3229211.html。
3. 使用replicate-wild-ignore-table选项而不要使用replicate-do-db或者replicate-ignore-db。
原因已经在上面做了说明。
4. 将主服务器的日志模式调整成mixed。
5. 每个表都加上主键,主键对数据库的同步会有影响尤其是居于ROW复制模式。
1.前言
日志是把数据库的每一个变化都记载到一个专用的文件里,这种文件就叫做日志文件。Mysql默认只打开出错日志,因为过多的日志将会影响系统的处理性能。
在5.0前支持文本格式和二进制格式,5.0后只支持二进制格式,因为二进制日志在性能、信息处理方面有更多的优点。
2.基础知识
2.1、二进制日志的启用
二进制日志由配置文件的log-bin选项负责启用,Mysql服务器将在数据根目录创建两个新文件XXX-bin.001和XXX-bin.index,若配置选项没有给出文件名,Mysql将使用主机名称命名这两个文件,其中.index文件包含一份全体日志文件的清单。
Mysql会把用户对所有数据库的内容和结构的修改情况记入XXX-bin.n文件,而不会记录SELECT和没有实际
2.2、更新的UPDATE语句。
日志文件的扩展
当停止或重启时,服务器会把日志文件记入下一个日志文件,Mysql会在重启时生成一个新的日志文件,文件序号递增,此外,如果日志文件超过max_binlog_size系统变量配置的上限时,也会生成新的日志文件。
2.3、日志文件的查看
Mysql提供了mysqlbinlog命令来查看日志文件,如mysqlbinlog xxx-bin.001 | more。在记录每条变更日志的时候,日志文件都会把当前时间给记录下来,以便进行数据库恢复。 【查看 relaylog日志 也是用 mysqlbinlog , 这个文件就是个中转文件,从主读过来后再写到这个文件 然后从服务器在从这个文件里读出来进行执行】
binlog 和 relaylog 内容都是 用 mysqlbinlog 去显示【他们的内容很相似,可以自己去看下】
relay-log日志记录的是在复制过程中,从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器
例如:
VM_141_21_sles10_64:/data/Chunbai/app/mysql/data/mysql/3306/relaylog # /data/Chunbai/app/mysql/bin/mysqlbinlog ./relaylog.000006 | more
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#140529 12:53:31 server id 2 end_log_pos 107 Start: binlog v 4, server v 5.5.3-m3-log created 140529 12:53:31
BINLOG '
S72GUw8CAAAAZwAAAGsAAAAAAAQANS41LjMtbTMtbG9nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAVAAEGggAAAAICAgCAA==
'/*!*/;
# at 107
#140529 12:53:31 server id 1 end_log_pos 0 Rotate to binlog.000013 pos: 4
# at 147
#140529 14:36:02 server id 1 end_log_pos 107 Start: binlog v 4, server v 5.5.3-m3-log created 140529 14:36:02
BINLOG '
UtWGUw8BAAAAZwAAAGsAAAAAAAQANS41LjMtbTMtbG9nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAVAAEGggAAAAICAgCAA==
'/*!*/;
# at 250
#140529 14:36:51 server id 1 end_log_pos 181 Query thread_id=18186 exec_time=0 error_code=0
SET TIMESTAMP=1401345411/*!*/;
SET @@session.pseudo_thread_id=18186/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
2.4、日志文件的停用
可以使用SET SQL_LOG_BIN=0命令停止使用日志文件,然后可以通过SET SQL_LOG_BIN=1命令来启用。
2.5、使用日志进行数据库恢复
如果遇到灾难事件,应该用最近一次制作的完整备份恢复数据库,然后使用备份之后的日志
文件把数据库恢复到最接近现在的可用状态。
使用日志进行恢复时需要依次进行,即最早生成的日志文件要最先恢复:
mysqlbinlog xxx-bin.00001 | mysql -u root -p
mysqlbinlog xxx-bin.00002 | mysql -u root -p
3.日志跟换策略
使用索引来循环文件,在以下条件将循环至下一个索引
a.服务器重启
b.服务器被更新
c.日志达到了最大日志长度max_binlog_size
d.日志被刷新mysql> flush logs;
4.日志格式
从官网文档中看到,之前的MySQL一直都只有基于statement的复制模式,直到5.1.5版本的MySQL才开始支持row level的复制。从5.0开始,MySQL的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给MySQL Replication复制又带来了更大的新挑战。另外,看到官方文档说,从5.1.8版本开始,MySQL提供了除Statement Level和Row Level之外的第三种复制模式:Mixed,实际上就前两种模式的结合。在Mixed模式下,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。新版本中的Statement Level还是和以前一样,仅仅记录执行的语句。而新版本的MySQL中对row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录,如果sql语句确实就是update或者delete等修改数据的语句,那么还是会记录所有行的变更。
--基于SQL语句的复制(statement-based replication,SBR),
--基于行的复制(row-based replication,RBR),
--混合模式复制(mixed-based replication,MBR)。
静态设置binlog格式:
vi my.cnf log-bin = mysql-bin #binlog_format = "STATEMENT" #binlog_format = "ROW" binlog_format = "MIXED"
动态修改binlog格式:
mysql> SET SESSION binlog_format = 'STATEMENT'; mysql> SET SESSION binlog_format = 'ROW'; mysql> SET SESSION binlog_format = 'MIXED'; mysql> SET GLOBAL binlog_format = 'STATEMENT'; mysql> SET GLOBAL binlog_format = 'ROW'; mysql> SET GLOBAL binlog_format = 'MIXED';
5.binary log相关变量和参数
5.1、命令行参数
--log-bin [=file_name]
设置此参数表示启用binlog功能,并制定路径名称。
--log-bin-index[=file]
设置此参数是指定二进制索引文件的路径与名称。
--max_binlog_size
Binlog最大值,最大和默认值是1GB,该设置并不能严格控制Binlog的大小,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,
为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束。
--binlog-do-db=db_name
此参数表示只记录指定数据库的二进制日志
--binlog-ignore-db=db_name
此参数表示不记录指定的数据库的二进制日志
5.2、系统变量
log_bin
binlog_cache_size
此参数表示binlog使用的内存大小,可以通过状态变量binlog_cache_use和binlog_cache_disk_use来帮助测试。
max_binlog_cache_size
此参数表示binlog使用的内存最大的尺寸
binlog_cache_use
使用二进制日志缓存的事务数量
binlog_cache_disk_use
使用二进制日志缓存但超过binlog_cache_size值并使用临时文件来保存事务中的语句的事务数量。
binlog_do_db
binlog_ignore_db
sync_binlog
这个参数直接影响mysql的性能和完整性。
sync_binlog=0:
当事务提交后,Mysql仅仅是将binlog_cache中的数据写入binlog文件,但不执行fsync之类的磁盘,同步指令通知文件系统将缓存刷新到磁盘,而让Filesystem自行决定什么时候来做同步,这个是性能最好的。
sync_binlog=0,在进行n次事务提交以后,Mysql将执行一次fsync之类的磁盘同步指令,通知文件系统将Binlog文件缓存刷新到磁盘。
Mysql中默认的设置是sync_binlog=0,即不做任何强制性的磁盘刷新指令,这时性能是最好的,但风险也是最大的。一旦系统Crash,在文件系统缓存中的所有Binlog信息都会丢失。
6.常见问题
6.1、如何清除binlog
--使用下面的两个命令
PURGE {MASTER|BINARY} LOGS TO 'log_name' //log_name不会被清除
PURGE {MASTER|BINARY} LOGS BEFORE 'date' //date不会被清除
实例如下:
mysql> show master logs; +----------------------+-----------+ | Log_name | File_size | +----------------------+-----------+ | mysql3306-bin.000001 | 107 | +----------------------+-----------+ 1 row in set (0.00 sec) mysql> flush logs; Query OK, 0 rows affected (0.11 sec) mysql> flush logs; Query OK, 0 rows affected (0.02 sec) mysql> flush logs; Query OK, 0 rows affected (0.01 sec) mysql> flush logs; Query OK, 0 rows affected (0.01 sec) mysql> show master logs; +----------------------+-----------+ | Log_name | File_size | +----------------------+-----------+ | mysql3306-bin.000001 | 154 | | mysql3306-bin.000002 | 154 | | mysql3306-bin.000003 | 154 | | mysql3306-bin.000004 | 154 | | mysql3306-bin.000005 | 107 | +----------------------+-----------+ 5 rows in set (0.00 sec) mysql> purge master logs to 'mysql3306-bin.000002'; Query OK, 0 rows affected (0.01 sec) mysql> show master logs; +----------------------+-----------+ | Log_name | File_size | +----------------------+-----------+ | mysql3306-bin.000002 | 154 | | mysql3306-bin.000003 | 154 | | mysql3306-bin.000004 | 154 | | mysql3306-bin.000005 | 107 | +----------------------+-----------+ 4 rows in set (0.00 sec)
[root@node4 data]# date Tue Jul 30 01:27:04 CST 2013 mysql> flush logs; Query OK, 0 rows affected (0.01 sec) mysql> show master logs; +----------------------+-----------+ | Log_name | File_size | +----------------------+-----------+ | mysql3306-bin.000002 | 154 | | mysql3306-bin.000003 | 154 | | mysql3306-bin.000004 | 154 | | mysql3306-bin.000005 | 154 | | mysql3306-bin.000006 | 107 | +----------------------+-----------+ 5 rows in set (0.00 sec) mysql> purge master logs before '2013-07-30 01:27:04'; Query OK, 0 rows affected (0.02 sec) mysql> show master logs; +----------------------+-----------+ | Log_name | File_size | +----------------------+-----------+ | mysql3306-bin.000005 | 154 | | mysql3306-bin.000006 | 107 | +----------------------+-----------+ 2 rows in set (0.00 sec)
--或使用命令:
RESET MASTER
删除之前所有的binlog,并重新生成新的binlog,后缀从000001开始。
注:如果您有一个活性的从属服务器,该服务器当前正在读取您正在试图删除的日志之一,则本语句不会起作用,而是失败,并伴随一个错误。
不过,如果从属服务器是休止的,并且您碰巧清理了其想要读取的日志之一,则从属服务器启动后不能复制。
当从属服务器正在复制时,本语句可以安全运行。您不需要停止它们。
6.2、记录到二进制日志知的内容配置
binlog-do-db=sales 只记录sales库 binlog-ignore-db=sales 除sales库不记录,其他都记录。
但是如果在操作数据库之前,不使用use $dbname 那么所有的SQL都不会记录 如果使用了use $dbname,那么判断规则取决于这里的$dbname,而不是SQL中操作的库
6.3、二进制日志不准确的处理
默认情况下,并不是每次写入时都将二进制日志与硬盘同步。因此如果操作系统或机器(不仅仅是MySQL服务器)崩溃,有可能二进制日志中最后的语句丢失。 要想防止这种情况,你可以使用sync_binlog全局变量(1是最安全的值,但也是最慢的),使二进制日志在每N次二进制日志写入后与硬盘同步。 即使sync_binlog设置为1,出现崩溃时,也有可能表内容和二进制日志内容之间存在不一致性。
如果崩溃恢复时MySQL服务器发现二进制日志变短了(即至少缺少一个成功提交的InnoDB事务), 如果sync_binlog =1并且硬盘/文件系统的确能根据需要进行同步(有些不需要)则不会发生,则输出错误消息 (“二进制日志<名>比期望的要小”)。 在这种情况下,二进制日志不准确,复制应从主服务器的数据快照开始。 为了您的安全,请只打开来源可靠的网址