分析
MySQL数据库自身提供的主从复制功能可以方便的实现数据的多处自动备份,实现数据库的拓展。多个数据备份不仅可以加强数据的安全性,通过实现读写分离还能进一步提升数据库的负载性能。
为什么要做主从复制
- 在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运行。
- 做数据的热备,主库宕机后能够及时替换主库,保证业务可用性。
- 架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
主从复制的流程
- 主库db的更新事件(update、insert、delete)被写到binlog
- 主库创建一个binlog dump thread,把binlog的内容发送到从库
- 从库启动并发起连接,连接到主库
- 从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到 relay log
- 从库启动之后,创建一个SQL线程 ,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db
注:上述流程为相对流程,并非绝对流程
主从的形式
- 一主一从
- 一主多从
- 多主一从
- 双主复制
双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中
- 级联复制
级联复制模式下,部分slave的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于replication,那么我们可以让3~5个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。
主从复制原理详解
MySQL主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL thread)运行在从节点,如下图所示:
- 主节点 binary log dump 线程
当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。 - 从节点I/O线程
当从节点上执行start slave命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。 - 从节点SQL线程
SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。
对于每一个主从连接,都需要三个进程来完成。
当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 进程,而每个从节点都有自己的I/O进程,SQL进程。
从节点用两个线程将::从主库拉取更新::和::执行::分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时I/O进程可以很快从主节点获取更新,尽管SQL进程还没有执行。如果在SQL进程执行之前从节点服务停止,至少I/O进程已经从主节点拉取到了最新的变更并且保存在本地relay日志中,当服务再次起来之后,就可以完成数据的同步。
复制的过程,如下图所示:
复制过程分解:
- 从节点上的I/O 进程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
- 主节点接收到来自从节点的I/O请求后,通过负责复制的I/O进程根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的bin-log file 的以及bin-log position;从节点的I/O进程接收到内容后,将接收到的日志内容更新到本机的relay log中,并将读取到的binary log文件名和位置保存到master-info 文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log 的哪个位置开始往后的日志内容,请发给我”;
- Slave 的 SQL线程检测到relay-log 中新增加了内容后,会将relay-log的内容解析成在从节点上实际执行过的操作,并在本数据库中执行。
主从复制模式
- 异步模式
MySQL 主从复制默认是异步模式,MySQL增删改操作会全部记录在binary log 中,当 slave节点连接 master 时,会主动从 master 处获取最新的 bin log 文件。并把bin log 中的 sql relay。
异步模式下,主节点不会主动 push bin log 到从节点,这样可能导致failover的情况下,也许从节点没有即时地将最新的 bin log 同步到本地,如下图所示:
- 半同步模式(mysql semi-sync)
半同步模式下主节点只需要接收到其中一台从节点的返回信息,就会 commit;否则需要等待直到超时时间然后切换成异步模式再提交;
这样做可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,binlog 至少传输到了一个从节点上,不能保证从节点将此事务更新到 db 中。性能上会有一定的降低,响应时间会变长。如下图所示:
半同步模式不是 mysql 内置的,从 mysql5.5开始集成,需要 maste 和 slave安装插件开启半同步 模式。
- 全同步模式
全同步模式是指主节点和从节点全部执行了 commit 并确认才会向客户端返回成功。
binlog 记录格式
MySQL 主从复制有三种方式,对应的 binlog 文件格式也有三种(STATEMENT, ROW, MIXED):
基于 SQL 语句的复制(statement-based replication,SBR)。
Statement-base Replication(SBR)就是记录 sql 语句在 bin log 中,MySQL5.1.4及之前的版本都是使用这种复制模式。优点是只需要记录会修改数据的 sql 语句到 binglog 中,减少了binglog日志量,节约 I/O,提高性能。缺点是在某些情况下,会导致主从节点数据不一致(比如:sleep(), now()等)。基于行的复制(row-based replication,RBR)。
Row-based Relication(RBR)是 mysql master 将 SQL 语句分解为基于 Row更改的语句并记录在binlog 中,也就是只记录哪条数据被修改了,修改成什么样。优点是不会出现某些特定情况下的存储过程、或者函数、或者 tigger 的调用、或者触发无法被正确复制的问题。缺点是会产生大量的日志,尤其是修改 table 的时候会让日志暴增,同时增加 binlog 同步时间。也不能通过binlog解析获取执行过的 sql 语句,只能看到发生的 data 的变更。混合模式复制(mixed-based replication,MBR)。
Mixed-format Replication (MBR),MySQL NDB cluster 7.3和7.4使用的MBR。是以上两种模式的混合,对于一般的复制使用 ::STATEMENT 模式::保存到 binlog,对于STATEMENT 无法复制的操作则使用 ::ROW 模式::来保存,MySQL 会根据执行的 SQL语句选择日志保存方式。
GTID 复制模式
GTID(Global Transaction ID)- 全局事务ID
在传统的复制里面,当发生故障,需要主从切换,需要找到 binlog和 pos点,然后将主节点指向新的主节点,相对来说比较麻烦,也容易出错。
在 MysQL5.6里面,不用再找 binlog 和 pos 点,我们只需要知道主节点的 ip,端口,以及账号密码就行,因为复制是自动的,MySQL 会通过内部机制GTID 自动找点同步。
基于 GTID 复制 – 实现的工作原理:
- 主节点更新数据时,会在事务前产生 GTID,一起记录到 binlog 日志中。
- 从节点的I/O 线程将变更的 binlog写入到本地的 relay log 中。
- SQL 线程从 relay log 中获取 GTID,然后对比本地 binlog 是否有记录(MySQL 从节点必须要开启 binary log)。
- 如果有记录,说明该事务已经执行,从节点会忽略。
- 如果没有记录,从节点就会从 relay log 中执行该 GTID 的事务,并记录到 binlog 。
- 在解析过程中会判断是否有主键,如果没有就用二级索引,如果有就用全部扫描。
基于库的多线程复制
在 MySQL5.6以前的版本,slave 的复制是单线程的。一个事件一个事件的读取应用。而 master 是并发写入的,所以延时是避免不了的。唯一有效的方法是把多个库放在多台 slave,这样又有点浪费服务器。
在 MySQL5.6里面,我们可以把多个表放在多个库,这样就可以使用多线程复制。
MySQL 数据库主从同步配置详解
注意:
1:主从数据库的版本必须一致。
2:主从同步之前确保备份的数据库和表在从库存在,主从复制不会创建库和表。
- ::一主一从::
- 手动指定二进制文件位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# 主数据库服务器设置 1:修改 my.cnf 配置文件(配置文件位置一般在: /etc/mysql/my.cnf), 设置如下选项: [mysqld] server_id = 1000 # 设置服务器id,这个id是唯一,不能跟别的服务器重复。 log_bin = master-bin # 开启并设置二进制日志文件名称。 binlog_format = MIXED # binlog 记录格式,MBR sync_binlog = 1 # 1:消耗性能但是最安全 expire_logs_days = 7 # 二进制日志自动删除/过期的天数;默认值为0,表示不自动删除。 # binlog_cache_size = 128m # max_binlog_cache_size = 512m # max_binlog_size = 256m log_bin_trust_function_creators=1 slave_net_timeout=60 #MySQL主从复制的时候,Slave会等待slave_net_timeout设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据 # 只记录以下数据库二进制文件;默认全部记录 binlog_do_db = dbname # 不需要记录以下数据库mysql,information_schema,performance_schema,sys二进制文件 binlog_ignore_db = mysql binlog_ignore_db = information_schema binlog_ignore_db = performance_schema binlog_ignore_db = sys # character_set_server = utf8mb4 # collation_server = utf8mb4_general_ci 2:重启mysql服务 `systemctl restart mysql.service` # 重启 mysql 服务后, 使用 `show variables like 'log_bin';` 查看logbin开启状态 使用 `show master status\G` 查看 master 状态 3:创建并授权同步数据使用的账户 CREATE USER 'master-1000'@'%' IDENTIFIED WITH mysql_native_password BY 'ae54839d02bc3603ddc654876bd4e273'; grant replication slave, replication client on *.* to 'rep_1'@'%' WITH GRANT OPTION; flush privileges; 4:备份主数据库服务器需要同步的数据 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 从数据库服务器配置(从数据库版本必须和主数据库版本一致) 1:使用上一步在主数据库设置的同步账户,远程登陆测试是否可用 `mysql -h 主数据库服务器IP -umaster-1000 -pae54839d02bc3603ddc654876bd4e273` 2:修改 my.cnf 配置文件,设置如下选项 [mysqld] server_id = 2001 3:重启 mysql 服务 `systemctl restart mysql.service` 4:把上一步主服务器导出的同步数据导入从服务器 `mysql -uroot -ppasswd < /tmp/master_database_backup.sql` 5:登陆从数据库服务器,设置主从关系 `mysql -uroot -ppasswd` `change master to master_host='$IP',master_user='$user',master_password='$passwd',master_port=3306,master_log_file='$master_log_file',master_log_pos=$master_log_pos;` # 参数说明 $IP:主数据库服务器IP地址 $user, $passwd:在主数据库服务器设置的用于同步数据的账户,密码 $master_log_file,$master_log_pos:参数来源自mysql主数据库服务器备份导出的sql文件 6:登陆从数据库服务器,启动同步服务 `start slave;` 7:查看启动状态,核查’Slave_IO_Running‘, ’Slave_SQL_Running‘两项都是 ’Yes‘,表示配置成功 `show slave status\G` |
注意事项:
如果主库里面有初始化数据,那么在主从复制前需要把主库数据导入从库以保证数据初始一致性。
实际生产环境中可能出现非常多的二进制文件,使用手动指定会很不方便
- 自动设置文件位置
MySQL5.6.5开始,新增了一个基于 GTID的复制方式,通过 GTID保证了每个在主库上提交的事务在集群中有一个唯一的 ID。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。
主从同步自动指定二进制文件位置,基于主从服务器同时开启 GTID 模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 主数据库服务器gtid配置 1:修改 my.cnf 配置文件 [mysqld] server_id = 1000 log_bin = master-bin gtid_mode = ON enforce_gtid_consistency = ON binlog_format = MIXED sync_binlog = 1 expire_logs_days = 7 log_bin_trust_function_creators=1 slave-net-timeout=60 binlog_do_db = dbname binlog_ignore_db = mysql binlog_ignore_db = information_schema binlog_ignore_db = performance_schema binlog_ignore_db = sys 2:重启 mysql 服务 `systemctl restart mysql.service` |
如果 mysql 版本是5.6,那么主从必须开启log_slave_updates参数,此时slave对比自己的 binlog查看是否有记录。如果 mysql 版本是5.7,那么主从不需要开启此参数(级联主从除外),mysql5.7提供了 gtid_excuted 系统表来记录复制的信息,以此减少从库的压力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 从数据库服务器gtid配置 1:修改 my.cnf 配置文件 [mysqld] server_id = 2001 log_bin = slave-bin-2001 gtid_mode = ON enforce_gtid_consistency = ON 2:重启 mysql 服务 `systemctl restart mysql.service` 3:登陆从数据库服务器设置主从关系 `change master to master_host='$IP',master_user='$user',master_password='$passwd',master_port=3306,master_auto_position=1;` # 参数说明 二进制文件位置由master_auto_position=1参数自动确定 4:开启同步 `start slave;` 5:查看同步状态 `show slave status\G` |
- ::多主一从配置::
数据汇总:将多个主数据库同步汇总到一个从数据库中,方便数据统计分析。
读写分离:从库只用于查询,提高数据库整体性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 从数据库服务器配置 1:修改 my.cnf 配置文件 # log_bin # 从服务器log_bin 可开可不开 server_id = 2001 gtid_mode = ON enforce_gtid_consistency = ON # 额外增加如下配置 master-info-repository = TABLE relay-log-info-repository = TABLE 2:重启 mysql 服务 `systemctl restart mysql.service` 3:登陆从数据库服务器设置主从关系 `change master to master_host='$master-1000-ip',master_user='$user',master_password='$passwd',master_auto_position=1 for channel '1000';` `change master to master_host='$master-1001-ip',master_user='$user',master_password='$passwd',master_auto_position=1 for channel '1001'` `change master to master_host='$master-1002-ip',master_user='$user',master_password='$passwd',master_auto_position=1 for channel '1002'` # 注意 for channel 'server_id' 也可以使用 for channel 'master_ip' 4:开启同步 `start slave;` # 单独启动/停止某个 channel 通道 start slave for channel '1001'; stop slave for channel '1001'; 5:查看同步状态 `show slave status\G` |
- ::一主多从配置::
一主多从配置和一主一从配置类似
只需要将不同的 slave 配置中的 server_id 修改,保证唯一性即可。
本着互联网开源、开放的精神和宗旨,本站所有内容可以随便传播。如需转载或分享无需说明来源。
有任何疑问或烦恼,欢迎评论区讨论。
暂无回复数据