上一篇 下一篇 分享链接 返回 返回顶部

云服务器CPU不高但响应变慢时,如何设计故障切换并保障数据一致性?

发布人:Minchunlin 发布时间:2026-09-29 14:14 阅读量:35
云服务器CPU不高但响应变慢时,如何设计故障切换并保障数据一致性?

业务接口开始超时,云服务器 CPU 使用率不高但响应慢,可能是哪些资源出现瓶颈?常见原因包括磁盘 I/O 等待、内存不足或交换、网络接收队列、应用线程池与数据库连接池耗尽、数据库锁等待、日志落盘,以及主备复制确认延迟。CPU 百分比只反映处理器是否繁忙,不能代表请求已经顺利完成。

排查时应先从请求入口定位等待发生在哪一段,再检查主机资源、应用进程、数据库锁与复制状态,最后决定是否摘除节点或执行数据库切换。只有同时确认旧主已经停止写入、备用节点的数据状态满足 RPO、流量入口已经可控,才可以提升备用节点,否则可能形成双主写入或造成无法确认的数据分叉。

先定义切换边界和恢复目标

明确适用环境

本文适用于常见的两层或三层架构:

  • 一个或多个无状态应用节点;
  • 一个数据库主节点和至少一个备用节点;
  • 通过负载均衡、服务发现或固定业务入口切换应用流量;
  • 数据库通过同步或异步复制保持备用副本;
  • 具备日志、监控、备份和管理员操作权限。

如果登录会话、临时文件或上传文件保存在单台云服务器本地,应用节点切换后可能出现“服务恢复但用户状态丢失”。这类状态应迁移到独立的共享存储或可复制的数据服务中,否则应用层仍然存在单点故障。应用节点高可用不能自动解决本地文件和本地会话的单点问题。

先约定 RPO 和 RTO

RPO 是故障后最多允许丢失的数据时间范围,RTO 是业务最多允许中断的时间范围。两者应在切换前确定,而不是等故障发生后临时决定。

目标取向设计重点主要风险
更看重数据完整性使用同步复制或具备明确确认机制的提交策略,切换前检查复制状态复制链路异常时,写入可能阻塞,可用性下降
更看重快速恢复使用异步复制,在备用节点满足条件时快速提升主节点最后一段尚未复制的数据可能无法恢复
允许人工确认自动摘除故障应用节点,数据库提升由人工执行恢复时间取决于确认和操作速度
允许自动切换自动检测、隔离旧主、提升备用、更新流量入口误判、双主和错误提升风险更高

先约定 RPO 和 RTO(AI示意图)

同步复制也不等于所有故障场景下绝对零数据损失。还要确认提交确认覆盖哪些副本、备用节点是否真正落盘,以及旧主节点是否已经被隔离。异步复制则必须接受一个事实:主库已经返回成功、但备用节点尚未收到或回放的事务,可能在主库永久失联后无法自动恢复。

切换前至少记录以下状态:

  • 故障开始时间和受影响的业务接口;
  • 当前主数据库、备用数据库和应用节点;
  • 复制模式、复制延迟、最后接收位置和最后回放位置;
  • 是否存在长事务、锁等待或大量请求重试;
  • 最近一次可用备份及备份校验结果;
  • 业务是否允许临时只读或暂停写入。

这些记录用于判断是否满足切换条件,也用于切换后的数据核对和回滚决策。

按由外到内、低风险到高风险的顺序定位瓶颈

1. 先从请求入口拆分耗时

在业务入口或接近用户的一台主机上执行请求耗时测试。以下命令适用于安装了 curl 的 Linux 或 macOS 环境,/healthz 应替换为不会修改业务数据的健康检查接口:

1. 先从请求入口拆分耗时(AI示意图)

图示对应原文命令:curl。

curl -sS -o /dev/null \
  -w 'dns=%{time_namelookup} connect=%{time_connect} appconnect=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://业务域名/healthz

重点看各阶段的相对变化:

  • dns 较高,说明名称解析或解析链路需要排查;
  • connect 或 appconnect 较高,说明连接建立、TLS 握手或入口端存在等待;
  • ttfb 较高而连接时间正常,通常说明请求已经到达服务端,但应用、数据库或下游服务处理较慢;
  • total 明显高于 ttfb,可能是响应体生成、传输或客户端读取过程较慢。

健康检查只能证明进程能够返回结果,不能证明数据库写入链路正常。应再选择一个经过鉴权、但可以安全重复执行的业务读请求进行对比,不要把创建订单、扣减库存或修改配置的接口作为首次探测对象。

如果只有一个应用节点的 ttfb 明显偏高,优先将该节点从流量入口摘除并保留现场;如果所有节点的 ttfb 都变高,则继续检查共享依赖、数据库、连接池和网络队列。此时不应仅凭 CPU 使用率作出切换判断。

2. 检查主机等待:磁盘、内存和网络队列

以下命令适用于 Linux:

uptime
vmstat 1 5
free -h
iostat -xz 1 5
df -h
df -i

2. 检查主机等待:磁盘、内存和网络队列(AI示意图)

图示对应原文命令:bash uptime vmstat 1 5 free -h iostat -xz 1 5 df -h df -i 。

iostat 和 pidstat 通常由 sysstat 提供。如果系统未安装这些工具,不建议在业务高峰期临时修改生产环境,优先使用已有监控,或在维护窗口补充工具。

可以按以下方式解释结果:

观察结果可能含义处理方向
vmstat 中的 wa 持续偏高进程在等待块设备或文件系统 I/O检查数据库数据盘、日志写入、临时文件和备份任务
si、so 持续出现内存不足,正在进行交换查找占用内存的进程,确认是否存在内存泄漏或异常并发
load 较高但 CPU 使用率不高任务可能处于不可中断等待,常见于 I/O 等待结合 iostat、进程状态和磁盘监控判断
await、队列长度或设备利用率持续异常磁盘响应或设备队列存在瓶颈先降低非必要 I/O,再检查日志、数据库和临时文件
df -h 接近满或 df -i 的 inode 用尽文件无法继续创建或写入清理前确认目录用途,保留备份并准备回滚
内存、I/O 均正常瓶颈可能在连接、线程、网络或外部依赖继续检查应用和数据库

不要依据一次采样就确认磁盘或内存故障。应把采样时间与接口变慢时间对齐,并与正常时段对比。清理日志、删除临时文件或调整服务配置前,要确认文件用途、保留必要备份,并记录可以恢复的路径。

网络队列和接口错误可以继续用以下命令观察:

ss -s
ss -lnt
ip -s link

在 ss -lnt 中,如果监听端口的 Recv-Q 长时间接近或超过队列上限,可能是请求到达过快而应用接收不及时。ip -s link 中的错误包、丢包或异常增长的队列,需要结合云平台监控和应用日志确认。若网络统计正常但请求仍然慢,不要反复重启网络服务;重启会清除现场,也不能解决数据库锁等待或连接池耗尽。

还要区分连接数和请求吞吐量:并发连接数表示某一时刻保持的连接数量,每秒请求数表示单位时间内完成或进入的请求数量,二者不能互相替代。连接数增加可能来自慢请求堆积,也可能来自长连接,必须结合响应时间、连接池等待和请求日志判断。

3. 检查应用进程、线程池和数据库连接池

先确认服务是否频繁重启、是否有超时、文件描述符不足或下游重试:

systemctl status <应用服务名> --no-pager
journalctl -u <应用服务名> --since "30 min ago" --no-pager

以上命令适用于使用 systemd 管理服务的 Linux。<应用服务名> 必须替换为实际服务名,不能直接照抄。

找到进程号后,可进一步观察线程和文件描述符:

pidstat -p  -t 1 5
ls /proc//fd | wc -l

重点核对:

  • 工作线程是否全部处于等待状态;
  • 数据库连接池是否耗尽;
  • 请求队列是否持续增长;
  • 是否出现大量连接创建和销毁;
  • 文件描述符数量是否接近服务限制;
  • 是否存在下游调用超时后重试,导致请求数量继续放大。

CPU 使用率低并不代表线程池健康。大量线程可能在等待数据库连接、锁、磁盘或外部接口;连接池耗尽时,新请求会排队,表现为 ttfb 上升而 CPU 仍然不高。

如果只有一个应用节点的线程池或连接池异常,应先将该节点设置为不可接收新请求,等待正在处理的请求结束,再进行重启或修复。重启前保留日志,并确认应用没有本地未提交的关键任务。应用节点摘除不会改变数据库角色,也不应触发数据库提升。

4. 检查数据库锁、I/O 和复制状态

要先区分“数据库执行慢”和“应用拿不到数据库连接”:

  • 连接获取超时:可能是连接池不足、连接未释放或数据库拒绝新连接;
  • SQL 执行超时:可能与查询计划、磁盘 I/O、锁等待或数据库负载有关;
  • 提交超时:可能与事务锁、日志落盘或复制确认有关;
  • 只有写请求变慢:优先检查锁、日志盘和复制确认;
  • 读写都变慢:同时检查数据库资源、连接数和底层存储。

如果使用 PostgreSQL,以下只读查询可用于查看活动会话。执行前确认账号具备查看统计信息的权限:

SELECT pid,
       usename,
       application_name,
       client_addr,
       state,
       wait_event_type,
       wait_event,
       query_start,
       left(query, 200) AS query_sample
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY query_start;

如果大量会话的 wait_event_type 为 Lock,应查找持锁时间较长的事务;如果主要等待 I/O,则继续检查数据库数据目录、日志目录和底层磁盘。没有确认事务影响范围时,不要直接终止会话。终止会话属于有影响的数据库操作,应先记录会话信息、评估回滚影响,并准备业务重试或恢复方案。

在 PostgreSQL 主节点上,可以使用以下查询查看复制状态:

SELECT application_name,
       client_addr,
       state,
       sync_state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       write_lag,
       flush_lag,
       replay_lag
FROM pg_stat_replication;

在备用节点上,可使用:

SELECT pg_is_in_recovery();

SELECT now() AS checked_at,
       pg_last_wal_receive_lsn() AS receive_lsn,
       pg_last_wal_replay_lsn() AS replay_lsn,
       pg_last_xact_replay_timestamp() AS last_replay_time;

这些查询只适用于 PostgreSQL,其他数据库应使用对应版本的活动会话、锁监控和复制状态命令。判断备用节点能否切换时,不能只看“连接状态正常”,还要确认它是否持续接收并回放数据,以及延迟是否符合业务设定的 RPO。

按故障类型决定是否切换

应用节点故障和数据库主节点故障必须分开处理:

故障类型推荐动作是否需要提升数据库
单个应用节点慢或进程异常摘除节点、保留日志、修复后再加入不需要
多个应用节点同时等待数据库先检查数据库锁、I/O、连接和复制不应立即提升
数据库主节点进程故障但主机仍可控先确认能否安全恢复,避免备用节点同时写入视恢复结果决定
数据库主机失联确认旧主已隔离,再评估备用节点复制状态可能需要
复制链路中断但主库仍在写不应直接提升备用节点先确定数据权威节点
无法确认旧主是否仍能写入暂停自动提升或进入只读不应强制切换

这张表的核心判断是:响应变慢不等于数据库主节点已经失效。锁等待、磁盘队列、连接池耗尽或复制确认变慢,都可能让业务变慢,但直接提升备用节点无法解决根因,反而可能造成数据分叉。

设计安全的故障切换流程

让应用始终只有一个可识别的写入口

应用节点可以多节点接入,但写入数据库的入口必须由数据库角色控制。应用不应把某个固定主机名永久写死为主数据库地址,而应通过角色服务、统一连接入口或可更新的服务发现记录访问当前写主。

健康检查至少应区分两类:

  • 存活检查:确认进程仍在运行;
  • 就绪检查:确认应用可以访问当前有效数据库,并具备处理业务请求的条件。

如果只检查进程存活,数据库已经不可用的应用节点仍可能被继续分配流量。

按“确认—隔离—提升—验证”执行

  1. 确认故障范围

先排除网络抖动、锁等待、磁盘暂时繁忙、连接池耗尽等可恢复问题,确认确实需要数据库角色切换。记录当前主库和备用库的复制状态、最后接收位置、最后回放位置、长事务及业务影响范围。

  1. 隔离旧主

通过云平台控制台、主机电源控制、网络隔离或数据库服务控制,确保旧主不能继续接受写入。隔离方式必须符合当前部署环境,执行前确认影响范围,并保留恢复旧主所需的日志和配置。

在无法确认旧主已经停止写入时,不得直接提升备用节点。此时应暂停自动提升,必要时先让业务进入只读或暂停写入状态。

  1. 确认备用节点状态

检查备用节点是否仍处于恢复状态、是否持续接收并回放日志,并记录最后接收和回放位置。异步复制场景下,要根据这些位置判断可能的数据缺口,确认是否符合业务 RPO。

  1. 暂停或限制写入

对一致性要求较高的业务,先进入维护或只读模式,避免切换期间产生无法确认状态的写请求。对于不能完全暂停的业务,应至少限制高风险写操作,并确保请求具备幂等键和审计记录。

  1. 提升备用节点

以 PostgreSQL 12 及以上版本为例,提升前先核对数据库版本和恢复状态:

   SELECT version();
   SELECT pg_is_in_recovery();

只有在旧主已经隔离、复制状态和必要备份已经记录后,才考虑执行:

   SELECT pg_promote(true);

pg_promote 会改变数据库角色,不是普通查询。执行前应确认影响范围、保留必要备份和复制状态,并准备失败时的恢复路径。执行后不能简单地把旧主再次切回主库;旧主通常需要作为新主的备用节点重新构建或重新同步。

  1. 更新写入入口

将应用连接指向新主,清理旧连接池,避免已有连接继续指向失效或被隔离的节点。更新服务发现记录、连接配置或角色入口前,应确认配置修改范围,并准备恢复旧入口的回滚操作。

  1. 逐步恢复流量

先放行少量可控流量,验证读写、错误率和响应时间,再逐步恢复全部流量。若新主出现大量连接、锁或 I/O 等待,应先限制流量,不要在数据库尚未稳定时继续扩大请求量。

  1. 重建旧主副本

不要让旧主直接重新加入写入集群。应根据数据库复制机制,将旧主从当前权威主重新初始化或重新同步为备用节点,确认复制正常后,再将其加入故障切换候选。

处理异步复制的数据缺口和重试

异步复制下,切换后需要根据业务流水号、审计日志或事件记录核对:

  • 切换前最后一段时间内已经返回成功的请求;
  • 已扣款但未生成业务单据的记录;
  • 已生成订单但未完成后续处理的记录;
  • 客户端重试是否造成重复写入;
  • 主库和备用库之间是否存在缺失或分叉数据。

不能用简单的“表行数相同”证明一致性。行数相同,仍可能存在不同记录、状态不一致或部分事务缺失。应优先核对业务唯一编号、事务状态、审计事件和关键关联关系。

订单、支付、库存、任务提交等写操作应使用业务请求号或幂等键,并在数据库中建立唯一约束或等价的去重机制。典型处理逻辑如下:

  1. 请求携带业务唯一编号;
  2. 业务数据和幂等记录处于同一事务;
  3. 重试时先查询该编号的处理状态;
  4. 已成功的请求返回原处理结果;
  5. 处理中或状态不明确的请求进入人工或异步核对流程。

幂等机制可以降低“客户端认为失败而重试、数据库实际已经提交”造成的重复写入风险,但不能替代数据库复制、旧主隔离和切换后的数据核对。

修复或切换后的验证方法

切换或资源修复完成后,应按以下顺序验收:

  1. 入口验证

再次执行安全健康检查和业务读请求,确认 ttfb 与总耗时回到正常基线。健康检查通过但业务读请求仍慢,说明应用或共享依赖仍未恢复。

  1. 应用验证

检查 5xx、超时、连接池等待、线程池队列和服务重启次数,确认这些指标没有持续增长。

  1. 主机验证

重新执行 vmstat、iostat、free、df,确认 I/O 等待、交换、磁盘空间和 inode 没有继续恶化。采样结果应与正常时间段对比,不能只看单次值。

  1. 数据库角色验证

确认只有一个节点接受写入,旧主仍处于隔离状态或已经重新作为备用节点加入。应用连接池和服务发现记录不能再指向旧写主。

  1. 复制验证

确认新主到备用节点的复制已经建立,备用节点持续接收并回放数据,延迟处于既定 RPO 范围内。

  1. 业务验证

使用测试或低风险业务完成一次读写闭环,检查幂等键、流水号、审计日志和关键状态。对切换窗口内的成功请求、超时请求和重试请求分别核对,不要只验证一个普通查询。

  1. 备份验证

确认新主已经纳入备份任务,并能找到切换后的有效恢复点。备份任务“已配置”不等于备份“可恢复”,应按既定流程检查备份结果和恢复记录。

自动切换不应只依据“主机 Ping 不通”。更稳妥的自动化条件至少包括:旧主已经完成隔离、备用节点状态有效、复制延迟符合策略、写入入口已经切换,以及切换后的健康检查能够验证数据库角色和应用可用性。

常见失败情况与回滚检查

切换后发现旧主仍可写

立即停止两侧写入或暂停业务写请求,保留两侧日志和数据库状态。不要直接把两边数据合并,也不要通过覆盖备份文件解决。应先确定哪一侧是业务权威数据源,再依据事务日志、业务流水号和审计记录恢复另一侧。

备用节点复制延迟过大

如果延迟超出业务允许的 RPO,不应自动提升。可以选择继续恢复旧主、临时只读,或在业务负责人确认数据损失范围后执行人工切换。没有明确授权时,不要把“快速恢复”当作允许丢数据的依据。

切换后应用仍然慢

检查应用是否仍缓存旧数据库地址、连接池是否未重建、读请求是否仍指向故障节点,以及新主是否受到大量重试冲击。必要时先限制流量,再重新检查数据库连接、锁、I/O 和复制状态。

误切换后需要恢复原主

数据库角色回滚不能简单执行“切回旧主”。如果新主已经产生写入,旧主与新主可能处于不同时间线。通常应按以下顺序处理:

  • 暂停或限制写入;
  • 确认当前权威主及其最后有效位置;
  • 将原主隔离并作为待重建节点;
  • 从当前权威主重新建立备用副本;
  • 复制验证通过后,再把原主加入故障切换候选。

涉及删除数据目录、重新初始化副本或覆盖配置的操作,都必须先完成备份、确认影响范围并保留恢复路径。验收结束后逐项确认:

  • [ ] 只有一个数据库节点接受写入;
  • [ ] 应用入口已经指向正确的写主;
  • [ ] 旧主已经隔离,或已重新加入为备用节点;
  • [ ] 复制状态、复制延迟和备份任务正常;
  • [ ] 关键业务流水号和幂等记录已经核对;
  • [ ] CPU、I/O、内存、连接池和请求耗时恢复到正常基线;
  • [ ] 已记录本次切换触发条件、执行时间、数据核对结果和回滚步骤。
目录结构
全文