Skip to content

Oracle 读写分离配置

读写分离定义

  • 读写分离是一种数据库架构设计,将读操作和写操作分离到不同的数据库实例上
  • 写操作集中在主数据库上,读操作分布在多个从数据库上
  • 通过负载均衡技术将读请求分发到多个从库,提高系统的整体性能和可用性
  • 适用于读多写少的应用场景,如电商、内容管理系统等

读写分离优势

  • 性能提升:分散读操作负载,提高系统整体吞吐量
  • 高可用性:主库故障时可以快速切换到从库
  • 扩展性:可以根据读负载水平扩展从库数量
  • 资源利用:合理利用硬件资源,主库专注于写操作
  • 成本优化:可以使用不同配置的服务器,从库可以使用较低配置

读写分离架构

基础架构

主从复制架构

  • 主库:处理所有写操作,负责数据变更
  • 从库:通过数据复制从主库获取数据,处理读操作
  • 复制机制:使用Oracle Data Guard或其他复制技术
  • 负载均衡:通过负载均衡器分发读请求

架构组件

  • 主数据库:生产环境的主要数据库,处理所有写操作
  • 从数据库:通过复制同步主库数据的数据库实例,处理读操作
  • 复制机制:Oracle Data Guard、Oracle GoldenGate等
  • 负载均衡器:分发读请求到从库,如F5、Nginx、Oracle RAC等
  • 应用层:修改应用程序以支持读写分离

高级架构

多级架构

  • 主库:处理写操作
  • 一级从库:直接从主库复制,处理部分读操作
  • 二级从库:从一级从库复制,处理更多读操作
  • 分发策略:根据查询复杂度和数据新鲜度分发请求

混合架构

  • 本地从库:处理低延迟要求的读操作
  • 远程从库:处理报表、分析等对延迟不敏感的读操作
  • 云从库:利用云资源弹性扩展读能力

实现方案

Oracle Data Guard 方案

架构设计

  • 主库:生产数据库,配置为主库角色
  • 备库:使用Data Guard配置为物理备库或逻辑备库
  • 角色:物理备库(只读)或逻辑备库(可读写,但通常用于只读)
  • 复制模式:最大可用性、最大性能或最大保护模式

配置步骤

  1. 配置主库

    • 启用归档模式
    • 配置闪回恢复区
    • 启用强制日志记录
    • 配置初始化参数
  2. 创建备库

    • 使用RMAN复制主库
    • 配置备库初始化参数
    • 建立主备库网络连接
    • 配置Data Guard broker(可选)
  3. 配置只读模式

    • 将备库设置为只读模式
    • 配置备库的监听
    • 测试备库的只读访问
  4. 配置负载均衡

    • 配置负载均衡器
    • 设置健康检查
    • 配置分发策略
    • 测试负载均衡功能

示例配置

sql
-- 主库配置
ALTER SYSTEM SET LOG_ARCHIVE_CONFIG = 'DG_CONFIG=(PRIMARY,STANDBY1,STANDBY2)';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_1 = 'LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=PRIMARY';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_2 = 'SERVICE=STANDBY1 ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=STANDBY1';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_3 = 'SERVICE=STANDBY2 ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=STANDBY2';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_1 = 'ENABLE';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2 = 'ENABLE';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_3 = 'ENABLE';

-- 备库配置
ALTER SYSTEM SET LOG_ARCHIVE_CONFIG = 'DG_CONFIG=(PRIMARY,STANDBY1)';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_1 = 'LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=STANDBY1';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_2 = 'SERVICE=PRIMARY ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=PRIMARY';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_1 = 'ENABLE';
ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2 = 'ENABLE';

-- 备库设置为只读模式
ALTER DATABASE OPEN READ ONLY;

Oracle GoldenGate 方案

架构设计

  • 主库:生产数据库,配置GoldenGate抽取进程
  • 从库:目标数据库,配置GoldenGate应用进程
  • 复制机制:基于日志的异步复制
  • 延迟:通常比Data Guard有更高的延迟,但更灵活

配置步骤

  1. 安装GoldenGate

    • 在主库和从库安装GoldenGate
    • 配置GoldenGate环境变量
    • 创建GoldenGate子目录
  2. 配置主库

    • 启用 supplemental logging
    • 创建GoldenGate管理用户
    • 配置抽取进程
    • 配置 trail文件
  3. 配置从库

    • 创建GoldenGate管理用户
    • 配置复制进程
    • 配置冲突解决策略(如果需要)
  4. 启动和验证

    • 启动抽取进程
    • 启动复制进程
    • 验证数据同步
    • 测试读操作

适用场景

  • 异构环境:从Oracle复制到其他数据库
  • 选择性复制:只复制特定表或列
  • 跨版本复制:支持不同Oracle版本之间的复制
  • 双向复制:支持双向复制(需要额外配置)

应用层实现

应用改造

代码修改

  • 连接管理:创建独立的读连接池和写连接池
  • SQL路由:根据操作类型选择连接池
  • 事务处理:确保事务中的读写操作使用同一连接
  • 错误处理:处理连接失败和故障转移

示例代码

java
// 连接池配置
DataSource writeDataSource = configureWriteDataSource();
DataSource readDataSource = configureReadDataSource();

// 获取连接
public Connection getConnection(boolean forWrite) {
    if (forWrite) {
        return writeDataSource.getConnection();
    } else {
        return readDataSource.getConnection();
    }
}

// 执行SQL
public void executeUpdate(String sql, Object... params) {
    try (Connection conn = getConnection(true);
         PreparedStatement ps = conn.prepareStatement(sql)) {
        // 设置参数并执行
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i + 1, params[i]);
        }
        ps.executeUpdate();
    }
}

public ResultSet executeQuery(String sql, Object... params) {
    try (Connection conn = getConnection(false);
         PreparedStatement ps = conn.prepareStatement(sql)) {
        // 设置参数并执行
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i + 1, params[i]);
        }
        return ps.executeQuery();
    }
}

中间件实现

连接池中间件

  • Oracle Connection Pool:支持连接池和负载均衡
  • DBCP:Apache DBCP支持读写分离
  • Druid:阿里巴巴Druid连接池,内置读写分离支持
  • HikariCP:高性能连接池,可扩展支持读写分离

代理层实现

  • MySQL Proxy:虽然是MySQL的,但理念可参考
  • PgBouncer:PostgreSQL的连接池,理念可参考
  • 自定义代理:开发专用的数据库代理层

框架支持

  • Spring:使用Spring的AbstractRoutingDataSource实现
  • MyBatis:通过插件或配置实现
  • Hibernate:通过配置和拦截器实现

负载均衡配置

硬件负载均衡

F5配置

  • 配置虚拟服务器:创建用于读操作的虚拟服务器
  • 配置池:添加所有从库到池
  • 健康检查:配置数据库健康检查
  • 负载均衡算法:轮询、最小连接数等
  • 会话持久性:根据需要配置会话持久性

配置示例

  • 虚拟服务器:192.168.1.100:1521
  • 池成员
    • 192.168.1.10:1521(从库1)
    • 192.168.1.11:1521(从库2)
    • 192.168.1.12:1521(从库3)
  • 健康检查:TCP端口检查 + SQL查询检查
  • 负载均衡方法:轮询

软件负载均衡

Nginx配置

  • 安装Nginx:安装支持TCP负载均衡的Nginx版本
  • 配置stream模块:配置TCP负载均衡
  • 添加后端服务器:配置从库服务器
  • 健康检查:配置健康检查机制

配置示例

nginx
stream {
    upstream oracle_read {
        server 192.168.1.10:1521 max_fails=3 fail_timeout=30s;
        server 192.168.1.11:1521 max_fails=3 fail_timeout=30s;
        server 192.168.1.12:1521 max_fails=3 fail_timeout=30s;
    }
    
    server {
        listen 1521;
        proxy_pass oracle_read;
        proxy_connect_timeout 10s;
        proxy_timeout 30s;
    }
}

HAProxy配置

  • 安装HAProxy:安装HAProxy
  • 配置TCP负载均衡:配置Oracle数据库的TCP负载均衡
  • 添加后端服务器:配置从库服务器
  • 健康检查:配置健康检查

配置示例

txt
frontend oracle_read
    bind *:1521
    mode tcp
    default_backend oracle_read_servers

backend oracle_read_servers
    mode tcp
    balance roundrobin
    server db1 192.168.1.10:1521 check inter 10s rise 2 fall 3
    server db2 192.168.1.11:1521 check inter 10s rise 2 fall 3
    server db3 192.168.1.12:1521 check inter 10s rise 2 fall 3

数据一致性

复制延迟

延迟原因

  • 网络延迟:主库和从库之间的网络传输时间
  • 处理延迟:从库应用 redo 日志的时间
  • 负载影响:从库负载过高导致应用延迟
  • 批量操作:大批量操作导致大量日志生成

监控和管理

  • 监控延迟:使用Oracle视图监控复制延迟
  • 设置阈值:设置可接受的延迟阈值
  • 告警机制:当延迟超过阈值时触发告警
  • 动态调整:根据延迟情况调整读请求分发

示例监控

sql
-- 监控Data Guard延迟
SELECT 
    dest_name,
    current_scn,
    applied_scn,
    round((current_scn - applied_scn) * 8 / 1024, 2) as "MB Behind",
    time_seconds as "Seconds Behind"
FROM 
    v$dataguard_stats
WHERE 
    name = 'apply lag';

-- 监控GoldenGate延迟
SELECT 
    extract_name,
    current_lag
FROM 
    gg_extract_status;

一致性策略

强一致性

  • 读主库:对一致性要求高的读操作直接读主库
  • 会话绑定:同一用户会话的读写操作使用同一连接
  • 事务隔离:确保事务中的读写操作使用同一连接

最终一致性

  • 接受延迟:应用可以接受一定程度的数据延迟
  • 时间标记:在数据中添加时间标记,应用根据需要选择数据源
  • 异步处理:将对一致性要求不高的操作异步处理

混合策略

  • 关键数据:关键数据的读操作走主库
  • 非关键数据:非关键数据的读操作走从库
  • 动态切换:根据业务场景动态选择数据源

故障处理

主库故障

故障检测

  • 心跳检测:通过定期心跳检测主库状态
  • 应用检测:应用程序检测写操作失败
  • 监控系统:监控系统检测主库不可用

故障转移

  1. 选择新主库:从健康的从库中选择一个作为新主库
  2. 提升备库:将选中的备库提升为新主库
  3. 更新连接:更新应用程序的写连接指向新主库
  4. 重新配置:将其他从库重新指向新主库
  5. 验证:验证新主库的功能

示例步骤

sql
-- 将备库提升为新主库(Data Guard)
ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;

-- 启动新主库
ALTER DATABASE OPEN;

-- 其他从库重新指向新主库
ALTER SYSTEM SET LOG_ARCHIVE_DEST_2 = 'SERVICE=new_primary ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=new_primary';

从库故障

故障检测

  • 健康检查:负载均衡器的健康检查
  • 应用检测:应用程序检测读操作失败
  • 监控系统:监控系统检测从库不可用

故障处理

  1. 从负载均衡中移除:将故障从库从负载均衡池中移除
  2. 诊断和修复:诊断从库故障原因并修复
  3. 重新同步:修复后重新同步数据
  4. 重新加入:数据同步后将从库重新加入负载均衡池
  5. 验证:验证从库的功能

自动恢复

  • 自动检测:负载均衡器自动检测从库状态
  • 自动移除:故障从库自动从池中移除
  • 自动加入:恢复后自动重新加入池
  • 告警通知:发送告警通知管理员

性能优化

从库优化

参数优化

  • 内存配置:增加SGA和PGA以提高查询性能
  • 并行查询:启用并行查询以提高复杂查询性能
  • 缓存设置:优化缓冲区缓存和共享池
  • I/O优化:优化存储I/O性能

示例参数

sql
-- 从库内存配置
ALTER SYSTEM SET sga_target = '8G' SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_target = '4G' SCOPE=SPFILE;

-- 并行查询配置
ALTER SYSTEM SET parallel_max_servers = 16 SCOPE=SPFILE;
ALTER SYSTEM SET parallel_execution_message_size = 16384 SCOPE=SPFILE;

-- 缓存优化
ALTER SYSTEM SET db_cache_size = '4G' SCOPE=SPFILE;
ALTER SYSTEM SET shared_pool_size = '2G' SCOPE=SPFILE;

索引优化

  • 查询优化:为频繁的读查询创建适当的索引
  • 分区索引:对大表使用分区索引
  • 位图索引:对低基数列使用位图索引
  • 函数索引:为频繁使用的函数创建函数索引

存储优化

  • 存储配置:使用高性能存储
  • RAID级别:使用适当的RAID级别
  • 文件布局:优化数据文件和日志文件布局
  • 存储缓存:配置适当的存储缓存

查询优化

查询路由

  • 基于类型:根据查询类型路由到不同从库
  • 基于复杂度:复杂查询路由到配置更高的从库
  • 基于频率:频繁查询路由到缓存更热的从库
  • 基于数据:根据数据分布路由查询

查询重写

  • 优化查询:重写复杂查询以提高性能
  • 避免全表扫描:为频繁查询创建索引
  • 使用绑定变量:减少硬解析
  • 合理使用HINT:使用适当的查询提示

缓存策略

  • 应用缓存:在应用层缓存热点数据
  • 数据库缓存:优化数据库缓存
  • 中间件缓存:使用Redis等中间件缓存
  • 结果缓存:使用Oracle的结果缓存功能

监控和管理

监控指标

数据库指标

  • 复制延迟:监控主从复制延迟
  • 从库状态:监控所有从库的状态
  • 读负载:监控从库的读负载
  • 资源使用:监控CPU、内存、I/O等资源使用
  • 查询性能:监控慢查询和高频查询

系统指标

  • 负载均衡器:监控负载均衡器的状态和性能
  • 网络:监控网络延迟和吞吐量
  • 存储:监控存储性能和空间使用
  • 服务器:监控服务器的健康状态

应用指标

  • 响应时间:监控应用程序的响应时间
  • 错误率:监控应用程序的错误率
  • 连接数:监控数据库连接数
  • 吞吐量:监控应用程序的吞吐量

管理工具

Oracle Enterprise Manager

  • 监控面板:创建专门的读写分离监控面板
  • 告警设置:设置复制延迟、从库状态等告警
  • 性能分析:分析数据库性能问题
  • 自动化任务:配置自动化的维护任务

自定义监控

  • 脚本监控:编写脚本监控关键指标
  • 告警系统:集成到企业告警系统
  • Dashboard:创建自定义的监控Dashboard
  • 自动化工具:开发自动化的故障处理工具

第三方工具

  • Zabbix:监控数据库和服务器状态
  • Prometheus:监控各种指标并存储
  • Grafana:创建可视化监控面板
  • Nagios:监控系统和服务状态

版本差异考虑

Oracle 11g

  • 复制选项:使用Data Guard或GoldenGate
  • 管理工具:使用Enterprise Manager 11g
  • 性能特性:基本的查询优化功能
  • 最佳实践:使用基本的主从架构,关注复制延迟

Oracle 12c

  • 复制选项:增强的Data Guard功能
  • 多租户:支持多租户架构的读写分离
  • 性能特性:增强的并行查询和内存管理
  • 最佳实践:利用多租户特性,优化从库配置

Oracle 19c

  • 复制选项:进一步增强的Data Guard功能
  • 自动索引:从库可以利用自动索引
  • 性能特性:实时统计信息、自适应执行计划
  • 最佳实践:利用自动性能优化特性,简化管理

Oracle 21c

  • 复制选项:更智能的Data Guard功能
  • AI特性:利用AI辅助的性能优化
  • 实时分析:增强的实时分析能力
  • 最佳实践:利用智能化特性,实现更高级的读写分离策略

常见问题(FAQ)

Q1: 读写分离适合哪些应用场景?

A1: 读写分离适合的应用场景:

  • 读多写少:如电商、内容管理系统、新闻网站
  • 报表分析:有大量报表和分析查询的系统
  • 高并发:需要处理高并发读请求的系统
  • 全球部署:需要在不同地区提供数据访问的系统
  • 灾备需求:同时需要灾备能力的系统

Q2: 如何选择合适的复制技术?

A2: 选择复制技术的考虑因素:

  • 数据一致性:Data Guard提供更强的一致性
  • 灵活性:GoldenGate提供更灵活的复制选项
  • 延迟要求:对延迟敏感的应用选择Data Guard
  • 异构需求:需要复制到其他数据库选择GoldenGate
  • 管理复杂度:Data Guard相对简单,GoldenGate更复杂

Q3: 如何处理复制延迟问题?

A3: 处理复制延迟的方法:

  • 监控延迟:设置合理的延迟监控
  • 动态路由:延迟超过阈值时将读请求路由到主库
  • 应用适配:修改应用接受一定程度的延迟
  • 优化复制:优化复制配置,减少延迟
  • 从库扩展:增加从库数量,分散负载

Q4: 如何实现应用层的读写分离?

A4: 实现应用层读写分离的方法:

  • 连接池分离:创建独立的读写连接池
  • SQL路由:根据SQL类型自动路由
  • 框架支持:利用ORM框架的读写分离支持
  • 中间件:使用数据库中间件实现
  • 代理层:在应用和数据库之间添加代理层

Q5: 如何处理主库故障?

A5: 处理主库故障的方法:

  • 故障检测:使用心跳检测和监控系统
  • 快速切换:配置自动或半自动的故障转移
  • 数据验证:确保新主库数据完整
  • 连接更新:更新应用程序的连接配置
  • 从库重配置:将其他从库重新指向新主库

Q6: 如何评估读写分离的效果?

A6: 评估读写分离效果的方法:

  • 性能提升:比较实施前后的系统性能
  • 负载分布:分析读负载在从库之间的分布
  • 可用性:评估系统的可用性提升
  • 扩展性:测试系统的横向扩展能力
  • 成本效益:分析实施成本和收益

Q7: 如何选择负载均衡策略?

A7: 选择负载均衡策略的考虑因素:

  • 应用特点:根据应用的特点选择策略
  • 服务器配置:考虑从库的硬件配置
  • 查询类型:根据查询的类型和复杂度
  • 会话要求:是否需要会话持久性
  • 性能目标:追求吞吐量还是响应时间

Q8: 如何处理从库的只读限制?

A8: 处理从库只读限制的方法:

  • 应用适配:修改应用避免在从库上执行写操作
  • 连接管理:确保写操作只使用主库连接
  • 错误处理:优雅处理从库的只读错误
  • 权限控制:在从库上限制写权限
  • 监控:监控从库上的写操作尝试

Q9: 如何实现全球部署的读写分离?

A9: 实现全球部署读写分离的方法:

  • 区域从库:在不同地区部署从库
  • CDN:使用CDN缓存静态内容
  • 智能路由:根据用户位置路由请求
  • 数据中心:在多个数据中心部署从库
  • 复制策略:使用合适的复制策略减少跨地域延迟

Q10: 如何优化从库的查询性能?

A10: 优化从库查询性能的方法:

  • 硬件配置:为从库配置合适的硬件
  • 内存优化:增加从库的内存配置
  • 索引优化:为频繁查询创建合适的索引
  • 参数调整:调整从库的数据库参数
  • 存储优化:使用高性能存储
  • 并行查询:启用适当的并行查询

Q11: 如何处理大量小查询的场景?

A11: 处理大量小查询场景的方法:

  • 连接池:优化连接池配置
  • 批量处理:合并多个小查询为批量查询
  • 缓存:使用缓存减少数据库查询
  • 负载均衡:使用合适的负载均衡策略
  • 数据库参数:调整数据库参数以优化小查询性能

Q12: 如何实现读写分离的自动化管理?

A12: 实现读写分离自动化管理的方法:

  • 自动监控:设置自动监控和告警
  • 自动故障转移:配置自动故障检测和转移
  • 自动扩展:根据负载自动添加或移除从库
  • 自动优化:自动优化数据库参数和查询
  • 智能路由:基于实时情况智能路由请求

Q13: 如何处理跨库事务?

A13: 处理跨库事务的方法:

  • 避免跨库:尽量避免跨库事务
  • 两阶段提交:使用两阶段提交协议(性能较差)
  • 消息队列:使用消息队列实现最终一致性
  • 本地事务:将跨库操作拆分为本地事务
  • 补偿机制:实现事务补偿机制

Q14: 如何评估从库的数量?

A14: 评估从库数量的方法:

  • 读负载:根据读负载计算需要的从库数量
  • 性能目标:根据性能目标确定从库数量
  • 容错要求:考虑容错要求,确保有足够的从库
  • 预算限制:根据预算限制调整从库数量
  • 扩展性:预留一定的扩展空间

Q15: 如何实现读写分离的安全管理?

A15: 实现读写分离安全管理的方法:

  • 权限控制:为从库用户设置只读权限
  • 网络隔离:隔离主库和从库的网络
  • 加密传输:使用加密传输数据
  • 审计:启用数据库审计
  • 访问控制:控制对负载均衡器的访问
  • 定期检查:定期检查安全配置