高可用与运维:金仓数据库生产环境部署与运维实战
数据库上线并不难难的是上线以后一直稳定运行。生产环境里真正考验运维能力的通常不是安装和初始化而是几个更实际的问题主库故障后能不能按预期切换备库延迟升高时能不能及时发现业务连接突然打满时能不能迅速恢复以及备份到了真正需要时能不能还原。下面结合项目中的部署和运维经验谈谈金仓数据库在高可用选型、故障处理和日常运维方面需要注意的事项。文中的命令以常见环境为例实际使用前仍应结合数据库版本、部署路径和业务要求进行确认。一、先看业务再决定集群怎么建高可用方案没有统一答案。读流量占比、写入峰值、是否允许短时中断以及 RTO、RPO 要求都会影响最终选择。项目初期如果只看产品功能不看真实流量模型集群即使搭起来后面也很容易出现资源闲置或能力不足的问题。1. 读写分离适合读多写少的系统读写分离一般由一个主实例和若干备实例组成。写请求进入主库备库持续同步数据并承接部分查询请求。这样做既保留了主备切换能力也能把一部分读压力从主库上移走。读写请求如何分流常见有两种做法。由应用识别读写 SQL。写请求固定访问主库读请求分发到备库。这种方式控制更直接适合有条件改造代码的系统。在数据库前增加代理由代理统一识别和转发请求。它对业务代码影响较小多套应用共同访问数据库时更容易管理但也要评估代理自身的性能和高可用。这里有一个容易踩的坑并不是所有查询都适合发往备库。事务中的查询、写入后需要马上读到结果的查询以及对实时一致性要求较高的查询通常应留在主库。否则备库尚未追平主库日志时应用可能读到旧数据。这个问题在测试环境不一定明显到了写入高峰期才容易暴露。主备集群不能只检查数据库进程是否存在。进程正常不代表网络、复制链路和节点角色都正常。生产部署时至少应综合判断实例状态、节点连通性和复制状态避免网络分区时发生误切换甚至脑裂。主库故障后集群通常会经过多轮探测再提升备库。这里不建议笼统承诺“几秒内一定完成”更稳妥的做法是在正式上线前按现场配置做故障演练分别测试进程退出、主机断电、业务网络中断和心跳网络中断。只有演练得到的数据才能作为这个项目的切换基线。可以通过以下 SQL 查看复制状态和日志位点差异-- 查看备节点同步状态 SELECT pid, usename, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM sys_stat_replication; -- 计算发送位点与回放位点之间的差值字节 SELECT pid, sent_lsn, replay_lsn, sys_calc_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes FROM sys_stat_replication;操作系统侧也可以先做最基本的检查ps -ef | grep kes netstat -tulnp | grep kes不过grep查到进程只能说明进程存在不能代替数据库可用性探测。更完整的监控还应包含登录测试、简单 SQL 探测和复制链路检查。读写分离的边界也比较清楚增加备节点可以提高读能力但写入最终仍集中在主实例。如果系统的主要矛盾是写压力继续增加备库意义有限这时应评估主库硬件、SQL 和索引设计必要时再考虑业务拆分。2. KES RAC多实例承载核心业务KES RAC 使用多实例共享存储架构多个实例访问同一套数据均可承担读写请求。与单写主库相比它更适合并发量较高、对实例故障恢复时间要求严格的业务。连接通常按照预设权重分发到活跃实例。对于要求同一会话固定落在某个实例上的业务可以配置会话粘性。部署后要持续观察各实例连接数不能只确认负载均衡功能已经开启连接池配置不合理时大量长连接仍可能集中在少数实例上。RAC 项目中我通常会重点核对三件事共享存储的性能和冗余是否满足要求。存储是所有实例共同依赖的基础数据库节点做了冗余并不等于整套架构已经没有单点。心跳和缓存同步网络是否与业务网络隔离。内部通信最好使用独立网卡和链路避免业务流量高峰影响集群通信。故障实例被隔离后连接能否真正迁移到健康实例。这个能力与客户端、连接串和连接池配置有关不能只在数据库侧验证。日常可用下面的语句查看实例状态和连接分布-- 查看集群实例信息 SELECT inst_id, inst_name, host_name, status, role FROM sys_cluster_instance; -- 查看各实例的连接数量 SELECT inst_id, count(*) AS conn_count FROM sys_stat_activity GROUP BY inst_id ORDER BY conn_count DESC;ps -ef | grep racRAC 的优势是多实例共同服务但部署和维护成本也更高。共享存储、内部网络、客户端连接以及运维团队的处理能力缺一不可。因此是否采用 RAC不应只由“可用性越高越好”来决定还要看业务等级和团队是否能承担相应复杂度。二、出了问题先恢复业务再查根因数据库故障往往不是单一原因造成的。硬件异常、网络抖动、SQL 执行计划变化和参数设置不合理都可能表现为“系统变慢”或“连接失败”。现场处置时最忌讳一开始就陷入根因讨论迟迟不做止损。比较实用的顺序是先确认影响范围再看告警和日志有明确止损手段时先恢复业务同时保留现场业务恢复后再根据日志、监控曲线和操作记录还原故障过程。# 实时查看数据库日志 tail -f /kes/data/log/kes-*.log # 查看近期 ERROR 信息 grep -i ERROR /kes/data/log/kes-*.log | tail -1001. 连接数打满应用无法建立新连接时先比较当前连接数和max_connections再按会话状态查看连接分布。SELECT state, count(*) AS total_conn FROM sys_stat_activity GROUP BY state; SELECT pid, usename, datname, state, wait_event_type, wait_event, query_start FROM sys_stat_activity;如果大量连接长期处于idle通常需要继续检查应用连接池是否设置了最大连接数、空闲回收时间以及异常退出后是否能释放连接。应急情况下可以清理已经确认无业务影响的空闲会话但不要看到idle就一律终止因为有些会话可能仍被应用连接池持有。-- 执行前应确认筛选条件和业务影响 SELECT sys_terminate_backend(pid) FROM sys_stat_activity WHERE state idle AND now() - state_change 30min::interval;单纯调大max_connections往往只能把问题向后拖。每个连接都会消耗资源如果连接池没有治理好上限越大故障时对数据库的冲击反而可能越重。2. SQL 突然变慢遇到业务响应变慢可以先找长时间运行的会话再判断它是在消耗 CPU、等待磁盘还是被其他事务阻塞。SELECT pid, now() - query_start AS run_time, query FROM sys_stat_activity WHERE state active AND now() - query_start 10s::interval; SELECT pid, usename, datname, locktype, relation::regclass, mode, granted FROM sys_locks ORDER BY pid;如果确认是阻塞性长事务可以在评估回滚成本和业务影响后终止阻塞会话。若是执行计划或索引问题应保留当时的 SQL、参数和执行计划再决定补索引还是改写语句。CPU 或 IO 已经持续打满时优化 SQL 通常比直接扩容更值得先做。-- 将 xxx_pid 替换为已确认的会话 PID SELECT sys_terminate_backend(xxx_pid);3. 备库延迟持续升高复制延迟不能只看某一个瞬时数值。更有价值的是观察差值是否持续扩大以及主库日志产生速度和备库回放速度是否匹配。SELECT usename, state, sent_lsn, replay_lsn, sys_calc_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes FROM sys_stat_replication;排查时可以沿着链路逐段看主库日志是否生成过快、网络是否丢包或带宽不足、备库磁盘是否出现高延迟、回放进程是否异常。批量导入引起的延迟可考虑错峰网络问题先处理链路如果长期受限于存储就需要调整存储配置不能只靠重启复制进程。4. 节点宕机但没有正常切换先保存数据库和集群组件日志再区分是主机、操作系统、网络还是数据库问题。切换未触发时应重点检查心跳链路、防火墙规则和节点时间同步。date chronyc sources telnet 备库IP 端口生产环境应提前设置日志轮转和保留周期。故障发生后如果频繁重启、反复执行切换却没有先保存日志后续复盘很可能只剩下现象没有足够证据还原原因。三、日常运维要盯住哪些事情高可用集群解决的是“某个组件出问题后怎么办”并不能代替日常维护。数据库能否长期稳定更多取决于巡检、监控、备份和演练是否真正执行。1. 巡检不要只生成报告常规巡检至少应覆盖实例与集群状态、复制延迟、磁盘空间、连接数、长事务、锁等待、表膨胀和参数变更。巡检报告的价值不在于项目多少而在于风险项有没有负责人、处理期限和复查结果。下面几条 SQL 可以作为人工抽查的起点-- 查看死亡元组较多的表 SELECT relname, n_live_tup, n_dead_tup, round(100 * n_dead_tup / (n_live_tup n_dead_tup 1), 2) AS dead_rate FROM sys_user_tables WHERE n_dead_tup 10000; -- 查看超过 5 分钟的活动事务 SELECT pid, usename, datname, now() - xact_start AS tx_duration, query FROM sys_stat_activity WHERE state active AND xact_start IS NOT NULL AND now() - xact_start 5min::interval; -- 查看表空间占用 SELECT spcname, sys_get_tablespace_size(spcname) AS size_byte FROM sys_tablespace;阈值不宜机械套用。比如死亡元组达到多少需要维护要结合表大小、更新频率、自动维护策略和业务窗口判断。2. 告警要能反映“还能不能提供服务”监控通常分为三层操作系统层关注 CPU、内存、磁盘、IO 和网络数据库层关注连接、会话、慢 SQL、事务、锁和空间集群层关注节点角色、心跳和复制状态。磁盘使用率可以设置预警和紧急两级阈值但具体是 80%、88% 还是其他数值应根据日增长量和扩容周期倒推。每天增长很快的磁盘即使当前只用了 70%也可能比长期稳定在 85% 的磁盘更紧急。还要避免只做“进程存活”监控。进程存在时磁盘可能已经只读复制可能已经中断数据库也可能无法接受新连接。较可靠的可用性检查应包含真实连接、轻量查询和关键链路状态。3. 备份是否有效要靠恢复验证生产环境通常会同时使用物理备份和逻辑备份。物理备份适合实例级恢复逻辑备份便于按库或按表处理。两者用途不同不能简单互相替代。#!/bin/bash BACKUP_DIR/data/kes_backup DATE$(date %Y%m%d_%H%M%S) kes_basebackup -D ${BACKUP_DIR}/backup_${DATE} -Ft -z# 导出数据库 kes_dump -h 127.0.0.1 -p 54321 -d testdb -f testdb_dump.sql # 导出单表 kes_dump -h 127.0.0.1 -p 54321 -d testdb -t t_user -f t_user.sql # 恢复前请按实际备份格式及版本核对命令参数 kes_restore -d testdb -f testdb_dump.sql备份文件不应和数据库数据放在同一块故障域中否则磁盘或主机损坏时两者可能一起丢失。除了定时执行还应检查任务返回码、备份集大小和保留周期并定期选取备份在隔离环境恢复。只有恢复成功并完成数据校验才能说明这份备份真正可用。对于异地容灾还要考虑复制延迟、网络中断和机房整体不可用等情况。跨机房部署完成不等于容灾完成切换流程、业务入口变更和回切方案同样需要演练。4. KEMCC 更适合做统一入口多套读写分离或 RAC 集群接入 KEMCC 后可以集中查看节点状态、角色和复制延迟也可以统一安排巡检、备份和日志收集。对运维人员来说它最大的作用是减少逐台登录服务器的重复操作并让各套集群采用较一致的检查口径。kemcccli -c run_inspect --cluster-id xxx工具给出的告警和报告仍需要人工判断。例如同样的复制延迟在离线报表库和核心交易库中的严重程度完全不同。KEMCC 自身也属于生产运维链路的一部分应考虑其高可用、权限控制和操作审计不能让管理工具成为新的单点。四、结语金仓数据库的生产运维最终要落到三个问题上架构是否与业务匹配故障发生时有没有经过验证的处置流程平时能否在风险演变成事故之前发现它。读多写少的系统通常可以从读写分离入手需要多实例共同承担读写、且对恢复时间要求更高的核心系统可以评估 KES RAC。但方案确定以后还要用故障演练验证切换时间和数据影响不能把产品能力直接当成项目结果。日常工作看起来琐碎无非是巡检、告警、备份和复盘但数据库的稳定性往往就来自这些事情是否长期做到了位。相比写在方案里的“高可用”一次完整的恢复演练、一条经过验证的告警和一份能够还原的备份更能说明生产环境是否真的可靠。