172 lines
13 KiB
Markdown
172 lines
13 KiB
Markdown
- [Replication](#replication)
|
||
- [Configuration Replication](#configuration-replication)
|
||
- [binary log file position based replication configuration overview](#binary-log-file-position-based-replication-configuration-overview)
|
||
- [Replication with Global Transaction Identifiers](#replication-with-global-transaction-identifiers)
|
||
- [GTID Format and Storage](#gtid-format-and-storage)
|
||
- [GTID Sets](#gtid-sets)
|
||
- [msyql.gtid\_executed](#msyqlgtid_executed)
|
||
|
||
# Replication
|
||
Replication允许数据从一个database server被复制到一个或多个mysql database servers(replicas)。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 identifiers(GTIDs),是事务的,并且不需要和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的当前position,replica可以断开连接、重新连接并重启之前的过程。
|
||
|
||
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 identifiers(GTIDs)的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 identifier(GTID)是一个唯一标识符,该标识符的创建并和`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的除外`。
|
||
|
||
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_id`和`transaction_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由`一个或多个GTIDs`或`GTIDs`范围构成。`gtid_executed`或`gtid_purged` system variables存储的就是GTID sets。`START REPLICA`选项`UNTIL SQL_BEFORE_GTIDS`和`UNTIL 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 GTIDs`和`GTIDs 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安装或升级时会被自动创建,其表结构如下:
|
||
```sql
|
||
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`被设置为`ON`或`ON_PERMISSIVE`时,GTIDs才会被存储到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。
|
||
|
||
如果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。 |