Appearance
MySQL 主从搭建
1. 主从复制的工作流程
MySQL 主从复制主要依赖以下三个核心组件:
- 主库的二进制日志(Binary Log)
- 从库的 I/O 线程(I/O Thread)
- 从库的 SQL 线程(SQL Thread)
复制过程可以分为以下几个步骤:
主库记录变更
主库开启了二进制日志(binlog),每当执行 DDL/DML 语句时,这些操作不会直接记录数据本身,而是以事件(Event)的形式记录到二进制日志中。
这些事件包含了操作的具体内容,比如 SQL 语句或者基于行的变更数据(取决于
binlog_format,可以是STATEMENT、ROW或MIXED格式)。二进制日志是按顺序写入的,每个事件都有一个唯一的日志位置(Log Position)。
从库读取二进制日志
从库通过 I/O 线程连接到主库,请求主库的二进制日志。
从库会告诉主库从哪个日志位置开始读取(通过
SOURCE_LOG_FILE和SOURCE_LOG_POS指定)。主库将新的二进制日志事件通过网络传输给从库的 I/O 线程。
I/O 线程接收到事件后,将其写入从库本地的中继日志(Relay Log)中。中继日志类似于主库的二进制日志,是从库用来暂存主库事件的缓冲区。
从库重放日志
从库的 SQL 线程读取中继日志中的事件,并按照顺序在本地数据库中执行这些事件。
执行完成后,从库的数据会与主库保持一致。
2. 主从复制的类型
根据同步方式和日志格式的不同,主从复制有以下几种类型:
异步复制:默认方式,主库写入 binlog 后立即返回,不等待从库同步完成;
- 优点:性能高;
- 缺点:可能存在数据不一致的风险;
半同步复制:主库在提交事务前,至少等待一个从库确认已接收 binlog;
- 优点:提高了数据一致性;
- 缺点:可能影响主库性能;
基于行的复制:binlog 记录具体的行数据变更;
- 优点:准确性高;
- 缺点:日志文件较大;
基于语句的复制:binlog 记录 SQL 语句;
- 优点:日志文件较小;
- 缺点:某些非确定性语句可能导致主从数据不一致;
3. 主从复制配置
3.1. 主库配置
my.cnf配置:INI[mysqld] server_id = 1 read_only = OFF binlog_format = ROWNote:
server_id需确保整个集群环境中唯一。重启 MySQL 服务器:
Bashsystemctl restart mysqld创建用于复制的账户:
SQLCREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';SQLGRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';SQLFLUSH PRIVILEGES;备份数据库:
Bashmysqldump -u root -p \ --databases dbname \ --single-transaction \ --source-data=2 \ --triggers \ --routines \ > backup.sql--single-transaction:在 InnoDB 引擎下保证数据一致性;--source-data=2:在备份文件中以注释形式生成CHANGE REPLICATION SOURCE TO ...语句;
Note:在 MySQL 8.0.26 之前请使用
--master-data选项代替--source-data选项。查看日志坐标信息:
打开生成的
backup.sql文件,查找类似于以下内容的注释行:After MySQL 8.0.26 SQL-- CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='binlog.000001', SOURCE_LOG_POS=12345;Before MySQL 8.0.26 SQL-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=12345;记下
SOURCE_LOG_FILE和SOURCE_LOG_POS,这些信息将在配置从库时使用。若希望手动指定从库的日志坐标,可以通过以下命令查看二进制日志坐标:
After MySQL 8.0.26 SQLSHOW BINARY LOG STATUS;Before MySQL 8.0.26 SQLSHOW MASTER STATUS输出如下:
Bash+---------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +---------------+----------+--------------+------------------+-------------------+ | binlog.000001 | 12345 | | | | +---------------+----------+--------------+------------------+-------------------+将
backup.sql文件传输到从库机器上。
3.2. 从库配置
my.cnf配置:INI[mysqld] server_id = 2 read_only = ON binlog_format = ROW replicate_do_db = dbname1
2
3
4
5Note:即使配置了
read_only = ON,管理员账号也依然是可写的,可以通过配置super_read_only = ON限制管理员账号只读。replicate_do_db=dbname:指定只复制某个或某些数据库;replicate_ignore_db=dbname:指定忽略某个或某些数据库的复制;replicate_do_table=dbname.table_name:指定只复制某个或某些表;replicate_ignore_table=dbname.table_name:指定忽略某个或某些表的复制;replicate_wild_do_table=dbname.table_pattern:使用通配符指定只复制匹配模式的表;replicate_wild_ignore_table=dbname.table_pattern:使用通配符指定忽略匹配模式的表;replicate_rewrite_db=old_name->new_name:将主库的某个数据库名重写为从库的另一个数据库名;
Note:上述选项可以根据需要重复配置多次。
通配符选项支持
%(任意字符任意长度)和_(单个字符)。重启 MySQL 服务器:
Bashsystemctl restart mysqld导入主库数据:
Bashmysql -u root -p < backup.sql连接主库:
After MySQL 8.0.26 SQLCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'master_host', SOURCE_USER = 'repl_user', SOURCE_PASSWORD = 'password', SOURCE_SSL = 0, GET_SOURCE_PUBLIC_KEY = 1, SOURCE_LOG_FILE = 'binlog.000001', SOURCE_LOG_POS = 12345;Before MySQL 8.0.26 SQLCHANGE MASTER TO MASTER_HOST = 'master_host', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'password', MASTER_SSL = 0, GET_MASTER_PUBLIC_KEY = 1, MASTER_LOG_FILE = 'binlog.000001', MASTER_LOG_POS = 12345;Note:
SOURCE_SSL和GET_SOURCE_PUBLIC_KEY明确禁用 SSL,让从库在连接时请求主库的公钥,用于加密认证信息,从而避免强制 SSL 连接。启动复制:
After MySQL 8.0.26 SQLSTART REPLICA;Before MySQL 8.0.26 SQLSTART SLAVE;检查同步状态:
After MySQL 8.0.26 SQLSHOW REPLICA STATUS\GBefore MySQL 8.0.26 SQLSHOW SLAVE STATUS\G检查
Slave_IO_Running和Slave_SQL_Running是否为Yes。Note:
Seconds_Behind_Master为延迟时间。
4. 双主复制配置
4.1. 配置 A
my.cnf配置:After MySQL 8.0.26 INI[mysqld] server_id = 1 read_only = OFF binlog_format = ROW log_replica_updates = ON replicate_do_db = dbname1
2
3
4
5
6Before MySQL 8.0.26 INI[mysqld] server_id = 1 read_only = OFF binlog_format = ROW log_slave_updates = ON replicate_do_db = dbname1
2
3
4
5
6重启 MySQL 服务器:
Bashsystemctl restart mysqld创建用于复制的账户:
SQLCREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';SQLGRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';SQLFLUSH PRIVILEGES;备份数据库:
Bashmysqldump -u root -p \ --databases dbname \ --single-transaction \ --source-data=2 \ --triggers \ --routines \ > backup.sql查看日志坐标信息:
打开生成的
backup.sql文件,查找类似于以下内容的注释行:After MySQL 8.0.26 SQL-- CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='binlog.000001', SOURCE_LOG_POS=12345;Before MySQL 8.0.26 SQL-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=12345;记下
SOURCE_LOG_FILE和SOURCE_LOG_POS,这些信息将在配置 B 库时使用。将
backup.sql文件传输到 B 库机器上。
4.2. 配置 B
导入 A 库数据:
Bashmysql -u root -p < backup.sqlmy.cnf配置:After MySQL 8.0.26 INI[mysqld] server_id = 2 read_only = OFF binlog_format = ROW log_replica_updates = ON replicate_do_db = dbname1
2
3
4
5
6Before MySQL 8.0.26 INI[mysqld] server_id = 2 read_only = OFF binlog_format = ROW log_slave_updates = ON replicate_do_db = dbname1
2
3
4
5
6重启 MySQL 服务器:
Bashsystemctl restart mysqld连接 A 库:
After MySQL 8.0.26 SQLCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'a_host', SOURCE_USER = 'repl_user', SOURCE_PASSWORD = 'password', SOURCE_SSL = 0, GET_SOURCE_PUBLIC_KEY = 1, SOURCE_LOG_FILE = 'binlog.000001', SOURCE_LOG_POS = 12345;Before MySQL 8.0.26 SQLCHANGE MASTER TO MASTER_HOST = 'a_host', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'password', MASTER_SSL = 0, GET_MASTER_PUBLIC_KEY = 1, MASTER_LOG_FILE = 'binlog.000001', MASTER_LOG_POS = 12345;启动复制:
After MySQL 8.0.26 SQLSTART REPLICA;Before MySQL 8.0.26 SQLSTART SLAVE;检查同步状态:
After MySQL 8.0.26 SQLSHOW REPLICA STATUS\GBefore MySQL 8.0.26 SQLSHOW SLAVE STATUS\G检查
Slave_IO_Running和Slave_SQL_Running是否为Yes。创建用于复制的账户:
SQLCREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';SQLGRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';SQLFLUSH PRIVILEGES;查看日志坐标信息:
After MySQL 8.0.26 SQLSHOW BINARY LOG STATUS;Before MySQL 8.0.26 SQLSHOW MASTER STATUS输出如下:
Bash+---------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +---------------+----------+--------------+------------------+-------------------+ | binlog.000002 | 23456 | | | | +---------------+----------+--------------+------------------+-------------------+记下
File和Position的值,这些信息将在配置 A 库时使用。
4.3. A 订阅 B
连接 B 库:
After MySQL 8.0.26 SQLCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'b_host', SOURCE_USER = 'repl_user', SOURCE_PASSWORD = 'password', SOURCE_SSL = 0, GET_SOURCE_PUBLIC_KEY = 1, SOURCE_LOG_FILE = 'binlog.000002', SOURCE_LOG_POS = 23456;1
2
3
4
5
6
7
8Before MySQL 8.0.26 SQLCHANGE MASTER TO MASTER_HOST = 'b_host', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'password', MASTER_SSL = 0, GET_MASTER_PUBLIC_KEY = 1, MASTER_LOG_FILE = 'binlog.000002', MASTER_LOG_POS = 23456;1
2
3
4
5
6
7
8启动复制:
After MySQL 8.0.26 SQLSTART REPLICA;Before MySQL 8.0.26 SQLSTART SLAVE;检查同步状态:
After MySQL 8.0.26 SQLSHOW REPLICA STATUS\GBefore MySQL 8.0.26 SQLSHOW SLAVE STATUS\G检查
Slave_IO_Running和Slave_SQL_Running是否为Yes。
5. GTID 复制配置
GTID(Global Transaction Identifier,全局事务标识符)是 MySQL 5.6 引入的特性,用于替代传统的基于二进制日志(binlog)文件名和位置(position)的复制方式。每个事务在提交时会被分配一个全局唯一的 GTID,其格式为 server_uuid:transaction_id。
server_uuid:MySQL 实例的唯一标识,首次启动时自动生成并存储在auto.cnf文件中;transaction_id:事务提交时按顺序分配的递增序列号,从 1 开始;
5.1. 配置 A
my.cnf配置:After MySQL 8.0.26 INI[mysqld] server_id = 1 read_only = OFF binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON log_replica_updates = ON replicate_do_db = dbname auto_increment_offset = 1 auto_increment_increment = 21
2
3
4
5
6
7
8
9
10Before MySQL 8.0.26 INI[mysqld] server_id = 1 read_only = OFF binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON log_slave_updates = ON replicate_do_db = dbname auto_increment_offset = 1 auto_increment_increment = 21
2
3
4
5
6
7
8
9
10重启 MySQL 服务器:
Bashsystemctl restart mysqld创建用于复制的账户:
SQLCREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';SQLGRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';SQLFLUSH PRIVILEGES;备份数据库:
Bashmysqldump -u root -p \ --set-gtid-purged=ON \ --databases dbname \ --single-transaction \ --source-data=2 \ --triggers \ --routines \ > backup.sql1
2
3
4
5
6
7
8--set-gtid-purged=ON:从库知道备份时主库的 GTID 状态,避免重复执行已包含在备份中的事务;
将
backup.sql文件传输到 B 库机器上。
5.2. 配置 B
my.cnf配置:After MySQL 8.0.26 INI[mysqld] server_id = 2 read_only = OFF binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON log_replica_updates = ON replicate_do_db = dbname auto_increment_offset = 2 auto_increment_increment = 21
2
3
4
5
6
7
8
9
10Before MySQL 8.0.26 INI[mysqld] server_id = 2 read_only = OFF binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON log_slave_updates = ON replicate_do_db = dbname auto_increment_offset = 2 auto_increment_increment = 21
2
3
4
5
6
7
8
9
10重启 MySQL 服务器:
Bashsystemctl restart mysqld导入 A 库数据:
Bashmysql -u root -p < backup.sql连接 A 库:
After MySQL 8.0.26 SQLCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'a_host', SOURCE_USER = 'repl_user', SOURCE_PASSWORD = 'password', SOURCE_SSL = 0, GET_SOURCE_PUBLIC_KEY = 1, SOURCE_AUTO_POSITION = 1;1
2
3
4
5
6
7Before MySQL 8.0.26 SQLCHANGE MASTER TO MASTER_HOST = 'a_host', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'password', MASTER_SSL = 0, GET_MASTER_PUBLIC_KEY = 1, MASTER_AUTO_POSITION = 1;1
2
3
4
5
6
7启动复制:
After MySQL 8.0.26 SQLSTART REPLICA;Before MySQL 8.0.26 SQLSTART SLAVE;检查同步状态:
After MySQL 8.0.26 SQLSHOW REPLICA STATUS\GBefore MySQL 8.0.26 SQLSHOW SLAVE STATUS\G检查
Slave_IO_Running和Slave_SQL_Running是否为Yes。创建用于复制的账户:
SQLCREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';SQLGRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';SQLFLUSH PRIVILEGES;
5.3. A 订阅 B
连接 B 库:
After MySQL 8.0.26 SQLCHANGE REPLICATION SOURCE TO SOURCE_HOST = 'b_host', SOURCE_USER = 'repl_user', SOURCE_PASSWORD = 'password', SOURCE_SSL = 0, GET_SOURCE_PUBLIC_KEY = 1, SOURCE_AUTO_POSITION = 1;1
2
3
4
5
6
7Before MySQL 8.0.26 SQLCHANGE MASTER TO MASTER_HOST = 'b_host', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'password', MASTER_SSL = 0, GET_MASTER_PUBLIC_KEY = 1, MASTER_AUTO_POSITION = 1;1
2
3
4
5
6
7启动复制:
After MySQL 8.0.26 SQLSTART REPLICA;Before MySQL 8.0.26 SQLSTART SLAVE;检查同步状态:
After MySQL 8.0.26 SQLSHOW REPLICA STATUS\GBefore MySQL 8.0.26 SQLSHOW SLAVE STATUS\G检查
Slave_IO_Running和Slave_SQL_Running是否为Yes。
5.4. 基于 GTID 复制的限制
由于基于 GTID 的复制依赖于事务,MySQL 中一些原本可用的功能在使用 GTID 时会受到限制。以下是有关 GTID 复制限制和局限性的信息:
更新涉及非事务性存储引擎
在使用 GTID 时,不能在同一语句或事务中对使用非事务性存储引擎(如
MyISAM)的表进行更新,同时对使用事务性存储引擎(如InnoDB)的表进行更新。这一限制的原因在于,在同一事务中混合对非事务性存储引擎表的更新和对事务性存储引擎表的更新,可能导致同一个事务被分配多个 GTID。当主库和从库对同一表的各自版本使用不同的存储引擎(一个是事务性的,另一个是非事务性的)时,也会出现类似问题。此外,需要注意的是,定义为操作非事务性表的触发器也可能是这些问题的原因。在上述任何情况下,事务与 GTID 之间的一一对应关系都会被打破,导致基于 GTID 的复制无法正常工作。
临时表
当
binlog_format设置为STATEMENT时,在使用 GTID(即系统变量enforce_gtid_consistency设置为ON)的情况下,CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句不能在事务、存储过程、函数或触发器中使用。在这些上下文之外使用 GTID 时,可以使用这些语句,前提是设置了autocommit=1。从 MySQL 8.0.13 开始,当
binlog_format设置为ROW或MIXED时,在使用 GTID 的情况下,允许在事务、存储过程、函数或触发器中使用CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句。这些语句不会写入二进制日志,因此不会复制到从库。基于行的复制意味着从库无需复制临时表即可保持同步。如果从事务中移除这些语句导致事务变为空,则该事务不会写入二进制日志。CREATE TABLE ... SELECT语句在 MySQL 8.0.21 之前,基于 GTID 的复制不允许使用
CREATE TABLE ... SELECT语句。当binlog_format设置为STATEMENT时,CREATE TABLE ... SELECT语句在二进制日志中记录为一个事务并分配一个 GTID;但如果使用ROW格式,该语句会被记录为两个事务并分配两个 GTID。如果主库使用STATEMENT格式,而从库使用ROW格式,从库将无法正确处理该事务,因此在使用 GTID 时禁用CREATE TABLE ... SELECT语句以避免这种情况。从 MySQL 8.0.21 开始,支持原子 DDL 的存储引擎取消了这一限制。在这种情况下,
CREATE TABLE ... SELECT在二进制日志中记录为一个事务。
更多详情请参考 MySQL 的官方说明文档。
6. 启用半同步复制
在半同步复制中,主库不会立即提交事务,而是等待至少一个从库确认已接收到事务并写入 Relay Log 后,才会将事务写入自己的 Binlog 并提交。这种方式可以减少主从数据不一致的风险。
从 MySQL 5.5 开始,MySQL 以插件的形式支持 Semi-Sync 半同步复制。
6.1. 检查是否已安装插件
Bash
mysql> show plugins;
+----------------------+----------+----------------+--------------------+---------+
| Name | Status | Type | Library | License |
+----------------------+----------+----------------+--------------------+---------+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
...
| rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL |
| rpl_semi_sync_slave | ACTIVE | REPLICATION | semisync_slave.so | GPL |
+----------------------+----------+----------------+--------------------+---------+1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
双主集群中,因为每个节点既是主库又是对方节点的从库,所以需要同时安装 rpl_semi_sync_master 和 rpl_semi_sync_slave 插件。
6.2. 加载半同步复制插件
如果未安装,则需加载半同步复制插件:
主库插件:
After MySQL 8.0.26 SQLINSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';Before MySQL 8.0.26 SQLINSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';从库插件:
After MySQL 8.0.26 SQLINSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';Before MySQL 8.0.26 SQLINSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
6.3. 修改 MySQL 配置文件
启用主库半同步复制:
After MySQL 8.0.26 INIrpl_semi_sync_source_enabled = 1 # 启用主库半同步复制 rpl_semi_sync_source_timeout = 10000 # 主库等待从库确认的超时时间(单位:毫秒,10 秒) rpl_semi_sync_source_wait_for_slave_count = 1 # 主库等待至少 1 个从库确认Before MySQL 8.0.26 INIrpl_semi_sync_master_enabled = 1 # 启用主库半同步复制 rpl_semi_sync_master_timeout = 10000 # 主库等待从库确认的超时时间(单位:毫秒,10 秒) rpl_semi_sync_master_wait_for_slave_count = 1 # 主库等待至少 1 个从库确认Tip:
rpl_semi_sync_source_timeout/rpl_semi_sync_master_timeout如果超时未收到从库确认,主库会降级为异步复制避免阻塞。启用从库半同步复制:
After MySQL 8.0.26 INIrpl_semi_sync_replica_enabled = 1 # 启用从库半同步复制Before MySQL 8.0.26 INIrpl_semi_sync_slave_enabled = 1 # 启用从库半同步复制
同理,双主集群中,需要同时启用主库和从库半同步复制,下不赘诉。
6.4. 验证半同步复制
查看半同步相关变量:
SQLSHOW VARIABLES LIKE 'rpl_semi_sync%';查看半同步运行状态:
SQLSHOW STATUS LIKE 'Rpl_semi_sync%';
关键状态变量:
Rpl_semi_sync_master_status:值为ON表示主库当前处于半同步模式;Rpl_semi_sync_master_clients:显示当前有多少从库参与半同步复制;Rpl_semi_sync_master_yes_tx:成功使用半同步提交的事务数;
7. 注意事项
复制延迟
MySQL 主从复制是异步或半同步的,数据在网络传输过程中会有一定延迟。在高并发场景下,主从同步的延迟可能导致数据在不同实例上不一致,影响查询结果。
触发器、存储过程等对象的定义不会自动同步,但其执行结果会同步
要实现完整同步,需通过手动操作在从库上创建这些对象。
数据一致性(主键冲突、更新冲突)
- 若使用
AUTO_INCREMENT生成主键,两台主库可能生成相同的主键值,引发插入冲突; - 若两台主库同时修改同一记录,例如一台更新字段 A,另一台更新字段 B,可能导致数据不一致;
对于主键冲突,一般推荐使用分布式 Id,或配置不同的
auto_increment_increment和auto_increment_offset避免自增 ID 冲突,例如:SQL-- 在 Server A SET GLOBAL auto_increment_increment = 2; SET GLOBAL auto_increment_offset = 1; -- 在 Server B SET GLOBAL auto_increment_increment = 2; SET GLOBAL auto_increment_offset = 2;这样 Server A 生成 1, 3, 5…,Server B 生成 2, 4, 6…,避免冲突。
而更新冲突可以通过业务逻辑或数据分片,尽量避免对同一记录在两台主库上同时写操作。
- 若使用
事务冲突
当多个事务在不同的主节点上进行写入操作时,可能会导致死锁或冲突回滚。尤其在使用并行复制(Parallel Replication)时,事务执行顺序可能不同步,影响数据一致性。
建议使用 GTID(全局事务标识符)复制。GTID 可以保证事务复制的唯一性,减少主从切换的复杂度:
INIgtid_mode = ON enforce_gtid_consistency = ON脑裂问题
如果某个 MySQL 节点故障,应用层需要快速检测并切换到可用的节点。需要避免脑裂(Split-Brain)问题,即两个节点都认为自己是主节点,导致数据不一致。
8. 小结
避免双写,建议一个节点写其它节点只读或分库写入:
- Active-Passive(一个节点写,一个节点读)通常更稳定;
- Active-Active 需要应用层保证数据不冲突,比如分库分表策略;