📖 数据密集型设计

主从复制与读写分离

深入探讨数据库主从复制与读写分离策略

一、主从复制概述

主从复制(Master-Slave Replication)是数据库高可用性和负载均衡的核心技术。通过将数据从主库复制到从库,实现读写分离,提升系统性能和可靠性。

二、主从复制原理

2.1 MySQL复制架构

MySQL主从复制基于二进制日志(Binary Log)实现:

graph TD A[主库 Master] --> B[二进制日志 Binary Log] B --> C[网络传输] C --> D[从库 Slave] D --> E[中继日志 Relay Log] E --> F[SQL线程] F --> G[从库数据] A --> A1[写入操作] A1 --> B

2.2 复制流程

sequenceDiagram participant Master as 主库 participant Slave as 从库 participant IO as IO线程 participant SQL as SQL线程 Master->>Slave: 发送二进制日志 IO->>Master: 请求日志 Master-->>IO: 返回日志事件 IO->>Slave: 写入中继日志 SQL->>Slave: 读取中继日志 SQL->>Slave: 执行SQL语句

2.3 复制类型

复制类型 原理 优点 缺点
基于语句 记录SQL语句 日志量小 可能不一致
基于行 记录行变更 一致性好 日志量大
混合模式 自动选择 平衡优缺点 复杂

三、主从复制配置

3.1 主库配置

[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
binlog_do_db = mydatabase
expire_logs_days = 7

3.2 从库配置

[mysqld]
server-id = 2
relay_log = /var/log/mysql/relay-bin.log
read_only = 1

3.3 启动复制

-- 主库创建复制用户
CREATE USER 'repl'@'slave_ip' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'slave_ip';

-- 从库配置复制
CHANGE MASTER TO
    MASTER_HOST='master_ip',
    MASTER_USER='repl',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='mysql-bin.000001',
    MASTER_LOG_POS=107;

START SLAVE;

四、读写分离策略

4.1 读写分离架构

graph TD A[应用程序] --> B{路由层} B --> C[写入请求] B --> D[读取请求] C --> E[主库 Master] D --> F[从库1 Slave1] D --> G[从库2 Slave2] D --> H[从库3 Slave3] E --> I[复制] I --> F I --> G I --> H

4.2 读写分离实现方式

应用层分离

在应用代码中实现读写分离:

public class DbRouter
{
    private readonly DbConnection _master;
    private readonly List<DbConnection> _slaves;
    
    public DbConnection GetConnection(bool isWrite)
    {
        if (isWrite) return _master;
        return _slaves[new Random().Next(_slaves.Count)];
    }
}

中间件分离

使用数据库中间件实现读写分离:

// MyCat配置示例
<dataNode name="dn1" dataHost="localhost1" database="db1"/>

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1">
    <writeHost host="hostM1" url="localhost:3306" user="root" password=""/>
    <readHost host="hostS1" url="localhost:3307" user="root" password=""/>
    <readHost host="hostS2" url="localhost:3308" user="root" password=""/>
</dataHost>

代理层分离

使用代理层实现读写分离:

# ProxySQL配置
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES
(1, 'master', 3306),
(2, 'slave1', 3306),
(2, 'slave2', 3306);

INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup) VALUES (1, 2);

五、主从延迟问题

5.1 延迟原因

  • 网络延迟:主从之间网络传输耗时
  • 从库负载:从库执行速度慢
  • 事务大小:大事务导致延迟
  • 并行度:单线程复制慢

5.2 延迟监控

-- 查看从库延迟
SHOW SLAVE STATUS\G

-- Seconds_Behind_Master 表示延迟秒数

5.3 延迟解决方案

方案 原理 适用场景
并行复制 多线程并行执行 高并发写入
半同步复制 等待至少一个从库确认 高一致性要求
延迟容忍读写 允许一定延迟 非实时查询
强制读主库 关键数据读主库 强一致性查询

六、高可用性设计

6.1 自动故障转移

使用工具实现自动故障转移:

graph TD A[主库故障] --> B{监控检测} B --> C[触发故障转移] C --> D[选择新主库] D --> E[提升从库为主库] E --> F[更新应用配置] F --> G[恢复服务]

6.2 常用高可用工具

工具 优点 缺点 适用场景
MHA 自动故障转移 维护复杂 MySQL
Orchestrator 可视化管理 依赖外部存储 MySQL
Patroni 支持多种数据库 配置复杂 PostgreSQL
Keepalived 简单高效 需要虚拟IP 通用

七、主从复制最佳实践

7.1 定期备份

定期备份主库数据,防止数据丢失。

7.2 监控复制状态

实时监控从库复制状态,及时发现问题。

7.3 避免大事务

将大事务拆分为小事务,减少复制延迟。

7.4 从库只读

设置从库为只读模式,防止误写入。

7.5 多从库负载均衡

使用多个从库分担读压力,实现负载均衡。

八、总结

主从复制和读写分离是构建高可用、高性能数据库系统的核心技术。通过合理配置和监控,能够实现系统的水平扩展和故障自动恢复,满足数据密集型应用的需求。