Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL8-SOP

  • MySQL实战45讲学习笔记

    • MySQL45讲学习笔记
    • MySQL基础架构
    • MySQL日志系统 (Redo Log 与 Binlog)
    • MySQL字符串字段索引优化
    • MySQL索引原理与优化
    • MySQL锁机制详解
    • MySQL事务与MVCC机制
    • MySQL普通索引与唯一索引的选择
    • MySQL优化器如何选择索引
    • MySQL抖动刷脏页
    • 表空间管理与回收
    • count函数详解
    • 日志索引
    • orderby工作原理
    • 随机排序实现
    • SQL性能差异函数与转换
    • 慢查询分析锁与版本
    • 幻读与间隙锁
    • 加锁规则分析
    • 应急性能优化方法
    • 数据持久化保证
    • 主备一致性原理
    • 高可用架构与切换
    • 备库延迟分析与优化
    • 主备切换GTID
    • 读写分离实践与问题
      • 1. 读写分离基础概念
        • 1.1 读写分离定义
        • 1.2 读写分离的优势
      • 2. 读写分离架构实现
        • 2.1 基本架构设计
        • 2.2 代理层实现方式
      • 3. 主从复制与同步
        • 3.1 主从复制原理
        • 3.2 同步延迟问题
      • 4. 读写分离实现方案
        • 4.1 应用层实现
        • 4.2 中间件实现
      • 5. 读写分离常见问题
        • 5.1 数据一致性问题
        • 5.2 事务处理问题
        • 5.3 负载均衡问题
      • 6. 读写分离优化策略
        • 6.1 读库负载优化
        • 6.2 写库性能优化
        • 6.3 故障切换优化
      • 7. 读写分离最佳实践
        • 7.1 配置优化建议
        • 7.2 监控和告警
        • 7.3 安全性考虑
      • 8. 实施步骤和注意事项
        • 8.1 实施步骤
        • 8.2 注意事项
      • 9. 总结
    • 数据库健康检查
    • 锁与死锁
    • 数据误删恢复
    • Kill命令详解
    • 查询与内存使用分析
    • Join原理与选择
    • 临时表原理与应用
    • 内部临时表详解
    • Memory引擎详解
    • 自增ID详解
    • Insert加锁分析
    • 表复制方法比较
    • Grant与权限管理
    • 分区表详解
    • SQL语句中的Join问题
    • 自增ID用尽问题
  • 专题系列
  • MySQL实战45讲学习笔记
Carry の Blog
2024-07-27
目录

读写分离实践与问题

# 读写分离实践与问题

读写分离是数据库架构中一种常见的优化策略,通过将读操作和写操作分别路由到不同的数据库实例,可以有效提升数据库的整体性能和扩展性。本文将深入探讨读写分离的实践方法和常见问题。

# 1. 读写分离基础概念

# 1.1 读写分离定义

读写分离是一种数据库架构模式,将数据库的读操作和写操作分配到不同的数据库实例上执行:

-- 写操作:发送到主库
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');

-- 读操作:发送到从库
SELECT * FROM users WHERE id = 1;
1
2
3
4
5

# 1.2 读写分离的优势

-- 读写分离的主要优势:
-- 1. 提升写入性能:主库专注处理写操作
-- 2. 提升读取性能:从库分担读操作压力
-- 3. 增强系统扩展性:可以水平扩展从库
-- 4. 提高可用性:主库故障时可快速切换

-- 性能对比示例
-- 无读写分离:单库处理所有请求
SELECT * FROM large_table WHERE condition;  -- 可能阻塞写操作

-- 读写分离:读操作走从库,写操作走主库
-- 读操作
SELECT * FROM large_table WHERE condition;  -- 从库处理,不影响主库

-- 写操作  
INSERT INTO large_table (col1, col2) VALUES ('val1', 'val2');  -- 主库处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2. 读写分离架构实现

# 2.1 基本架构设计

-- 读写分离典型架构:
-- 1. 主库(Master):处理所有写操作
-- 2. 从库(Slave):处理读操作
-- 3. 代理层(Proxy):负责请求路由

-- 架构图示意
-- 客户端 -> 代理层 -> 主库(写)/从库(读)
--        -> 代理层 -> 主库(写)/从库(读)
1
2
3
4
5
6
7
8

# 2.2 代理层实现方式

-- 代理层实现方式:
-- 1. 应用层代理:应用程序代码中实现路由逻辑
-- 2. 中间件代理:使用专门的数据库中间件
-- 3. 数据库代理:使用数据库自带的读写分离功能

-- 应用层代理示例(伪代码)
IF operation_type = 'WRITE' THEN
    route_to_master();
ELSE
    route_to_slave();
END IF;

-- 中间件代理示例(如MyCat)
-- 在配置文件中定义主从节点
-- <dataHost name="dh1">
--     <writeHost host="master" url="jdbc:mysql://master:3306" user="user" password="password"/>
--     <readHost host="slave1" url="jdbc:mysql://slave1:3306" user="user" password="password"/>
-- </dataHost>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3. 主从复制与同步

# 3.1 主从复制原理

-- 主从复制的工作原理:
-- 1. 主库将数据变更记录到二进制日志(binlog)
-- 2. 从库通过I/O线程读取binlog
-- 3. 从库通过SQL线程应用binlog中的变更

-- 查看主从状态
SHOW MASTER STATUS;
SHOW SLAVE STATUS\G;

-- 主从复制配置示例
-- 主库配置
server-id = 1
log-bin = mysql-bin
binlog-format = ROW

-- 从库配置
server-id = 2
relay-log = mysql-relay-bin
read-only = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3.2 同步延迟问题

-- 主从同步延迟问题:
-- 1. 网络延迟
-- 2. 从库负载过高
-- 3. 大事务处理
-- 4. 磁盘IO瓶颈

-- 监控同步延迟
SELECT 
    Slave_IO_Running,
    Slave_SQL_Running,
    Seconds_Behind_Master,
    Last_Error
FROM information_schema.slave_status;

-- 延迟监控脚本
DELIMITER //
CREATE PROCEDURE check_replication_delay()
BEGIN
    SELECT 
        'Replication Delay Check' as check_type,
        Seconds_Behind_Master as delay_seconds,
        CASE 
            WHEN Seconds_Behind_Master IS NULL THEN 'No Replication'
            WHEN Seconds_Behind_Master > 300 THEN 'High Delay'
            WHEN Seconds_Behind_Master > 60 THEN 'Medium Delay'
            ELSE 'Low Delay'
        END as delay_status
    FROM information_schema.slave_status;
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 4. 读写分离实现方案

# 4.1 应用层实现

-- 应用层读写分离实现:
-- 1. 配置多个数据库连接
-- 2. 根据操作类型路由请求
-- 3. 处理事务一致性

-- Java实现示例
public class ReadWriteSplitter {
    private static final String MASTER_URL = "jdbc:mysql://master:3306/db";
    private static final String SLAVE_URL = "jdbc:mysql://slave:3306/db";
    
    public Connection getConnection(boolean isWrite) throws SQLException {
        if (isWrite) {
            return DriverManager.getConnection(MASTER_URL, user, password);
        } else {
            return DriverManager.getConnection(SLAVE_URL, user, password);
        }
    }
}

-- Spring框架实现
@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    public DataSource masterDataSource() {
        // 主库数据源配置
    }
    
    @Bean
    public DataSource slaveDataSource() {
        // 从库数据源配置
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 4.2 中间件实现

-- 中间件读写分离实现:
-- 1. MyCat
-- 2. ShardingSphere
-- 3. ProxySQL

-- MyCat配置示例
-- schema.xml
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
    <table name="user" dataNode="dn1,dn2" rule="mod-long" />
</schema>

<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost2" database="db2" />

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
          writeType="0" dbType="mysql" dbDriver="native">
    <heartbeat>select user()</heartbeat>
    <writeHost host="hostM1" url="192.168.1.1:3306" user="root" password="123456"/>
</dataHost>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 5. 读写分离常见问题

# 5.1 数据一致性问题

-- 数据一致性问题:
-- 1. 主从延迟导致读取到旧数据
-- 2. 事务中的读写混合操作
-- 3. 强一致性要求场景

-- 解决方案:
-- 1. 读写分离时考虑延迟容忍度
-- 2. 对于强一致性要求的场景,直接读主库
-- 3. 实现最终一致性策略

-- 强一致性读取示例
-- 对于需要强一致性的操作,强制读主库
SELECT * FROM users WHERE id = 1;  -- 如果是刚写入的记录,强制读主库
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.2 事务处理问题

-- 事务处理问题:
-- 1. 事务跨库问题
-- 2. 事务中读写混合操作
-- 3. 分布式事务处理

-- 事务处理示例
-- 事务开始时确定数据源
BEGIN;
-- 如果涉及写操作,则使用主库
INSERT INTO orders (user_id, amount) VALUES (1, 100);
-- 如果后续读操作,可能需要读主库以保证一致性
SELECT * FROM orders WHERE user_id = 1;
COMMIT;

-- 避免跨库事务
-- 1. 将相关数据放在同一库中
-- 2. 使用分布式事务管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.3 负载均衡问题

-- 负载均衡问题:
-- 1. 从库负载不均
-- 2. 读写比例失衡
-- 3. 从库故障处理

-- 负载均衡策略
-- 1. 轮询策略
-- 2. 权重策略
-- 3. 响应时间策略

-- 负载监控脚本
DELIMITER //
CREATE PROCEDURE monitor_load_balance()
BEGIN
    SELECT 
        'Load Balance Monitoring' as check_type,
        COUNT(*) as total_connections,
        (SELECT COUNT(*) FROM information_schema.processlist WHERE COMMAND != 'Sleep') as active_connections,
        (SELECT COUNT(*) FROM information_schema.processlist WHERE COMMAND = 'Sleep') as sleeping_connections
    FROM information_schema.processlist;
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6. 读写分离优化策略

# 6.1 读库负载优化

-- 读库负载优化:
-- 1. 合理配置从库数量
-- 2. 优化查询语句
-- 3. 使用缓存层

-- 查询优化示例
-- 优化前:全表扫描
SELECT * FROM large_table WHERE condition;

-- 优化后:使用索引
CREATE INDEX idx_condition ON large_table(condition);
SELECT * FROM large_table WHERE condition;
1
2
3
4
5
6
7
8
9
10
11
12

# 6.2 写库性能优化

-- 写库性能优化:
-- 1. 批量写入
-- 2. 异步写入
-- 3. 事务优化

-- 批量写入示例
-- 优化前:单条插入
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
INSERT INTO users (name, email) VALUES ('Jane', 'jane@example.com');

-- 优化后:批量插入
INSERT INTO users (name, email) VALUES 
    ('John', 'john@example.com'),
    ('Jane', 'jane@example.com'),
    ('Bob', 'bob@example.com');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 6.3 故障切换优化

-- 故障切换优化:
-- 1. 自动故障检测
-- 2. 快速故障切换
-- 3. 数据一致性保障

-- 故障检测脚本
DELIMITER //
CREATE PROCEDURE detect_master_failure()
BEGIN
    DECLARE master_status VARCHAR(10);
    
    SELECT 
        CASE 
            WHEN @@read_only = 0 THEN 'MASTER'
            ELSE 'SLAVE'
        END INTO master_status;
        
    SELECT 
        'Master Detection' as check_type,
        master_status as current_role,
        CASE 
            WHEN master_status = 'MASTER' THEN 'Normal'
            ELSE 'Potential Issue'
        END as status;
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 7. 读写分离最佳实践

# 7.1 配置优化建议

-- 读写分离配置优化:
-- 1. 主从配置参数调优
-- 2. 连接池配置
-- 3. 超时设置

-- 主库配置优化
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
SET GLOBAL sync_binlog = 100;

-- 从库配置优化
SET GLOBAL read_only = 1;
SET GLOBAL innodb_read_only = 1;

-- 连接池配置示例
-- 应用程序连接池设置
maxActive = 20
maxIdle = 10
minIdle = 5
maxWait = 60000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 7.2 监控和告警

-- 读写分离监控:
-- 1. 连接数监控
-- 2. 延迟监控
-- 3. 性能监控

-- 监控脚本
DELIMITER //
CREATE PROCEDURE read_write_monitor()
BEGIN
    SELECT 
        'ReadWrite Split Monitor' as monitor_type,
        (SELECT COUNT(*) FROM information_schema.processlist WHERE COMMAND != 'Sleep') as active_connections,
        (SELECT COUNT(*) FROM information_schema.processlist WHERE COMMAND = 'Sleep') as sleeping_connections,
        (SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Threads_connected') as total_connections,
        (SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME = 'Seconds_Behind_Master') as replication_delay;
END //
DELIMITER ;

-- 告警配置示例
-- 当延迟超过5分钟时告警
-- 当连接数超过最大连接数的80%时告警
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 7.3 安全性考虑

-- 读写分离安全性:
-- 1. 网络隔离
-- 2. 权限控制
-- 3. 数据加密

-- 权限控制示例
-- 主库用户权限
CREATE USER 'master_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE, DELETE ON database.* TO 'master_user'@'%';

-- 从库用户权限
CREATE USER 'slave_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON database.* TO 'slave_user'@'%';
REVOKE INSERT, UPDATE, DELETE ON database.* FROM 'slave_user'@'%';
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 8. 实施步骤和注意事项

# 8.1 实施步骤

-- 读写分离实施步骤:
-- 1. 架构评估和规划
-- 2. 主从环境搭建
-- 3. 代理层部署
-- 4. 应用改造
-- 5. 测试验证
-- 6. 上线部署

-- 架构规划示例
-- 评估现有系统负载
-- 确定读写比例
-- 选择合适的中间件
-- 设计故障切换方案
1
2
3
4
5
6
7
8
9
10
11
12
13

# 8.2 注意事项

-- 实施注意事项:
-- 1. 数据一致性风险
-- 2. 应用改造成本
-- 3. 故障处理复杂性
-- 4. 性能监控要求

-- 逐步实施建议:
-- 1. 先在非核心业务上测试
-- 2. 逐步迁移业务流量
-- 3. 建立完善的监控体系
-- 4. 制定详细的回滚方案
1
2
3
4
5
6
7
8
9
10
11

# 9. 总结

读写分离是提升数据库性能和扩展性的重要手段,但在实施过程中需要注意诸多细节。通过合理的架构设计、充分的测试验证和完善的监控体系,可以有效发挥读写分离的优势。

关键要点包括:

  1. 架构设计:合理规划主从架构,选择合适的代理层
  2. 数据一致性:权衡性能和一致性需求,制定相应策略
  3. 性能优化:针对读写特点进行参数调优和查询优化
  4. 故障处理:建立完善的故障检测和切换机制
  5. 监控告警:持续监控系统状态,及时发现和处理问题

通过系统性的实施和优化,读写分离能够显著提升数据库系统的整体性能和可扩展性,为业务发展提供有力支撑。

#MySQL#读写分离#主从复制#数据库架构
上次更新: 3/5/2026

← 主备切换GTID 数据库健康检查→

最近更新
01
MySQL抖动刷脏页
03-05
02
表空间管理与回收
03-05
03
count函数详解
03-05
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式