Files
rikako-note/mysql/mysql集群/Replication.md
2025-10-21 15:41:26 +08:00

32 KiB
Raw Permalink Blame History

Replication

Replication允许数据从一个database server被复制到一个或多个mysql database serversreplicas。replication默认是异步的replicas并无需永久连接即可接收来自source的更新。基于configuration可以针对所有的databases、选定的databases、甚至database中指定的tables进行replicate。

mysql中replication包含如下优点

  • 可拓展方案可以将负载分散到多个replicas从而提升性能。在该环境中所有的writes和updates都发生在source server。但是reads则是可以发生在一个或多个replicas上。通过该模型能够提升writes的性能因为source专门用于更新并可以通过增加replicas的数量来提高read speed
  • data security 因为replica可以暂停replication过程故而可以在replica中运行备份服务而不会破坏对应的source data
  • analytics实时数据可以在source中生成而对信息的分析则可以发生在replica分析过程不会影响source的性能
  • long-distance data distribution可以replication来对remote site创建一个local copy而无需对source的永久访问

在mysql 8.4中支持不同的replication方式。

  • 传统方式基于从source的binary log中复制事件并且需要log files和在source和replica之间进行同步的position
  • 新的replication方式基于global transaction identifiersGTIDs是事务的并且不需要和log files、position进行交互其大大简化了许多通用的replication任务。使用GTIDs的replication保证了source和replica的一致性所有在source提交的事务都会在replica被应用。

mysql中的replication支持不同类型的同步。

  • 原始的同步是单向、异步的复制一个server作为source、其他一个或多个servers作为replicas。
  • NDB Cluster中支持synchronous replication
  • 在mysql 8.4中支持了半同步复制通过半同步复制在source中执行的提交将会被阻塞直到至少一个replica收到transaction并对transaction进行log event且向source发送ack
  • mysql 8.4同样支持delayed replication使得replica故意落后于source至少指定的时间

Configuration Replication

binary log file position based replication configuration overview

在该section中会描述mysql servers间基于binary log file position的replication方案。source会将database的writes和updates操作以events的形式写入到binary log中。根据database记录的变更binary log中的信息将会以不同的logging format存储。replicas可以被配置从source的binary log读取events并且在replica本地的binary log中执行时间。

每个replica都会接收binary log的完整副本内容并由replica来决定binary log中哪些statements应当被执行。除非你显式指定否则binary log中所有的events都会在replica上被执行。如果需要你可以对replica进行配置仅处理应用于特定databases、tables的events。

每个replica都会记录二进制日志的坐标其已经从source读取并处理的file name和文件中的position。这代表多个replicas可以连接到source并执行相同binary log的不同部分。由于该过程受replicas控制故而独立的replicas可以和source建立连接、取消连接并且不会影响到source的操作。并且每个replica记录了binary log的当前positionreplica可以断开连接、重新连接并重启之前的过程。

source和每个replica都配置了unique ID使用server_id system variable除此之外每个replica必须配置如下信息

  • source's host name
  • source's log file name
  • position of source's file

这些可以在replica的mysql session内通过CHANGE REPLICATION SOURCE TO语句来管理并且这些信息存储在replica的connection metadata repository中。

Replication with Global Transaction Identifiers

在该章节中描述了使用global transaction identifiersGTIDs的transaction-based replication。当使用GTIDs时每个在source上提交的事务都可以被标识和追踪并可以被任一replica应用。

在使用GTIDs时启动新replica或failover to a new source时并不需要参照log files或file position。由于GTIDs时完全transaction-based的其更容易判断是否source和replicas一致只要在source中提交的事务全部也都在replica上提交那么source和replica则是保证一致的。

在使用GTIDs时可以选择是statement-based的还是row-based的推荐使用row-based format。

GTIDs在source和replica都是持久化的。总是可以通过检测binary log来判断是否source中的任一事务是否在replica上被应用。此外一旦给定GTID的事务在给定server上被提交那么后续任一事务如果拥有相同的GTID其都会被server忽略。因此在source上被提交的事务可以在replica上应用多次冗余的应用会被忽略其可以保证数据的一致性。

GTID Format and Storage

一个global transation identifierGTID是一个唯一标识符该标识符的创建并和source上提交的每一个事务进行关联。GTID不仅在创建其的server上是唯一的并且在给定replication拓扑的所有servers间是唯一的。

GTID的分配区分了client trasactions在source上提交的事务以及replicated transactions在replica上reproduced的事务。当client transaction在source上提交时如果transaction被写入到binary log中其会被分配一个新的GTID。client transactions将会被保证单调递增并且生成的编号之间不会存在间隙。如果client transaction没有被写入到binary log那么其在source中并不会被分配GTID

Replicated transaction将会使用事务被source server分配的GTID。在replicated transaction开始执行前GTID就已经存在并且即使replicated transaction没有写入到replica的binary log中或是被replica过滤该GTID也会被持久化。mysql.gtid_executed system table将会被用于保存应用到给定server的所有事务的GTID但是已经存储到当前active binary log file的除外

active binary log file中的gtid最终也会被写入到gtid_executed表中但是对于不同的存储引擎写入时机可能不同。对于innodb而言在事务提交时就会写入gtid_executed表而对于其他存储引擎而言则会在binary log发生rotation/server shutdown后才会将active binary log中尚未写入的GTIDs写入到mysql.gtid_executed

GTIDs的auto-skip功能代表一个在source上提交的事务最多只能在replica上应用一次这有助于保证一致性。一旦拥有给定GTID的事务在给定server上被提交任何后续执行的事务如果拥有相同的GTID都会被server忽略。并不会抛出异常并且事务中的statements都不会被实际执行。

如果拥有给定GTID的事务在server上已经开始执行但是尚未提交或回滚那么任何尝试开启一个拥有相同GTID事务的操作都会被阻塞。该server并不会开始执行拥有相同GTID的事务也不会将控制权交还给client。一旦第一个事务提交或回滚那么被阻塞的事务就可以开始执行。如果第一次执行被回滚那么被阻塞事务可以实际执行如果第一个事务成功提交那么被阻塞事务并不会被实际执行而是会被自动跳过。

GTID的表示形式如下

GTID = source_id:transaction_id
  • source_id表示了originating server通常为source的server_uuid
  • transaction_id则是一个由transaction在source上提交顺序决定的序列号。例如第一个被提交的事务其transaction_id为1而第十个被提交的事务其transaction_id则是为10.
    • 在GTID中transaction_id部分的值不可能为0

例如在UUID为3E11FA47-71CA-11E1-9E33-C80AA9429562上的server提交的第23个事务其GTID为

3E11FA47-71CA-11E1-9E33-C80AA9429562:23

在GTID中序列号的上限值为2^63 - 1, or 9223372036854775807(signed 64-bit integer)。如果server运行时超过GTIDs其将执行binlog_error_action指定的行为。当server接近该限制时会发出一个warning message。

在mysql 8.4中也支持tagged GTIDs一个tagged GTID由三部分组成通过:进行分隔,示例如下所示:

GTID = source_id:tag:transaction_id

在该示例中,source_idtransaction_id的含义和先前相同,tag则是一个用户自定义的字符串,用于表示specific group of transactions

例如在UUID为ed102faf-eb00-11eb-8f20-0c5415bfaa1d的server上第117个提交的tag为Domain_1的事务其GTID为

ed102faf-eb00-11eb-8f20-0c5415bfaa1d:Domain_1:117

事务的GTID会展示在mysqlbinlog的输出中,用于分辨performance schema replication status tables中独立的事务,例如replication_applier_status_by_worker表。

gtid_next system variable的值是单个GTID。

GTID Sets

一个GTID set由一个或多个GTIDsGTIDs范围构成。gtid_executedgtid_purged system variables存储的就是GTID sets。START REPLICA选项UNTIL SQL_BEFORE_GTIDSUNTIL SQL_AFTER_GTIDS可令replica在处理事务时最多只处理到GTID set中的第一个GTID在处理完GTID set中的最后一个GTID后停止。内置的GTID_SUBSET()GTID_SUBTRACT()函数需要GTID sets作为输入。

在相同server上的GTIDs范围可以按照如下形式来表示

3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5

上述示例表示在uuid为3E11FA47-71CA-11E1-9E33-C80AA9429562的server上提交的顺序为1~5之间的事务。

相同server上的多个single GTIDs或ranges of GTIDs可以通过如下形式来表示

3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49

GTID set可以包含任意single GTIDsGTIDs range的组合也可以包含来自不同server的GTIDs。如下实例中展示了gtid_executed system variable中存储的GTID set代表replica中应用了来自超过一个source的事务

2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19

当GTID set从server variables中返回时UUID按照字母排序返回而序列号间区间则是合并后按照升序排列。

当构建GTID set时用户自定义tag也会被作为UUID的一部分这代表来自相同server且tag相同的多个GTIDs可以被包含在一个表达式中如下所示

3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:11:47-49

来源相同server但是tags不同的GTIDs表示方式如下

3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:15-21, 3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_2:8-52

GTID set的完整语法如下所示

gtid_set:
    uuid_set [, uuid_set] ...
    | ''

uuid_set:
    uuid:[tag:]interval[:interval]...

uuid:
    hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh

h:
    [0-9|A-F]

tag:
    [a-z_][a-z0-9_]{0,31}

interval:
    m[-n]

    (m >= 1; n > m)
msyql.gtid_executed

GTIDs被存储在mysql.gtid_executed表中该表中的行用于表示GTID或GTID set行包含信息如下

  • source server的uuid
  • 用户自定义的tag
  • starting transaction IDs of the set
  • ending transaction IDs of the set

如果行代表single GTID那么最后两个字段的值相同。

mysql.gtid_executed表在mysql server安装或升级时会被自动创建其表结构如下

CREATE TABLE gtid_executed (
  source_uuid CHAR(36) NOT NULL,
  interval_start BIGINT NOT NULL,
  interval_end BIGINT NOT NULL,
  gtid_tag CHAR(32) NOT NULL,
  PRIMARY KEY (source_uuid, gtid_tag, interval_start)
);

mysql.gtid_executed用于mysql server内部使用其允许replica在binary logging被禁用的情况下使用GTIDs其也可以在binary logs丢失时保留GTID的状态。如果执行RESET BINARY LOGS AND GTIDS,那么mysql.gtid_executed表将会被清空。

只有当gtid_mode被设置为ONON_PERMISSIVEGTIDs才会被存储到mysql.gtid_executed中。如果binary logging被禁用或者log_replica_updates被禁用server在事务提交时将会把属于个各事务的GTID和事务一起存储到buffer中并且background threads将会周期性将buffer中的内容以entries的形式添加到mysql.gtid_executed表中。

对于innodb存储引擎而言如果binary logging被启用server更新mysql.gtid_executed表的方式将会和binary logging或replica update logging被启用时一样都会在每个事务提交时存储GTID。对于其他存储引擎则是在binary log rotation发生时或server shut down时更新mysql.gtid_executed表的内容。

如果mysql.gtid_executed表无法被写访问并且binary log file因reaching the maximum file size之外的任何理由被rotated那么current binary log file将仍被使用。并且当client发起rotation时将会返回错误信息并且server将会输出warning日志。如果mysql.gtid_executed无法被写访问并且binary log单个文件大小达到max_binlog_size那么server将会根据binlog_error_action设置来执行操作。如果IGNORE_ERROR被设置那么server将会输出error到日志并且binary logging将会被停止如果ABORT_SERVER被设置那么server将会shutdown。

因为写入到active binary log的GTIDs最终也要被写入mysql.gtid_executed表,但是该表若当前不可写访问,那么此时将无法触发binary log rotation

MySQL.gtid_executed中缺失的GTIDs必须包含在active binary log file中如果log file触发rotation但是无法向mysql.gtid_executed中写入数据那么rotation是不被允许的。

mysql.gtid_executed table compression

随着时间的推移mysql.gtid_executed表会填满大量行行数据代表独立的GTID示例如下

+--------------------------------------+----------------+--------------+----------+
| source_uuid                          | interval_start | interval_end | gtid_tag |
|--------------------------------------+----------------+--------------|----------+
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31             | 31           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 32             | 32           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 33             | 33           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 34             | 34           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 35             | 35           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36             | 36           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37             | 37           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38             | 38           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39             | 39           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40             | 40           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41             | 41           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42             | 42           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43             | 43           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44             | 44           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 45             | 45           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 46             | 46           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47             | 47           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 48             | 48           | Domain_1 |

为了节省空间可以对gtid_executed表周期性的进行压缩将多个single GTID替换为单个GTID set,压缩后的数据如下;

+--------------------------------------+----------------+--------------+----------+
| source_uuid                          | interval_start | interval_end | gtid_tag |
|--------------------------------------+----------------+--------------|----------+
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31             | 35           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36             | 39           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40             | 43           | Domain_1 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44             | 46           | Domain_2 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47             | 48           | Domain_1 |
...

server可通过名为thread/sql/compress_gtid_table的前台线程来执行gtid_executed表的压缩操作该线程并不会在show processlist的输出中被列出,但是可以通过查询threads表来查看,示例如下:

mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
*************************** 1. row ***************************
          THREAD_ID: 26
               NAME: thread/sql/compress_gtid_table
               TYPE: FOREGROUND
     PROCESSLIST_ID: 1
   PROCESSLIST_USER: NULL
   PROCESSLIST_HOST: NULL
     PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
   PROCESSLIST_TIME: 1509
  PROCESSLIST_STATE: Suspending
   PROCESSLIST_INFO: NULL
   PARENT_THREAD_ID: 1
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: NULL
       THREAD_OS_ID: 18677

当server启用了binary log时上述压缩方式并不会被使用mysql.gtid_executed在每次binary log rotation时会被压缩。但是当binary logging被禁用时thread/sql/compress_gtid线程处于sleep状态每有一定数量的事务被执行时线程会wake up并执行压缩操作。在table被压缩之前经过的事务数量即压缩率可由system variable gtid_executed_compression_period来进行控制。如果将值设置为0代表该thread永远不会wake up。

相比于其他存储引擎innodb事务写入mysql.gtid_executed的过程有所不同在innodb存储引擎中过程通过线程innodb/clone_gtid_thread来执行。此GTID持久化线程将会分组收集GTIDs并将其刷新到mysql.gtid_executed表中并对table进行压缩。如果server中既包含innodb事务又包含non-innodb事务那么由compress_gtid_table线程执行的压缩操作将会干扰clone_gtid_thread的工作,并对其效率进行显著下降。为此,在此场景下更推荐将gtid_executed_compression_period设置为0故而compress_gtid_table线程将永远不被激活。

gtid_executed_compression_period的默认值为0且所有事务不论其所属存储引擎都会被clone_gitid_thread写入到mysql.gtid_exec uted中。

当server实例启动后如果gtid_executed_compression_preiod被设置为非0值并且compress_gtid_table线程也启动在多数server配置中将会对msyql.gtid_executed表执行显式压缩。压缩通过线程的启动触发。

GTID生命周期

GTID生命周期由如下步骤组成

  1. 事务在source上被执行并提交client transaction将会被分配GTIDGTID由source UUIDsmallest nonzero transaction sequence number not yet used on this server组成。GTID也会被写入到binary log中在log中GTID被写入在事务之前。如果client transaction没有被写入binary log例如事务被过滤或事务为read-only那么该事务不会被分配GTID
  2. 如果为事务分配了GTID那么在事务提交时GTID会被原子的持久化。在binary log中GTID会被写入到事务开始的位置。不管何时如果binary log发生rotation或server shutdownserver会将所有写入到binary log file中事务的GTIDs写入到mysql.gtid_executed表中
  3. 如果为事务分配了GTID那么GTID的外部化是non-atomically在事务提交后非常短的时间。外部化过程会将GTID添加到gtid_executed system variable所代表的GTID set中@@GLOBAL.gtid_executed。该GTID set中包含representation of the set of all committed GTID transactions并且在replication中会作为代表server state的token使用。
    1. 当binary logging启用时gtid_executed system variable代表的GTIDs set是已被应用事务的完整记录。但是mysql.gtid_executed表则并记录所有GTIDs可能由部分GTIDs仍存在于active binary log file中尚未被写入到gtid_executed table
  4. 在binary log data被转移到replica并存储在replica的relay log中后replica会读取GTID的值并且将其设置到gtid_next system variable中。这告知replica下一个事务将会使用gtid_next所代表的GTID。replica在session context中设置gtid_next
  5. replica在处理事务前会验证没有其他线程已经持有了gtid_next中GTID的所有权。通过该方法replica可以保证该该GTID关联的事务在replica上没有被应用过并且还能保证没有其他session已经读取该GTID但是尚未提交关联事务。故而如果并发的尝试应用相同的事务那么server只会让其中的一个运行。
    1. replica的gtid_owned system variable@@GLOBAL.gtid_owned代表了当前正在使用的每个GTID和拥有该GTID的线程ID。如果GTID已经被使用过并不会抛出错误auto-skip功能会忽略该事务
  6. 如果GTID尚未被使用那么replica将会对replicated transaction进行应用。因为gtid_next被设置为了由source分配的GTIDreplica将不会尝试为事务分配新的GTID而是直接使用存储在gtid_next中存储的GTID
  7. 如果replica上启用了binary loggingGTID将会在提交时被原子的持久化写入到binary log中事务开始的位置。无论何时如果binary log发生rotation或server shutdownserver会将先前写入到binary log中事务的GTIDs写入到mysql.gtid_executed表中
  8. 如果replica禁用binary logGTID将会原子的被持久化直接被写入到mysql.gtid_executed表中。mysql会向事务中追加一个statement并且将GTID插入到table中该操作是原子的在该场景下mysql.gtid_executed表记录了完整的transactions applied on the replica
  9. 在replicated transaction提交后很短的时间GTID会被非原子的externalizedGTID会被添加到replica的gtid_executed system variable代表的GTIDs中。在source中gtid_executed system variable包含了所有提交的GTID事务。

在source上被完全过滤的client transactions并不会被分配GTID因此其不会被添加到gtid_executed system variable或被添加到mysql.gtid_executed表中。然而replicated transaction中的GTIDs即使在replica被完全过滤也会被持久化。

  • 如果binary logging在replica开启被过滤的事务将会作为gtid_log_event的形式被写入到binary log后续跟着一个empty transaction事务中仅包含BEGIN和COMMIT语句
  • 如果binary logging在replica被禁用给过滤事务的GTID将会被写入到mysql.gtid_executed

将filtered-out transactions的GTIDs保留可以确保mysql.gtid_executed表和gtid_executedsystem variable中的GTIDs可以被压缩。同时其也能确保replica重新连接到source时filtered-out transactions不会被重新获取

在多线程的replica上replica_parallel_workers > 0事务可以被并行的应用故而replicated transactions可以以不同的顺序来提交除非replica_preserve_commit_order = 1)。在并行提交时,gtid_executedsystem variable中的GTIDs将包含多个GTID ranges多个范围之间存在空隙。在多线程replicas上只有最近被应用的事务间才会存在空隙并且会随着replication的进行而被填充。当replication threads通过STOP REPLICA停止时这些空隙会被填补。当发生shutdown event时server failure导致此时replication 停止,空隙仍可能保留。

What changes are assign a GTID

GTID生成的典型场景为server为提交事务生成新的GTID。然而GTIDs可以被分配给除事务外的其他修改且在某些场景下一个事务可以被分配多个GTIDs。

每个写入binary log的数据库修改(DDL/DML)都会被分配一个GTID。其包含了自动提交的变更、使用BEGIN...COMMIT的变更和使用START TRANSACTION的变更。一个GTID会被分配给数据库的creation, alteration, deletion操作,并且non-table database object例如procedure, function, trigger, event, view, user, role, grantcreation, alteration, deletion也会被分配GTID。

非事务更新和事务更新都会被分配GTID额外的对于非事务更新如果在尝试写入binary log cahche时发生disk write failure导致binary log中出现间隙那么生成的日志事件将会被分配一个GTID。

Replication Implementation

在replication的设计中source server会追踪其binary log中所有对databases的修改。binary log中记录了自server启动时所有修改数据库结构或内容的事件。通常SELECT语句将不会被记录,其并没有对数据库结构或内容造成修改。

每个连接到source的replica都会请求binary log的副本replica会从source处拉取数据而不是source向replica推送数据。replica也会执行其从binary log收到的事件。发生在source上的修改将会在replica上进行重现。在重现过程中,会发生表创建、表结构修改、数据的新增/删除/修改等操作。

由于每个replica都是独立的每个连接到source的replica其对source中binary log内容的replaying都是独立的。此外因为每个replica只通过请求source来接收binary log的拷贝replica能够以其自身的节奏来读取和更新其数据副本并且其能在不对source和其他replicas造成影响的条件下开启或停止replication过程。

Replication Formats

在binary log中events根据其事件类型以不同的格式被记录。replication使用的foramts取决于事件被记录到source server的binary log中时所使用的foramt。binary log format和replciation过程中使用到的format其关联关系如下

  • 当使用statement-based binary logging时source会将sql statements写入到binary log。从source到replica的replication将会在replica上执行该sql语句。这被称之为statement-based replication关联了mysql statement-based binary logging format
  • 当使用row-based loggging时source将会将table rows如何变更的事件写入到binary log中。在replica中将会重现events对table rows所做的修改。则会被成为row-based replication
    • row-based logging是默认的方法
  • 可以配置mysql使用mix-format logging,但使用mix-format logging将默认使用statement-based log。但是对于特定的语句也取决于使用的存储引擎在某些床惊吓log也会被自动切换到row-based。使用mixed format的replication被称之为mix-based replication或mix-format replication

mysql server中的logging format通过binlog_format system variable来进行控制。该变量可以在session/global级别进行设置

  • 在将variable设置为session级别时将仅会对当前session生效并且仅持续到当前session结束
  • 将variable设置为global级别时该设置将会对clients that connect after the change生效,但对于any current client sessions包括.发出该修改请求的session都不生效

使用statement-based和row-based replication的优缺点对比

每个binary logging format都有优缺点。对大多数usersmixed replication format能够提供性能和数据完整性的最佳组合。

Advantages of statement-based replication
  • 在使用statement-based格式时会向log files中写入更少的数据。特别是在更新或删除大量行时使用statement-based格式能够导致更少的空间占用。在从备份中获取和恢复时其速度也更快
  • log files包含所有造成修改的statements可以被用于审核database
Disadvantages of statement-based replication
  • 对于Statement-based replication而言statements并不是安全的。并非所有对数据造成修改的statements都可以使用statement-based replication。在使用statement-based replication时任何非确定性的行为都难以复制例如在语句中包含随机函数等非确定性行为
  • 对于复杂语句statement必须在实际对目标行执行修改前重新计算。而当使用row-based replication时replica可以直接修改受影响行而无需重新计算
Advantages of row-based replication
  • 所有的修改可以被replicated其是最安全的replication形式
disadvantages of row-based replication
  • 相比于statement-based replicationrow-based replication通常会向log中ieur更多数据特别是当statement操作大量行数据是
  • 在replica并无法查看从source接收并执行的statements。可以通过mysqlbinlog--base64-output=DECODE-ROWS--verbose选项来查看数据变更

Replay Log and Replication Metadata Repositories

replica server会创建一系列仓库其中存储在replication过程中使用的信息

  • relay log: 该日志被replication I/O线程写入包含从source server的binary log读取的事务。relay log中记录的事务将会被replication SQL thread应用到replica
  • connection metadata repository: 包含replication receiver thread连接到source server并从binary log获取事务时需要的信息。connection metadata repository会被写入到mysql.slave_master_info
  • applier metadata repository: 包含replication applier thread从relay log读取并应用事务时所需要的信息。applier metadata repository会被写入到mysql.slave_relay_log_info表中

The Relay Log

relay log和binary log类似由一些numbered files构成,文件中包含描述数据库变更的事件。relay log还包含一个index file其中记录了所有被使用的relay log files的名称。默认情况下relay log files位于data directory中

relay log files拥有和binary log相同的格式也可以通过mysqlbinlog进行读取。如果使用了binary log transaction compression那么写入relay log的事务payloads也会按照和binary log相同的方式被压缩。

对于默认的replication channelrelay log file命名形式如下host_name-relay-bin.nnnnnn:

  • host_name为replica server host的名称
  • nnnnnn是序列号序列号从000001开始

对于非默认的replication channels默认的名称为host_name-relay-bin-channel

  • channel为replciation channel的名称

replica会使用index file来追踪当前在使用的relay log files。默认relay log index file的名称为host_name-relay-bin.index

当如下条件下replica server将会创建新的relay log file

  • 每次replication I/O thread开启时
  • 当logs被刷新时例如当执行FLUSH LOGS命令时)
  • 当当前relay log file的大小太大时大小上限可以通过如下方式决定
    • 如果max_relay_log_size的大小大于0那么其就是relay log file的最大大小
    • 如果max_relay_log_size为0那么relay log file的最大大小由max_binlog_size决定

replication sql thread在其执行完文件中所有events之后都不再需要该文件被执行完的relay log file都会被自动删除。目前没有显式的机制来删除relay logsrelay log的删除由replciation sql thread来处理。但是FLUSH LOGS可以针对relay logs进行rotation。