为什么要主从复制
1,在业务复杂的系统中,有这么一个场景,有一句SQL需要锁表,导致暂时不能使用读的fy一个场景,有一句SQL需要锁表(排它锁),导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运行。
2,做数据的热备,主机当即后能够及时替换主库,保证业务员的可用性。
3,架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做对库的存储,降低磁盘I/O访问的评率,提高单个机器的I/O性能。
MySQL主从复制的流程
1,主库db的更新事件(数据库表结构和内容变更,例如update、insert、delete)被写到binlog。
2,从库启动并发起连接,连接到主库。
3,主库创建一个binlog dump thread,把binlog的内容发送到从库。
4,从库启动后,从库创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log。
5,从库启动后,从库创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db。
MySQL主从复制的原理
Mysql主从复制是一个异步的复制过程,主库发送更新事件到从库,从库读取更新记录,并执行更新记录,是的从库的内容与主库保持一致。
binlog:binary log,主库中保存所有更新事件日志的二进制文件。binlog是数据库服务启动的一刻起,保存数据库所有变更记录(数据库结构和内容)的文件。在主库中,只要有更新事件出现,就会被一次地写入到binlog中,之后会推送到从库进行复的数据源。
binlog输出线程:每当有从库连接到主库的时候,主库都会创建一个线程然后发送binlog内容到从库。对于每一个即将发送给从库的sql事件,binlog输出线程会将其锁住,一旦该事件被线程读取完之后,该锁就会被释放,即使在该事件完全发送到从库的时候,该锁也会被释放。
从库I/O线程:当START SLAVE语句在从库开始执行后,从库创建一个I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库上,从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到一个本地文件,其中包括erlay log文件。
从库的SQL线程:从库创建一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。
binlog三种同步方式
异步方式:MySQL提交事务的线程完全不关心binlog是否已经同步到从库,事务执行完就会返回客户端响应结果,这种模式如果主库宕机,从库数据存在丢失风险。
同步方式:MySQL提交事务的线程会等待所有从库binlog同步成功的响应,这种情况不存在从库数据丢失的情况
半同步方式:MySQL5.7版本之后增加的功能,mysql提交事务的线程不会等待所有从库binlog同步成功的响应,只要有一部分从库同步成功他就会返回客户端相应结果,这种方式也会存在从库丢失数据的风险,但性能又比同步方式高。
综上
对于每一个主从复制的连接,都会有三个线程。拥有多个从库的主库为每一个连接到主库的从库创建一个binlog输出线程,每一个从库都有它自己的I/O线程和SQL线程。
从库通过创建两个独立的线程,使得在进行复制时,从库的读和写进行了分离。因此,即使负责执行写的线程运行较慢,负责读取更新语句的线程并不会一次变得缓慢。比如说,如果从库有一段时间没运行了,当他在启动的时候,尽管他的sql线程执行的比较慢,他的I/O线程可以快读地从主库里读取所有的binlog内容。这样一来,即使从库在SQL线程执行完所有读取到的语句前停止了,I/O线程也至少完全读取了所有的内容,并将其安全地备份在从库本地的relay log,随时准备在从库下一次启动的时候执行语句。
主从配置
1,主从服务器要有相同的初始数据状态,将主库中的数据导出((mysqldump))并导入(source)到从库中,期间要避免主库的数据发生改变。
2,主服务器my.cnf配置
[mysqld]
#主数据库端ID号
server_id = 1
#开启二进制日志
log-bin = mysql-bin
#需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可
binlog-do-db = db
#将从服务器从主服务器收到的更新记入到从服务器自己的二进制日志文件中
log-slave-updates
#控制binlog的写入频率。每执行多少次事务写入一次(这个参数性能消耗很大,但可减小MySQL崩溃造成的损失)
sync_binlog = 1
#这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突
auto_increment_offset = 1
#这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突
auto_increment_increment = 1
#二进制日志自动删除的天数,默认值为0,表示“没有自动删除”,启动时和二进制日志循环时可能删除
expire_logs_days = 7
#将函数复制到slave
log_bin_trust_function_creators = 1
3,重启主MySQL,创建允许从服务器同步的账户,查看主服务器状态,至此,不要操作主库,防止状态值发生变化
#创建slave账号account,密码123456
mysql>grant replication slave on *.* to 'account'@'10.10.20.116' identified by '123456';
#更新数据库权限
mysql>flush privileges;
#查看主库状态
mysql>show master status\G;
***************** 1. row ****************
File: mysql-bin.000033 #当前记录的日志
Position: 337523 #日志中记录的位置
Binlog_Do_DB:
Binlog_Ignore_DB:
4,从库my.cnf配置
[mysqld]
server_id = 2
log-bin = mysql-bin
log-slave-updates
sync_binlog = 0
#log buffer将每秒一次地写入log file中,并且log file的flush(刷到磁盘)操作同时进行。
#该模式下在事务提交的时候,不会主动触发写入磁盘的操作
innodb_flush_log_at_trx_commit = 0
#指定slave要复制哪个库
replicate-do-db = db
#MySQL主从复制的时候,当Master和Slave之间的网络中断,但是Master和Slave无法察觉的情况下(比如防火墙或者路由问题)。
#Slave会等待slave_net_timeout设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据
slave-net-timeout = 60
log_bin_trust_function_creators = 1
5,从库执行同步命令,并查看从库状态
#执行同步命令,设置主服务器ip,同步账号密码,同步位置
mysql>change master to master_host='10.10.20.111',master_user='account',master_password='123456',master_log_file='mysql-bin.000033',master_log_pos=337523;
#开启同步功能
mysql>start slave;
#查看slave状态
mysql>show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.10.20.111
Master_User: account
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000033
Read_Master_Log_Pos: 337523
Relay_Log_File: db2-relay-bin.000002
Relay_Log_Pos: 337686
Relay_Master_Log_File: mysql-bin.000033
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
...
Slave_IO_Running及Slave_SQL_Running进程必须为正常运行,即Yes状态,否则说明同步失败。失败则需要通过mysql错误日志来定位问题。