1. 主从复制简介
mysql复制将来自一个MySQL数据库服务器(master称为源)的数据复制到一个或多个MySQL数据库服务(slave称为副本)。mysql复制实现整个复制操作主要由三个线程完成的,其中两个线程在 Slave(sql_thread 和 IO_thread)在slave上,另外一个线程在 Master(IO 进程)上。
默认情况下,复制是异步的;副本不需要永久连接才能从源接收更新。根据配置,您可以复制数据库中的所有数据库、选定数据库,甚至选定表。
2. MySQL复制流程
MySQL主从复制中的关键组成部分,这里会涉及到三个线程:I/O 线程、Log Dump 线程(也可称为IO线程)、SQL 线程。

(1) 主库在执行任何数据变更操作,都会将操作记录写入 binlog(二进制日志)文件中。
(2) 从库通过配置的主库连接信息,使用 I/O 线程连接到主库,并请求从指定binlog日志文件的指定pos节点位置(或者从最开始的日志)开始复制之后的日志内容。
(3) 主库在接收到来自slave端的IO线程请求后,为每个连接的从库创建一个专用的 dump 线程,根据slave端IO线程的请求信息,读取指定binlog日志指定pos节点位置之后的日志信息,将 binlog 中的事件按照顺序推送给对应的从库 I/O 线程。返回的信息在主库的binlog文件名以及在该binlog日志中的pos节点位置。
(4) 从库的 I/O 线程接收主库推送的二进制日志binlog 数据,并将其写入本地中继日志 relay log中。并将读取到的主库的binlog文件名和pos节点位置记录到master-info(该文件存slave端)文件中,以便在下一次读取的时候能够清楚的告诉主库下次需要的binlog文件和pos位置。
(5) 从库的 SQL 线程读取 relay log,依次解析并执行其中的 SQL 操作,从而使从库的数据与主库保持一致。
3. 复制的常用拓扑结构
复制的限制:
- 每个slave只能有一个master。
- 每个slave只能有一个唯一的服务器ID。
- 每个master可以有很多slave。
- 如果设置log_slave_updates,slave可以是其它slave的master,从而扩散master的更新。
(1) 一主一从
是最基础的复制结构,用来分担之前单台数据库服务器的压力,可以进行读写分离。

(2) 一主多从
一台 Slave 承受不住读请求压力时,可以添加多台,进行负载均衡,分散读压力。对多台 Slave 进行分工,服务于不同的系统。

(3) 双主复制
双主结构就是用来解决单主故障问题的互相将对方作为自己的 Master,自己作为对方的 Slave 来进行复制,但对外来讲,还是一个主和一个从。当 主库下线时,自动提升成新的主库,原来的主Master 上线后,能够自动加入到主从复制中,会自动从之前的位置开始重新复制,不需要人为地干预,大大提升了效率。

(4) 级联复制
当直接从属于 Master 的 Slave 过多时,连到 Master 的 Slave IO 线程就比较多,对 Master 的压力是很大的。级联结构就是通过减少直接从属于 Master 的 Slave 数量,减轻 Master 的压力,分散复制请求,从而提高整体的复制效率。

(5) 双主级联
级联复制结构解决了 Slave 过多导致的瓶颈问题,但还是有单主结构中切换主时的维护问题。为了解决这个问题,就可以加入上面的双主结构。在必要时,可以再对 Slaves 进行分级。

Mysql 的复制结构有很多种方式,复制的最大问题是数据延和一致性问题,选择复制结构时需要根据自己的具体情况,并评估好目标结构的延时对系统的影响。
4. MySQL中复制的优点
(1) 横向扩展, 在多个副本之间分散负载以提高性能。所有写入和更新都必须在源服务器上进行。读取可以在一个或多个副本上,从而提高写入性能,同时在越来越多的副本上显著提高读取速度,同时可以实现读写分离。
(2) 数据安全,由于副本可以暂停复制过程,因此可以在副本上运行备份服务,而不会损坏相应的源数据。
(3) 从库进行数据分析,可以在源上创建实时数据,而对信息的分析可以在副本上进行,而不会影响源的性能。
(4) 远程数据分发,可以使用复制创建数据的本地副本供远程站点使用,而无需永久访问源。
(5) 数据备份, 只是简单的对数据库进行备份,降低数据丢失的风险,另外主库宕机时,可以切换到从库使用,解决单点故障或做故障切换。
(6) 负载均衡和容错。
5. MySQL不同的复制方法
(1) 从源的二进制日志中复制事件,并要求日志文件及其位置在源和副本之间同步。
(2) 基于全局事务标识符(GTID), 不需要处理日志文件或这些文件中的位置,只要源上提交的所有事务也应用于副本,使用GTID的复制就可以保证源和副本之间的一致性。
6. MySQL复制中不同的同步类型
(1) 异步复制
这是MySQL的默认复制方式。主库在执行完客户端提交的事务后会立刻将执行结果返回给客户端,并不关心从库是否已经接收处理。这种方式的优点是性能较高,但缺点是数据一致性较弱,主从之间可能存在延迟,主库崩溃时未同步的数据可能会丢失
(2) 半同步复制
在这种方式下,主库提交事务后,会至少等待一个从库接收并写入relay log后才返回客户端确认。这种方式平衡了性能和数据一致性,但如果从库无响应,主库会退化为异步复制。适用于对数据一致性要求较高的场景。
(3) 延迟复制
复制落后于源至少一段指定的时间;默认复制延迟为0秒。使用CHANGE REPLICATION SOURCE_DELAY=N(复制配置后可以单独执行)语句将延迟设置为N秒。延迟复制的方法取决于两个时间戳,即immediate_commit_timestamp和original_commit_timestamp。
original_commit_timestamp:自事务被写入(提交)到原始源的二进制日志的纪元以来的微秒数。
Immediate_commit_timestamp:自事务被写入(提交)到即时源的二进制日志的纪元以来的微秒数。
7. 复制格式
(1) 基于语句的二进制日志记录
源将SQL语句写入二进制日志。通过在复制副本上执行SQL语句,可以将源复制到复制副本。这被称为基于语句的复制(可以缩写为SBR),它对应于基于MySQL语句的二进制日志记录格式。
优点:
- 成熟的技术。
- 记录的二进制日志量非常少。
- 日志文件包含进行任何更改的所有语句,因此可用于数据库审计。
缺点:
- 并非所有修改数据的语句(如INSERT DELETE、UPDATE和REPLACE语句)都可以使用基于语句的复制进行复制。
- 可能导致数据异常,或者主从数据不一致。
- 依赖于可加载函数或非确定性存储程序的语句,因为此类函数或存储程序返回的值或取决于提供给它的参数以外的因素。
- 使用LIMIT子句而不使用ORDER BY的DELETE和UPDATE语句是不确定的。
- 锁定使用NOWAIT或SKIP LOCKED选项的读取语句(SELECT…FOR UPDATE和SELECT…FOR SHARE)。
- 必须对副本应用确定性可加载函数。
- 使用基于语句的复制无法正确复制使用以下任何函数的语句:LOAD_FILE(),UUID(), UUID_SHORT(), USER(), FOUND_ROWS(), SYSDATE() , GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK(), RAND(), RELEASE_LOCK(), SOURCE_POS_WAIT(), SLEEP(),VERSION()
(2) 基于行的日志记录
源将事件写入二进制日志,指示如何更改单个表行。将源复制到副本的工作原理是将表示表行更改的事件复制到副本。这被称为基于行的复制(可缩写为RBR)。
基于行的日志记录是默认方法。
优点:
- 所有更改都可以复制。这是最安全的复制形式。
- 对于以下类型的语句,源代码上需要更少的行锁,从而实现了更高的并发性:
- 对于任何INSERT、UPDATE或DELETE语句,副本上所需的行锁更少。
- 可以将 InnoDB 的事务隔离基本设为 READ COMMITTED,以获得更好的并发性。
缺点:
- RBR可以生成更多必须记录的数据。要复制DML语句(如UPDATE或DELETE语句),基于语句的复制只会将该语句写入二进制日志。相比之下,基于行的复制将每个更改的行写入二进制日志。如果语句更改了许多行,基于行的复制可能会将更多的数据写入二进制日志;即使对于回滚的语句也是如此。这也意味着制作和恢复备份可能需要更多时间。此外,二进制日志被锁定更长时间以写入数据,这可能会导致并发问题。使用binlog_row_image=minimal可以大大减少缺点。
- 与基于语句的复制相比,基于行的复制需要更长的时间来复制生成大型BLOB值的确定性可加载函数。这是因为记录的是BLOB列值,而不是生成数据的语句。
- 无法在副本上看到从源接收并执行了哪些语句。但是,您可以使用mysqlbinlog使用选项--base64 output=DECODE-ROWS和--verbose查看更改了哪些数据。
- 使用binlog_rows_query_log_events变量,如果启用,当使用-vv选项时,该变量会将一个rows_query事件与语句一起添加到mysqlbinlog输出中。
- 对于使用MyISAM存储引擎的表,当将INSERT语句作为基于行的事件应用于二进制日志时,需要对副本进行比将其作为语句应用更强的锁定。这意味着在使用基于行的复制时,不支持MyISAM表上的并发插入。
(3) 混合格式日志记录
使用混合格式日志记录时,默认情况下使用基于语句的日志。根据某些语句以及所使用的存储引擎,在特定情况下,日志会自动切换为基于行的日志。使用混合格式的复制称为基于混合的复制或混合格式复制。
可能的情况包括:
- 表的存储引擎为 NDB,这时对于表的 DML 操作都会以 ROW 格式记录
- 使用了 UUID()、USER()、CURRENT_USER()、FOUND_ROWS()、ROW_COUNT()等不确定函数
- 使用了 INSERT DELAY 语句
- 使用了用户定义函数
- 使用了临时表
8. 复制通道
8.1 复制通道简介
在MySQL多源复制中,副本打开多个复制通道,每个源服务器一个。复制通道表示从源流向副本的事务路径。每个复制通道都有自己的接收器(I/O)线程、一个或多个应用程序(SQL)线程和中继日志。当通道的接收器线程接收到来自源的事务时,它们会被添加到通道的中继日志文件中,并传递给通道的应用程序线程。这使每个通道能够独立运行。在多源复制拓扑中,一个副本服务器上可以创建的最大通道数为256。每个复制通道必须有一个唯一的(非空)名称。
多源副本上的每个通道都必须从不同的源进行复制。无法设置从单个副本到单个源的多个复制通道。这是因为副本的服务器ID在复制拓扑中必须是唯一的。源仅通过副本的服务器ID而不是复制通道的名称来区分副本,因此无法识别同一副本中的不同复制通道。
多源副本可以在特定的复制通道上配置复制过滤器。当同一数据库或表存在于多个源上,并且您只需要从一个源复制副本时,可以使用特定于通道的复制筛选器。
对于基于GTID的复制,如果同一事务可能来自多个源(例如菱形拓扑),则必须确保所有通道上的过滤设置相同。
MySQL服务器在启动时会自动创建一个默认通道,其名称为空字符串(“”)。该频道始终存在;它不能由用户创建或销毁。
8.2 单通道
单复制没有指定多通道和FOR CHANNEL channel ,除了一些特定语句之外,下面通常可用于所有可用通道。
START REPLICA启动所有通道的复制线程,但group_replication_recovery和group_replication_applier通道除外。
STOP REPLICA停止所有通道的复制线程,但group_replication_recovery和group_replication_applier通道除外。
SHOW REPLICA STATUS报告所有通道的状态,但group_replication_applier通道除外。
RESET REPLICA重置所有通道。(谨慎使用RESET REPLICA,因为此语句会删除所有现有通道,清除其中继日志文件,并仅重新创建默认通道。)
以下语句和函数在多源复制拓扑中使用时会产生此错误,并且FOR CHANNEL通道选项不用于指定要操作的通道:
SHOW RELAYLOG EVENTS
CHANGE REPLICATION SOURCE TO
SOURCE_POS_WAIT()
默认通道始终存在于单源复制拓扑中。
8.3 启动选项和复制通道
(1) 下面启动选项将影响所有通道
--log-replica-updates 副本接收到的所有事务(即使来自多个来源)都会写入二进制日志。
--relay-log-purge 设置后,每个通道都会自动清除自己的中继日志。
--replica-transaction-retries 指定的事务重试次数。
--skip-replica-start 任何通道上都不会启动复制线程。
--replica-skip-errors 执行将继续,所有通道的错误都将被跳过。
(2) 以下启动选项设置的值适用于每个通道;由于这些是mysqld启动选项,因此它们应用于每个通道。
--max-relay-log-size=size 每个通道的单个中继日志文件的最大大小;达到此限制后,文件将被重用。
--relay-log-space-limit=size 每个单独通道的所有中继日志总大小的上限。对于N个通道,这些日志的组合大小限制为relay_log_space_limit*N。
--replica-parallel-workers=value 每个通道的复制应用程序线程数。
replica_checkpoint_group 接收器线程对每个源的等待时间。
--relay-log-index=filename 每个通道的中继日志索引文件的基本名称。
--relay-log=filename 表示每个通道的中继日志文件的基本名称
--replica-net-timeout=N 每个通道等待N秒来检查连接是否断开。
--replica-skip-counter=N 每个通道跳过其源中的N个事件。
9. 复制线程
MySQL复制功能使用以下类型的线程实现:
(1) Binary log dump thread二进制日志转储线程。
主库创建了一个线程,以便在从库连接时将二进制日志内容发送到副本。此线程可以在源上的SHOW PROCESSIST输出中标识为Binlog转储线程。
(2) Replication I/O receiver thread复制I/O接收器线程
当在副本服务器上发出START REPLICA语句时,副本会创建一个I/O(接收器)线程,该线程连接到源并要求其发送其二进制日志中记录的更新。
复制接收器线程读取源的Binlog转储线程发送的更新,并将其复制到包含副本中继日志的本地文件中。
此线程的状态在SHOW REPLICA STATUS的输出中显示为Slave_IO_running。
(3) Replication SQL applier thread 复制SQL应用程序线程
有N个应用程序线程和一个协调器线程,它从中继日志中顺序读取事务,每个worker应用协调器分配给它的事务应用执行。
复制副本创建了由replica_parali_workers指定的指定数量的工作线程来应用事务,以及一个从中继日志读取事务并将其分配给工作线程的协调器线程。如果使用多个复制通道,则每个通道都有使用此变量指定的线程数。
10. 中继日志和复制元数据存储库
副本服务器创建多个信息存储库,用于复制过程:
relay log中继日志中的事务由复制SQL线程把从复制源服务器的二进制日志读取的事务应用于副本。
复制副本的连接元数据存储库包含复制接收器线程连接到复制源服务器并从源的二进制日志中检索事务所需的信息。连接元数据存储库被写入mysql.slave_master_info表。
复制副本的应用程序元数据存储库包含复制应用程序线程从复制副本的中继日志中读取和应用事务所需的信息。应用程序元数据存储库被写入mysql.slave_relay_log_info表。
10.1. Relay Log
relay log中继日志与二进制日志一样,由一组包含描述数据库更改的事件的编号文件和一个包含所有使用的中继日志文件名称的索引文件组成。中继日志文件的默认位置是数据目录。
relay log中继日志文件的格式与二进制日志文件相同,可以使用mysqlbinlog读取。
对于默认复制通道,中继日志文件名的默认格式为host_name-relay-bin.nnnnnn,其中host_name是副本服务器主机的名称,nnnnnn是序列号。连续的中继日志文件是使用从000001开始的连续序列号创建的。对于非默认复制通道,默认基本名称是host_name-relay-bin-channel,其中channel是中继日志中记录的复制通道的名称。
副本使用索引文件来跟踪当前正在使用的中继日志文件。默认的中继日志索引文件名为host_name-relay-bin.index(用于默认通道)和host_name-relay-bin-channel.index(用于非默认复制通道)。
副本服务器在以下条件下创建新的中继日志文件:
- 每次复制I/O(接收器)线程启动时。
- 当日志被刷新时(例如,使用FLUSH logs或mysqladmin刷新日志)。
当前中继日志文件的大小变得太大时,如下:
如果max_relay_log_size的值大于0,则表示中继日志文件的最大大小。
如果max_relay_log_size的值为0,则max_binlog_size确定最大中继日志文件大小。
复制SQL(应用程序)线程在执行完文件中的所有事件后不再需要它,会自动删除每个中继日志文件。FLUSH logs会轮换中继日志,这会影响复制SQL线程何时删除它们。
10.2. 复制元数据存储库
副本服务器创建两个复制元数据存储库,即连接元数据存储库和应用程序元数据存储库。复制元数据存储库在副本服务器关闭后仍然存在。如果正在使用基于二进制日志文件位置的复制,当副本重新启动时,它会读取两个存储库,以确定之前从源读取二进制日志和处理自己的中继日志的进度。如果使用基于GTID的复制,则复制副本不会为此目的使用复制元数据存储库,但确实需要它们来存储其中包含的其他元数据。
- 复制副本的连接元数据存储库包含复制I/O(接收器)线程连接到复制源服务器并从源的二进制日志中检索事务所需的信息。此存储库中的元数据包括连接配置、复制用户帐户详细信息、连接的SSL设置以及复制接收器线程当前从源二进制日志读取的文件名和位置。
- 复制副本的应用程序元数据存储库包含复制SQL(应用程序)线程从复制副本的中继日志中读取和应用事务所需的信息。此存储库中的元数据包括复制应用程序线程在中继日志中执行事务的文件名和位置,以及源二进制日志中的等效位置。它还包括应用事务过程的元数据,例如工作线程的数量和通道的PRIVILEGE_CHECKS_USER帐户。
连接元数据存储库被写入mysql系统模式中的slave_master_info表,而应用程序元数据存储库则被写入mysql系统模式的slave_relay_log_info表。
复制元数据存储库仅在以下情况下同步:
- 当发布 CHANGE REPLICATION SOURCE TO声明时。
- 当发出RESET REPLICA声明时。RESET REPLICA ALL会删除而不是更新存储库,因此它们会隐式同步。
- 初始化复制通道时。
- 如果复制元数据存储库从文件移动到表。
默认情况下,将复制元数据存储库创建为表;不推荐使用文件。
应用程序工作线程元数据存储库,主要是为内部使用而创建的,它保存了多线程副本上工作线程的状态信息。应用程序工作线程元数据存储库包括每个工作线程的中继日志文件和源二进制日志文件的名称和位置。如果应用程序元数据存储库是作为表创建的(这是默认设置),则应用程序worker元数据存储库将写入mysql.slave_worker_info表。如果应用程序元数据存储库被写入文件,则应用程序工作元数据存储库将被写入worker-relay-log.info文件。对于外部使用,工作线程的状态信息显示在Performance Schema replication_applier_status_by_worker表中。
复制元数据存储库最初包含与SHOW REPLICA STATUS语句输出中显示的信息类似的信息。
378

被折叠的 条评论
为什么被折叠?



