Skip to content

第十章 国企 / 金融场景专题(第209-228题) ​

209. 手机银行登录系统要高可用,怎么设计(高可用登录架构) ​

【考察内容】高可用架构设计 + 认证体系 + 金融可用性要求

【题目】行里要求手机银行登录系统全年可用率不低于 99.99%(全年停机不超过 53 分钟),日活 3000 万,早高峰 8:00–9:00 登录 QPS 峰值 3 万。请设计这套登录系统,并说明如何做到高可用。

【参考答案】按“先保可用、再谈体验”的思路:

  1. 分层设计:接入层用多机房 DNS 智能调度 + 四层/七层负载(LVS + Nginx),客户端 SDK 内置多 IP 兜底与自动重试;应用层登录服务无状态化(Session 外置到 Redis 集群),支持水平扩容;数据层用户认证库主从 + 读写分离,凭证校验走缓存;

  2. 认证链路:设备指纹 + 图形/短信验证码(前置风控)→ 密码/生物识别校验 → 颁发短时效 AccessToken + 长时效 RefreshToken,敏感操作二次认证;

  3. 高可用手段:同城双活(两机房同时承载,任一故障秒级切流);依赖降级(先把依赖拆开再谈降级:第 2 条里图形验证码与短信验证码同属「验证码服务」,所以「验证码服务挂」时拿短信当备用因子是走不通的(同来源一起挂)。分两种情况答:① 只有图形/风控验证码组件挂 → 降级为「密码+设备指纹+短信验证码」,保持认证强度;② 短信网关也挂(或与短信链路同源故障)→ 降级为「密码+设备指纹+人脸/UKey/口令」等不依赖短信的因子,并临时限制敏感操作、二次认证改用可用因子。两条路径都要留可审计记录。风控服务不可用时降级为“放行但加强事后审计”);限流熔断(按用户 / IP / 设备维度,防撞库打满);灰度与回滚(新版本按用户分桶灰度,异常自动回滚);

  4. 监控与演练:登录成功率、P99 耗时、验证码下发成功率、各依赖可用率;定期做故障演练(机房切换、依赖宕机)。

  5. 容量估算: 手机银行登录峰值经验:早高峰/还款日可达日常 3–5 倍;登录接口实例数 = 峰值 QPS ÷ 单机 QPS 能力 × 1.5(是「除」不是「乘」:峰值 3 万、单机 2000 → 15 台,再 ×1.5 ≈ 23 台;若按【关键数字】保守取单实例 1000 QPS,则是 30 台 ×1.5 ≈ 45 台)。Session/Token Redis:活跃会话数×Token 大小,千万级会话数 GB 级内存。认证库读 QPS≈登录 QPS×(1+重试)。可用性目标:登录 99.99%(全年停机 <53 分钟)。

  6. 失败与降级: 验证码服务挂→密码+设备指纹;风控挂→限额放行+事后审计;Redis 会话挂→JWT 本地验签短时兜底;认证库主挂→从库提升+只接受降级登录(限制敏感操作)。每次降级都要有监管可接受的记录。

【原理溯源】

  • 为什么登录系统必须无状态化? 有状态 Session 绑在单机进程里,实例挂掉该机上的所有在线用户全部掉线,故障半径等于实例数的倒数。把 Session 外置到共享存储(Redis 集群)后,任意实例可处理任意请求,扩容/缩容/故障切换都不影响会话连续性——这是水平扩展的前提,也是 99.99% 的地基。
  • 为什么金融登录不能用“纯可用性优先”的降级? 互联网业务验证码挂了可以直接放行;银行不行——登录是资金安全的第一道门。放行等于把撞库/盗号风险放大到全量流量。所以金融降级必须是认证因子降级(换备用因子),而不是认证强度降级(去掉认证)。验证码不可用 → 降为“密码 + 设备指纹 + 短信验证码”,但要先看第 2 条的依赖划分:图形与短信验证码同属「验证码服务」,该服务整体挂时短信不可用,只能换成人脸/UKey/口令这类不依赖短信的因子;风控不可用 → 可放行但必须事后加强审计。可用性可以降,认证强度不能无痕地降。
  • 为什么 99.99% 意味着切流必须秒级? 全年 8760 小时 × 0.01% ≈ 52.6 分钟。单次机房故障若切流耗时 10 分钟,一年只允许发生 5 次;若切流 1 分钟,允许 50 次。所以架构目标不是“永不故障”,而是故障检测 + 流量切换的总时间压缩到 1 分钟内。客户端多 IP 兜底把 DNS 切换的传播延迟也吃掉一部分。
  • 为什么 Session 要用短 AccessToken + 长 RefreshToken? 长时效 Token 一旦泄露,攻击窗口等于 Token 有效期。短时效 AccessToken(如 15–30 分钟)把泄露后的可利用时间压到很短;RefreshToken 存在更安全的位置(HttpOnly Cookie / 安全存储)且可撤销,用于无感续期。敏感操作(转账、改密)再强制二次认证——即使 AccessToken 被盗,也转不走钱。
  • 为什么撞库要三维限流而不是只限 IP? 只限 IP:攻击者换代理池即可绕过;只限账号:对单账号低速撞库无效。按 IP / 设备 / 账号三维限流,再叠加风控评分(异地、新设备、高频失败),才能在“误伤正常用户”和“放过攻击者”之间取得平衡。

【选型判断树】

登录依赖故障时,降级路径怎么选?
├─ 验证码服务不可用
│   → **先分清挂的是哪个组件**:只有图形/风控验证码挂 → 备用因子=密码+设备指纹+短信验证码;
│      短信网关也挂(与验证码服务同源故障时)→ 改用人脸/UKey/口令等不依赖短信的因子,并限制敏感操作
│   → 禁止:直接放行(认证强度不能无痕降低)
├─ 风控服务不可用
│   → 可降级放行,但必须:① 记全量登录日志;② 事后回溯审计;③ 敏感操作仍强制二次认证
├─ 认证库主库不可用
│   → 读从库校验(凭证类可容忍短暂旧数据)
│   → 但**禁用、改密、踢人必须读主或走 Redis 黑名单**,否则冻结指令在复制延迟窗内失效、被盗账号仍可登录
│   → 同城另一机房主库接管(强同步复制保证 RPO=0)
└─ Redis(Session)集群不可用
    → 本地缓存兜底短期 Session + 强制重新登录
    → 不可:跳过 Session 校验直接放行

口诀:可用性可降,认证强度不可无痕地降;每次降级都要留审计。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“登录是资金安全第一道门,设计原则是可用性优先但认证强度不妥协”
0:30–1:30分层架构接入层多机房 DNS + 负载;应用层无状态 + Session 外置;数据层主从 + 缓存
1:30–2:30认证链路设备指纹/验证码前置 → 密码/生物识别 → 短 Token + 长 Refresh → 敏感操作二次认证
2:30–3:30高可用四件套同城双活秒级切流;依赖降级(换因子不换强度);三维限流防撞库;灰度回滚
3:30–4:30指标与演练99.99%≈53 分钟;监控登录成功率/P99/依赖可用率;定期真实切流演练
4:30–5:00收尾“一句话:金融登录的高可用,是把故障恢复压到秒级,同时保证降级不降安全”

【关键数字】

参数经验值说明
可用率 99.99%全年停机 ≤ 53 分钟8760h × 0.01%
切流目标检测 + 切换 < 60 秒否则故障预算不够用
日活 3000 万 / 峰值 QPS 3 万单实例 1000–2000 QPS(压测定档)23–45 实例(×1.5 冗余),双机房均摊
AccessToken 有效期15–30 分钟泄露后可利用窗口短
RefreshToken 有效期7–30 天,可撤销存安全存储,支持踢人
同城机房延迟< 2ms强同步复制可接受
撞库限流单账号失败 5–10 次锁 15 分钟三维:IP/设备/账号
敏感操作二次认证转账/改密/大额支付即使 Token 被盗也转不走钱

【追问链】(三层)

L1|“99.99% 是怎么算出来的?你们系统达标吗?” → 8760 小时 × 0.01% ≈ 52.6 分钟/年。拆解到组件:任一机房故障切流 <1 分钟、单实例故障影响 <10 秒(健康检查摘除)、依赖降级开关秒级生效。达标验收靠真实切流演练的实测 RTO,不是纸面计算。

L2|“验证码服务挂了,直接放行不是更快恢复可用吗?” → 快,但不能这么做。登录是资金入口,直接放行=把撞库/盗号风险放大到全量。正确做法是认证因子降级:换备用因子(图形验证码挂→密码+设备指纹+短信;短信网关也挂→密码+设备指纹+人脸/UKey),保持认证强度;若必须放行,只放低风险场景(查询),转账类仍强制二次认证,并全量留审计事后回溯。

L3|“同城双活,数据库怎么保证两边数据一致?” → 应用层无状态天然双活;数据库用强同步复制保证任一机房故障时 RPO=0。注意口径:只有两个机房各一副本时,"多数派"就等于全部 ack,实质是强制全同步——任一链路抖动即无法定档,所以生产要引入第三仲裁点(2+1 Witness/日志节点)或三副本跨机房,代价是写延迟增加约一次同城 RTT(<2ms)与一个故障域。流量调度用 DNS/GSLB 健康检查 + 客户端多 IP 兜底,把 DNS 生效延迟也覆盖掉。切流演练必须真做,不能纸上推演。

【评分标准】

档位答案特征
60 分能说出集群、缓存、主从、负载均衡
80 分分层清晰;无状态化 + 同城双活 + 依赖降级 + 限流四件套;能拆 99.99%≈53 分钟
95 分主动指出“金融登录可用性可降、认证强度不可无痕地降”;短 Token + 长 Refresh + 敏感操作二次认证;降级路径具体到因子替换;强调真实切流演练;提及撞库三维限流

【关联题】

  • 同主题金融版: 第 209 题(本题)对应互联网版第 130/155 题(登录/SSO)
  • 上游理论: 第 222 题(同城双活与两地三中心)——登录双活的底层依赖
  • 安全相邻: 第 214 题(数据脱敏)、第 220 题(审计留痕)——认证与审计是一套体系
  • 降级专题: 第 217 题(金融级服务降级)——依赖降级的通用方法论

【自测】

  1. 99.99% 可用率对应的全年停机预算是多少分钟?这对切流速度有什么要求? 参考答案:约 53 分钟。单次机房故障的检测+切流必须压到 1 分钟内,否则一年只允许几次故障。
  2. 验证码服务不可用时,金融登录能否直接放行?正确做法是什么? 参考答案:不能。登录是资金入口,直接放行会放大撞库风险。应降为备用认证因子(密码+设备指纹+短信),保持认证强度;若部分放行,敏感操作仍强制二次认证并全量审计。
  3. 为什么 AccessToken 要短时效、RefreshToken 要长时效且可撤销? 参考答案:短时效压缩 Token 被盗后的可利用窗口;长 Refresh 支持无感续期且可随时撤销(踢人)。敏感操作再强制二次认证,即使 Access 被盗也转不走钱。

210. 亿级账户流水表翻页越来越慢(亿级数据分页查询) ​

【考察内容】深分页优化 + 亿级数据查询设计

【题目】账户流水表有 8 亿行数据,客户在 App 上翻看历史流水,翻到后面几十页时接口要 5 秒以上,客户投诉。请给出优化方案,并说明如果要设计一个“亿级数据的分页查询方案”,你的整体思路是什么。

【参考答案】

  1. 先定位:EXPLAIN 看是否全表扫描;深分页 LIMIT 1000000, 20 的本质是扫描并丢弃前 100 万行,代价随页数线性增长——但题干是「翻到后面几十页」,20 条/页时 offset 只有约千级(几十×20≈1000,与 100 万差约 1000 倍),千级 offset 本不该 5 秒,所以第一步要按「offset 不大却仍慢」这个分支定位:ORDER BY 字段无索引/无覆盖索引导致全表 filesort、SELECT * 宽行回表放大、分库分表下每片都要取 offset+n 条再跨片归并、页面另外还发了 COUNT(*) 全量统计。游标分页只治「offset 大」那一支,不先 EXPLAIN 就答游标分页属于没对症;

  2. 优化手段(按性价比排序):

    • 游标分页(推荐):改用“上一页最后一条的 id/时间”作为游标,WHERE id < :last_id ORDER BY id DESC LIMIT 20,走主键索引,页数无关,恒定 O(log n);
    • 延迟关联:SELECT * FROM t JOIN (SELECT id FROM t ORDER BY id LIMIT 1000000, 20) x USING(id),先在覆盖索引上分页拿到主键,再回表,减少回表次数;
    • 业务限流:限制最大可翻页数(如只允许查最近 6 个月),引导用户用条件筛选(时间范围 + 卡号)缩小结果集;
    • 冷热分离:近 3 个月热数据在线上库,历史数据归档到历史库 / 数仓,查询路由到不同库;
    • 覆盖索引:把常用查询字段(流水号、时间、金额、对手方)做成联合索引,避免回表;
  3. 分页查询方案的通用骨架:明确查询维度(按时间 / 按卡号 / 按类型)→ 选择分页方式(游标分页优先,跳页需求才用 offset)→ 设计索引(查询字段顺序 = 索引顺序,最左前缀)→ 控制结果集大小 → 冷热分层 → 加缓存(首页 / 热门页)。

  4. 容量估算: 亿级流水表:单行按 1KB → 1 亿行 ≈ 100GB;宽表按 3~8KB/行 → 300GB~800GB;若已到 8 亿行 ×1KB ≈ 800GB 才谈得上 TB 级——「数百 GB~TB」要说清按几 KB/行、多少行。深分页 LIMIT 1000000,20 会扫过百万行,必须改写。优化:① 游标/seek(WHERE id/时间 > last);② 延迟关联先查主键再回表;③ 按用户+时间分区/分表;④ 热数据近线存储。翻页深度产品上限(如 100 页)从源头限制。查询 P99 目标金融柜面常 <2s。

  5. 失败与降级: 历史查询走离线/归档库异步导出,核心在线库只服务近期;归档库不可用时提示稍后重试而不是拖垮主库。分析型需求强制走数仓。

【原理溯源】

  • 为什么 LIMIT offset, n 慢在“扫描丢弃”? InnoDB 的 B+ 树索引只能告诉你“下一条在哪”,不能告诉你“第 100 万条在哪”。执行 LIMIT 1000000, 20 时引擎必须沿索引扫过前 100 万条再丢弃,只留最后 20 条。页数越深扫描越多,RT 随页数线性增长——这是算法层面的必然,加索引救不了。
  • 为什么游标分页能与页数无关? 游标(上一页最后一条的 id/时间)直接定位到 B+ 树中该键的位置,从那里顺序取 20 条。定位是 O(log n),取 20 条是 O(20),总代价恒定。代价是放弃了“随机跳到第 N 页”的能力——而流水浏览的用户行为本就是“往下刷”,跳页需求极低。
  • 为什么金融流水要冷热分离? 银行流水有天然的时间衰减:客户 95% 的查询集中在近 3 个月。把历史数据归档到历史库/数仓,线上库体积缩到原来的 1/10,索引更小、缓存命中更高、备份窗口更短。同时归档不是删除——监管要求流水可追溯多年,历史库必须可查,只是查询走另一条链路(可接受秒级延迟)。
  • 为什么金融场景不能随便加缓存? 流水是账务数据,缓存旧数据会让客户看到“余额不对/少了笔交易”,引发投诉甚至监管问询。可以缓存的是首页摘要、热点产品页这类非实时账务;逐笔流水必须走库(或走从库+写后读主),宁可慢一点,不能错一点。
  • 为什么延迟关联有效? 先在覆盖索引(只含 id)上做深分页——覆盖索引体积小、扫描快;拿到 20 个 id 后再回主表取完整行。把“扫描 100 万行完整数据”变成“扫描 100 万行窄索引 + 回表 20 次”,IO 降一个数量级。是游标分页不可用时的次优解。

【选型判断树】

亿级流水查询,先问“用户要不要跳页”?
├─ 不要跳页(绝大多数 App 流水浏览)
│   → 游标分页:WHERE id < last_id ORDER BY id DESC LIMIT 20
│   → 恒定 O(log n),页数无关
├─ 必须跳页(客服后台按页码定位)
│   → 延迟关联 + 覆盖索引,且限制最大页数(如 100 页)
│   → 超出则强制改条件检索
└─ 进一步分层
    ├─ 近 3 个月 → 线上库(主/从)
    ├─ 3 个月–5 年 → 历史库(可接受秒级延迟)
    └─ 更久远 → 数仓/归档库(T+1 批量可接受)

额外约束(金融):账务字段不缓存;查询走从库时对刚发生的交易写后读主。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“先按 EXPLAIN 判是哪一类:题干几十页=offset 千级,这类慢多半不是扫描丢弃,而是无覆盖索引/filesort/回表/跨片归并/COUNT;offset 十几万才轮到『扫描丢弃』”
0:30–1:30机制LIMIT offset,n 要扫过前 offset 行再丢弃;页数越深代价线性涨
1:30–2:30对症offset 大 → 游标分页(上页最后 id 定位,与页数无关,代价是不能跳页);*offset 不大却慢 → 补覆盖索引/去 SELECT /分片内先取后归并/去掉全量 COUNT
2:30–3:30补充手段延迟关联、覆盖索引、业务限页、冷热分离(近 3 月在线上库)
3:30–4:30金融约束账务数据不缓存;历史归档仍可追溯;写后读主
4:30–5:00收尾“一句话:流水查询优先游标分页 + 冷热分层,金融约束是正确性优先于缓存命中”

【关键数字】

参数经验值说明
流水表规模8 亿行单表已需分库分表或归档
深分页阈值offset > 10 万时明显变慢超过考虑换游标;但题干那种 offset 千级仍 5s 的,要先查索引/filesort/回表/跨片归并/COUNT(*)
游标分页 RT恒定 < 50ms与页数无关
冷热分界近 3 个月为热数据按业务查询分布调整
历史流水留存金融通常 ≥ 5 年归档不删除
覆盖索引扫描比回表快一个数量级窄索引体积小
从库延迟容忍历史查询可秒级;刚发生交易写后读主账务一致性约束

【追问链】(三层)

L1|“业务说必须支持跳页怎么办?” → 用延迟关联+覆盖索引缓解,同时限制最大可翻页数(如 100 页)。真正的跳页体验应改为按条件检索(时间范围+卡号+金额区间)——金融流水的用户真实需求是“找到那笔交易”,不是“翻到第 87 页”。

L2|“分库分表后怎么分页?” → 各分片各取前 N 条,中间层归并排序后取全局前 N。深分页时每片都要取回前 offset+n 条再归并截段——不能只取 offset/分片数(全局 offset 之前的行可能全落在同一片,那样是漏记录,不只是变慢);offset 越大每片扫描量线性上升——所以分库分表场景更应强制游标分页。跨片统计/检索走 ES 或数仓,不在线上库广播。

L3|“缓存流水首页行不行?” → 首页摘要可以(账户余额快照+最近 5 笔,短 TTL),但逐笔明细不建议——账务数据缓存旧值会引发“钱对不上”的投诉。若必须缓存,要与对账联动:缓存只做展示加速,以库为准,缓存与库不一致时以库覆盖。

【评分标准】

档位答案特征
60 分知道加索引、分页要优化
80 分先按 EXPLAIN 判类别(offset 大=扫描丢弃;offset 不大却慢=filesort/回表/跨片归并/COUNT),再对症给游标分页或索引方案;知道延迟关联、冷热分离
95 分能论证游标分页的 O(log n);主动提金融约束(账务不缓存、历史可追溯);分库分表后的归并方案;写后读主;按业务查询模式设计索引与分层

【关联题】

  • 互联网版原型: 第 56 题(深分页优化)——本题是金融口径改造
  • 分片专题: 第 215 题(金融数据分片)——分库分表后的分页
  • 读写分离: 第 216 题(主从延迟)——查询走从库的一致性问题
  • 对账兜底: 第 219 题(日终对账)——归档/缓存出错时的最终防线

【自测】

  1. LIMIT 1000000, 20 为什么慢?加索引能解决吗? 参考答案:引擎必须扫描并丢弃前 100 万行,页数越深代价线性增长。加索引救不了扫描丢弃本身,应改游标分页。
  2. 游标分页的代价是什么?金融流水场景能否接受? 参考答案:不能随机跳页。流水浏览用户行为本就是往下刷,跳页需求极低,完全可接受;真要跳页改为条件检索。
  3. 历史流水为什么归档而不是删除?归档后查询怎么办? 参考答案:监管要求流水可追溯多年(通常≥5年)。归档到历史库/数仓,查询路由到另一条链路,可接受秒级延迟,但必须可查。

211. 理财开售瞬间被抢空(金融秒杀场景) ​

【考察内容】金融场景下的高并发抢购 + 合规与公平性

【题目】一款年化 4.5% 的理财产品今日 10:00 开售,额度 5 亿元,预计 100 万客户同时抢购。要求:不超卖、不重复购买、系统不崩,且监管要求“销售过程可追溯、不得有内部插队”。请设计方案。

【参考答案】

  1. 先与互联网秒杀区分:金融抢购多两条硬约束——额度是钱(不能超卖)、过程要可追溯(监管审计);

  2. 削峰:开售前页面静态化 + 倒计时本地渲染;开售瞬间用答题 / 验证码 / 预约资格做前置拦截,把并发打散到几十秒;

  3. 库存控制:额度预扣在 Redis(按份数用 DECR、按金额用 DECRBY,或 Lua 脚本保证原子性),扣减成功才进入下单;Redis 与 DB 最终一致靠 MQ 异步落库 + 定时对账补偿,DB 层再用 UPDATE ... WHERE 剩余额度 >= :amount 条件更新兜底,双重防超卖;每个客户限购 1 份用唯一索引(客户号 + 产品号)挡重复,或 Redis SETNX 预占;

  4. 公平性与可追溯:全流程流水落库(谁、何时、以什么请求号、扣了多少额度),请求号全局唯一便于审计;拒绝任何“内部通道”,所有流量走同一入口,防止插队质疑;

  5. 兜底:排队机制(超阈值直接返回“排队中”)、降级(只保下单主链路)、限流(网关 + 用户维度)。

  6. 容量估算: 理财秒杀:额度 N 份、预约用户 M 人,峰值 QPS 可按“M×瞬时点击率”粗估,常见远高于日常百倍。库存扣减必须原子(DB 乐观锁/Redis Lua/预扣号段)。单机 Redis 扣减 10 万+ QPS 可扛热点;DB 最终落账异步化。超卖零容忍;少卖可接受。带宽与风控也要算。

  7. 失败与降级: 系统过载时:排队页/资格抽签,而不是让用户请求打死核心账务。扣减成功但下单失败必须有自动退回额度任务。支付通道失败保留额度锁定时限(如 15 分钟)后自动释放。

【原理溯源】

  • 为什么金融抢购比互联网秒杀多了两条硬约束? 电商超卖可以补发优惠券、延迟发货;理财超卖是资金差错——超募金额涉及非法集资红线,少卖涉及销售未达标。且监管明确要求“销售过程可追溯、不得有内部插队”,这不只是技术指标,是合规义务。所以金融抢购的正确性权重远高于吞吐量。
  • 为什么 Redis 预扣 + DB 条件更新要双重防超卖? Redis DECR 原子且快,但 Redis 是缓存不是账本——宕机丢数据、主从切换丢写都会导致额度虚高。DB 的 UPDATE ... WHERE 剩余 >= :amount 是最后的账本防线:条件不满足则更新 0 行,从 SQL 层面杜绝超卖。两者一个管性能(挡并发),一个管正确性(守底线)。
  • 为什么唯一索引比 Redis SETNX 更可靠? SETNX 依赖 Redis 可用性;唯一索引依赖数据库的 ACID 保证。客户+产品的唯一约束是防重复购买的最终防线,即使 Redis 全挂,数据库仍能挡住第二笔。两者叠加:Redis 挡在前面减少 DB 压力,唯一索引兜在后面保证正确。
  • 为什么“可追溯”必须做到请求级留痕? 监管检查时要能回答:“某客户为何没抢到?额度被谁买走了?是否存在内部人员优先?”每笔请求的进入时间、请求号、来源 IP/渠道、扣减结果全部落库,才能用数据自证公平。没有留痕,客户投诉“有内幕”时你无法自证清白。
  • 为什么削峰用“预约资格/答题”而不是简单限流? 简单限流会把真实客户和脚本一视同仁地挡掉,引发投诉。预约资格/答题把“有资格的真人”和“黄牛脚本”区分开:脚本答不了题、没有预约码。打散并发的同时兼顾公平性——这是金融场景比电商更讲究的地方。

【选型判断树】

金融抢购方案,按约束优先级决策:
1. 正确性(不可妥协)
   ├─ 额度不超卖 → Redis 预扣 + DB 条件更新双保险
   └─ 不重复购买 → Redis SETNX + DB 唯一索引(客户号+产品号)
2. 合规(不可妥协)
   ├─ 过程可追溯 → 全链路请求号 + 流水落库
   └─ 不得内部插队 → 统一入口,禁止旁路通道
3. 性能(在前两者约束下优化)
   ├─ 削峰 → 静态化 + 验证码/预约资格打散
   ├─ 异步 → 扣减成功才 MQ 落库
   └─ 兜底 → 排队 + 限流 + 只保下单主链路

口诀:先守正确与合规,再谈性能;超卖是资金差错,不是体验问题。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“金融抢购与电商秒杀同形不同核:额度是钱、过程要可审计”
0:30–1:30正确性Redis 预扣挡并发 + DB 条件更新守底线;唯一索引防重复
1:30–2:30合规全链路请求号留痕;统一入口防插队;拒绝内部通道
2:30–3:30削峰静态化 + 验证码/预约资格打散;MQ 异步落库 + 对账补偿
3:30–4:30兜底排队、限流、降级只保下单主链路
4:30–5:00收尾“一句话:金融抢购的优先级是不超卖 > 可审计 > 高吞吐”

【关键数字】

参数经验值说明
额度5 亿元超卖即资金差错
并发100 万客户同时峰值 QPS 估 10–30 万
Redis 预扣毫秒级DECR/Lua 保证原子
DB 条件更新WHERE 剩余 >= :amt更新 0 行=额度不够
唯一索引客户号 + 产品号防重复购买最终防线
削峰窗口把 1 秒并发打散到 30–60 秒验证码/预约资格
对账周期开售期间准实时 + 日终发现 Redis 与 DB 不一致
限购每客户 1 份唯一索引强制

【追问链】(三层)

L1|“Redis 扣减成功但落库失败怎么办?” → MQ 重试 + 本地消息表保证投递;定时对账比对 Redis 与 DB 额度,不一致以 DB 为准修正 Redis。客户侧若已看到“购买成功”但落库失败,走差错处理:补偿购入或退回并致歉。关键是最终一致 + 对账兜底,不是依赖 Redis 永不失败。

L2|“客户投诉没抢到但怀疑有内部人插队,怎么自证?” → 全链路请求号留痕:每笔请求的进入时间、来源渠道/IP、扣减结果可查。用数据证明“所有流量走同一入口、无旁路通道、按时间序处理”。这也是为什么禁止“内部预留额度走特殊接口”——一旦有旁路,自证公平就不可能。

L3|“额度只剩 1 万,两个人同时买 5 千,会不会都成功?” → 会,两个都成功,而且这不是超卖。Redis 的 DECRBY(按金额扣用 DECRBY,DECR 只能减 1)是原子操作:第一个扣 5 千后剩 5 千,第二个再扣 5 千后剩 0,两次都拿到成功结果,合计正好等于剩余额度,一分没多。真正会出事的是「先查再扣」——两个请求都读到 1 万、都认为够,各扣一次就超卖 5 千,所以第 3 条要求必须原子扣减(DECR 或 Lua)。换成两人各买 8 千:第一个成功后剩 2 千,第二个扣完是 -6 千,Lua 判负即回滚并返回失败;DB 侧再走 UPDATE ... WHERE 剩余额度 >= :amount,条件不满足更新 0 行,这是原理溯源说的账本防线——超卖零容忍。

【评分标准】

档位答案特征
60 分答出 Redis 扣减、MQ 削峰、限流
80 分指出金融比电商多“额度是钱”和“可审计”;双重防超卖;唯一索引防重复
95 分主动对比金融与电商的本质差异;请求级留痕自证公平;预约资格兼顾削峰与防黄牛;对账补偿闭环;拒绝内部通道的合规意识

【关联题】

  • 互联网版原型: 第 6 题(秒杀系统)——本题是金融口径改造
  • 幂等专题: 第 213 题(金融级接口幂等)——防重复购买的通用机制
  • 对账兜底: 第 219 题(日终对账)——Redis 与 DB 不一致的最终防线
  • 审计留痕: 第 220 题(审计与等保)——可追溯的合规要求

【自测】

  1. 金融抢购与电商秒杀的两条本质差异是什么? 参考答案:额度是钱(超卖即资金差错,不能补发解决);过程必须可追溯、不得内部插队(监管合规义务)。
  2. 为什么要 Redis 预扣 + DB 条件更新双重防超卖? 参考答案:Redis 管性能挡并发,但不是账本;DB 条件更新从 SQL 层面杜绝超卖,是正确性底线。
  3. 客户怀疑有内部插队,如何自证清白? 参考答案:全链路请求号留痕,每笔请求的进入时间、来源、结果可查;证明所有流量走同一入口、无旁路通道。

212. 核心账务与营销系统的 CAP 怎么取舍(CAP 在金融落地) ​

【考察内容】分布式理论在金融场景的实际选型

【题目】面试官问:CAP 理论在银行系统里怎么取舍?核心账务系统和营销活动系统应该选 CP 还是 AP?为什么?

【参考答案】

  1. 先纠一个常见误解:CAP 的“三选二”是在发生网络分区(P)时才需要取舍;正常情况下 C 和 A 都能满足。所以真正的问题是——分区发生时,你要保一致性还是保可用性;

  2. 核心账务系统 → CP:钱的账不能错。分区时宁可拒绝服务(返回“系统繁忙,请稍后重试”),也不能两边各自记账导致账不平。落地手段:同城双活用强同步复制(两副本场景下"多数派"即全部确认,需再配第三仲裁点才是真 quorum)、分布式事务(TCC / 本地消息表)、日终对账兜底;

  3. 营销活动系统 → 可选 AP:领券、积分、活动页这类短暂不一致可接受(用户刷新一下就对了),可用性优先。落地手段:异步复制、最终一致、MQ 补偿;

  4. 更进一步的答法:实际系统是按业务分级混用——同一个银行里,账务 CP、支付准 CP、营销 AP、查询类 AP(走从库);并用 BASE 思想对非核心链路做柔性事务。

  5. 容量估算与取舍落地: 核心账务选 CP(一致性优先):宁可短暂不可用,不可错账;营销/浏览选 AP。同步复制延迟与吞吐需压测:核心库集群节点数、半同步超时。账务日切窗口与批量任务资源隔离。监管可用性与时效要求写进 SLO。

  6. 失败与降级: 一致性组件(强同步)故障时:核心转账可暂停或排队,不允许“先成功后对不齐”;营销系统可降级 AP 读旧数据。故障恢复后以账务系统为准做对账修复。

【原理溯源】

  • 为什么账务不能选最终一致? 最终一致意味着分区/故障窗口内两边各自记账,恢复后靠对账/补偿收敛。对互联网业务(积分、点赞)这没问题;对账务,不一致窗口内的每一笔错误记账都是资金差错——可能已扣款未入账、可能重复入账。资金差错进监管投诉、影响账务平衡,事后补偿的代价(对账、冲正、客户沟通、监管报告)远大于分区期暂时拒绝服务。所以核心账务宁可 CP——分区时拒绝,不制造错误数据。
  • 为什么营销可以 AP? 领券、积分的不一致窗口用户几乎无感(刷新一下就对了),且错了可以补偿(补发一张券)。错误代价低、可修复,用短暂不一致换高可用是划算的。这与账务形成鲜明对比:错误代价决定一致性强度。
  • 为什么实际是“分级混用”而不是一刀切? 同一家银行里,转账扣款错 1 分钱都要上报;活动页多展示一个推荐位毫无影响。一刀切 CP 会让营销活动在分区时白白不可用;一刀切 AP 会让账务冒资金风险。正确做法是按业务的数据价值分级:账务 CP、支付准 CP(关键路径同步+异步补偿)、营销 AP、查询 AP。
  • 为什么账务 CP 还要对账兜底? CP 保证的是“分区时不制造不一致”,但不能保证“所有时候都不出错”——应用 bug、消息丢失、人工误操作都可能造成账务差错。对账是独立于运行时协议的最终防线:不管底层怎么保证,日终总账+明细核对能发现一切差异。金融系统的可靠性哲学是分层设防,不是单点信任。
  • 为什么查询类可以 AP? 查询走从库,短暂读到旧数据不影响资金安全(不会因为读旧数据而多扣钱)。写路径 CP 保证正确,读路径 AP 保证吞吐——这是“读写分治”的经典应用。刚发生的交易用“写后读主”弥补读己之写问题。

【选型判断树】

银行系统 CAP 选型,按数据价值分级:
├─ 核心账务(余额、流水、清算)
│   → CP:分区时拒绝服务,不制造错误账务
│   → 手段:强同步复制、TCC/本地消息表、日终对账
├─ 支付链路(准 CP)
│   → 关键路径同步强一致 + 异步补偿 + 对账
├─ 营销活动(券、积分、活动页)
│   → AP:短暂不一致可接受,可用性优先
│   → 手段:异步复制、最终一致、MQ 补偿
└─ 查询展示(余额查询、流水浏览)
    → AP:走从库,短暂旧数据可接受
    → 刚发生的交易:写后读主

前提:CAP 只在分区时取舍;正常时 C 和 A 都能满足。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“先澄清:CAP 是分区时的取舍,不是平时三选二”
0:30–1:30账务选 CP钱的账不能错;分区时宁可拒绝服务;强同步复制 + TCC + 对账
1:30–2:30营销选 AP券/积分不一致用户无感、可补偿;可用性优先
2:30–3:30分级混用账务 CP、支付准 CP、营销 AP、查询 AP;按数据价值分级
3:30–4:30对账兜底CP 不等于永不出错;日终对账是独立于协议的最终防线
4:30–5:00收尾“一句话:错误代价决定一致性强度——账务错不起所以 CP,营销错得起所以 AP”

【关键数字】

参数经验值说明
账务一致性强一致(CP)不一致窗口内不允许错误记账
强同步复制延迟同城 < 2ms多数派提交
营销最终一致 SLA秒级刷新即可见
对账周期资金 T+0 准实时 + T+1 日终双保险
账务差错处理超阈值人工双人复核调账本身留痕
查询从库延迟容忍秒级写后读主弥补

【追问链】(三层)

L1|“核心账务选 CP,高峰期拒绝服务客户不会投诉吗?” → 账务写操作可短暂排队/拒绝,但查询走从库保证可读。关键是“钱不错”比“立刻成功”更重要。可用性用同城双活+快速切流补:正常时双活都可用,只有真正的分区/故障时才触发 CP 行为,而那种时候本来也难以正常服务。

L2|“最终一致怎么保证不丢?” → 本地消息表保证业务与消息同事务提交;MQ 重试 + 死信兜底投递;定时对账发现漏单。三重机制缺一不可。对账是最后一道防线——即使消息全丢,日终对账也能发现差异并补处理。

L3|“能不能做个既强一致又高可用的系统?” → CAP 说的是分区场景。常态下 Raft/ZAB 多数派存活即可既一致又可用。跨地域时:单地域 Raft 强一致,跨地域异步复制+最终一致,或单元化把交易锁在单地域。不能在跨分区场景同时要 C 和 A,但可以在无分区时两者兼得。

【评分标准】

档位答案特征
60 分知道 CAP 三选二,账务选 CP
80 分先澄清“分区时才取舍”;账务 CP、营销 AP 分级;能落到强同步、TCC、对账
95 分论证“错误代价决定一致性强度”;分级混用整体观;对账是独立于协议的最终防线;能答“为何账务不能最终一致”的金融约束

【关联题】

  • 互联网理论版: 第 97 题(CAP)、第 98 题(BASE)——本题是金融落地改造
  • 事务专题: 第 218 题(金融分布式事务)——TCC/状态机的具体实现
  • 对账兜底: 第 219 题(日终对账)——CP 之后的最终防线
  • 读写分离: 第 216 题(主从延迟)——查询 AP 的具体问题

【自测】

  1. 为什么账务不能选最终一致? 参考答案:不一致窗口内的错误记账是资金差错,进监管投诉、影响账务平衡;事后补偿代价远大于分区期暂时拒绝服务。
  2. 营销系统为什么可以 AP? 参考答案:券/积分短暂不一致用户无感,错了可补偿,错误代价低;用不一致换可用性划算。
  3. 为什么 CP 了还要做对账? 参考答案:CP 只保证分区时不制造不一致,不能防应用 bug、消息丢失、人工误操作。对账是独立于运行时协议的最终防线,分层设防。

213. 转账接口被重复调用导致重复扣款(金融级接口幂等) ​

【考察内容】金融场景的幂等设计

【题目】客户点了一次“转账”,但因为网络超时客户端自动重试,后端收到两次请求,客户被扣了两次钱。请说明如何设计幂等来根治,并解释为什么这个场景比普通电商的幂等要求更严。

【参考答案】

  1. 幂等键设计:客户端生成全局唯一请求流水号(UUID 或 业务号+时间戳+随机数),服务端以该流水号为幂等键;

  2. 存储与判定:用唯一索引(或 Redis SETNX)挡重复——INSERT INTO txn_log(request_id, ...) UNIQUE KEY(request_id),插入失败即为重复请求,直接返回首次结果;

  3. 状态机:转账单有明确状态流转(待处理 → 处理中 → 成功 / 失败),幂等判定要结合状态:同流水号 + 同状态 → 返回原结果;同流水号 + 不同参数 → 拒绝并告警(防篡改);

  4. 与业务的一致性:幂等记录与业务扣款必须在同一个本地事务里提交(或“先落幂等记录,再走业务,最后更新状态”的本地消息表模式),否则会出现“幂等记录有了但钱没扣”或“钱扣了但幂等记录没落”;

  5. 为什么比电商严:电商重复下单可取消、钱能退;银行重复扣款是资金差错,会进监管投诉、影响账务平衡,且客户感知极强。因此必须做到“宁可拒绝,不可重复”,并配套对账与差错处理。

  6. 容量估算: 幂等键存储:按日交易量×保留期(金融常 1–7 年)。如日 1000 万笔×1 年≈36 亿条,需分库分表或归档。幂等键长度与索引要考虑。重复请求命中率监控。接口超时重试策略与幂等配合(客户端 1 次+服务端去重)。

  7. 失败与降级: 幂等存储不可用:金融资金接口 fail-closed(拒绝交易)而不是放行重复;非资金查询可放行但打日志。补偿任务与人工调账通道必须存在。

【原理溯源】

  • 为什么网络超时会导致重复扣款? 客户端超时后不知道服务端是否已处理,只能重试;服务端若无幂等机制,会把重试当成新请求再扣一次。这不是客户端的错——分布式系统中“至少一次”投递是常态,幂等必须在服务端保证,不能指望客户端不重试。
  • 为什么唯一索引比 Redis SETNX 更可靠? SETNX 依赖 Redis:主从切换可能丢写、宕机可能丢数据。唯一索引依赖数据库 ACID:只要事务提交,约束一定生效。金融场景必须有不依赖缓存的最终防线——Redis 只是前置拦截减压,唯一索引才是正确性保证。
  • 为什么幂等要“结合状态机”而不是只看 key? 只看 key:同一流水号第二次请求直接返回首次结果。但若第一次还在“处理中”(未终态),返回“处理中”给客户端可能导致客户端继续重试或展示错误状态。结合状态机:处理中→返回处理中(可轮询);成功→返回成功结果;失败→返回失败原因。更关键的是:同流水号但金额/收款方不同——这不是重试,是篡改或 bug,必须拒绝+告警,不能当成重复请求静默处理。
  • 为什么幂等记录必须与业务扣款同事务? 若分两步:先写幂等记录再扣款,中间宕机→有幂等记录但钱没扣,客户重试被幂等拦截,转账永远失败;先扣款再写幂等记录,中间宕机→钱扣了但无幂等记录,重试会再扣一次。同事务保证两者要么都在要么都不在——这是本地 ACID 事务在金融幂等中的核心价值。
  • 为什么金融幂等是“宁可拒绝,不可重复”? 重复扣款=资金差错,要走差错处理、可能进监管投诉、客户信任受损。拒绝服务=客户重试或稍后再来,代价可控。所以拿不准时(比如幂等存储不可用)应该拒绝请求而不是放行——这是与互联网“尽量服务”的根本差异。

【选型判断树】

金融接口幂等,按防线分层:
1. 前置拦截(性能层)
   └─ Redis SETNX:毫秒级挡重复,减少 DB 压力
2. 最终防线(正确性层)
   └─ DB 唯一索引(request_id):不依赖缓存,ACID 保证
3. 语义判定(业务层)
   ├─ 同流水号 + 同参数 + 处理中 → 返回处理中
   ├─ 同流水号 + 同参数 + 终态 → 返回首次结果
   └─ 同流水号 + 不同参数 → 拒绝 + 告警(防篡改)
4. 事务一致性
   └─ 幂等记录与业务扣款同一本地事务
5. 不确定时
   └─ 拒绝服务,不放行(宁可拒绝不可重复)

口诀:Redis 挡在前,唯一索引兜在底,状态机判语义,同事务保一致。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“分布式至少一次投递是常态,幂等必须服务端保证”
0:30–1:30双层防线Redis SETNX 前置拦截;DB 唯一索引最终防线
1:30–2:30状态机判定处理中/成功/失败分别返回什么;不同参数=篡改要拒绝
2:30–3:30事务一致性幂等记录与扣款同事务,避免半吊子状态
3:30–4:30与电商对比电商重复可退;银行重复=资金差错;宁可拒绝不可重复
4:30–5:00收尾“一句话:金融幂等是双层防线 + 状态语义 + 同事务,拿不准时拒绝”

【关键数字】

参数经验值说明
幂等键全局唯一请求流水号UUID 或 业务号+时间戳+随机
Redis SETNX TTL覆盖最大重试窗口,通常 ≥ 24h资金类建议长期
唯一索引request_idDB 层最终防线
幂等有效期热层 1–7 年可查,终态归档长期留存审计与对账需要;"永久"指归档层,不是热库
重试策略客户端指数退避 + 最多 3–5 次减少无效重试
状态机终态成功/失败/已退回处理中可轮询

【追问链】(三层)

L1|“Redis 挂了怎么办?” → 唯一索引是最终防线。Redis 只是前置拦截,挂了流量直达 DB,DB 唯一索引仍能挡重复。代价是 DB 压力增大,需要限流保护。正确性不依赖 Redis,这是金融幂等的设计原则。

L2|“同流水号不同金额怎么处理?” → 这不是重试,是篡改或客户端 bug。必须拒绝请求并告警,不能当成重复请求返回首次结果——否则攻击者可能用同一流水号、不同金额反复试探。金融安全要求语义严格匹配。

L3|“幂等记录和业务扣款为什么要同事务?分两步不行吗?” → 分两步会出现半吊子:先写幂等后扣款,中间宕机→有幂等无扣款,重试被拦截,转账永远失败;先扣款后写幂等,中间宕机→有钱无幂等,重试再扣一次。同事务保证要么都在要么都不在——这是本地 ACID 在金融幂等中的核心价值。

【评分标准】

档位答案特征
60 分知道用 Redis 或唯一索引防重复
80 分双层防线;结合状态机判定;幂等与业务同事务
95 分论证“宁可拒绝不可重复”的金融约束;同流水号不同参数=篡改要拒绝;幂等有效期覆盖审计需求;能对比电商幂等的严格程度差异

【关联题】

  • 互联网版原型: 第 110 题(接口幂等)——本题是金融口径改造
  • 分布式事务: 第 218 题(金融分布式事务)——TCC 中的幂等
  • 对账兜底: 第 219 题(日终对账)——幂等失效后的最终防线
  • 秒杀防重: 第 211 题(金融抢购)——唯一索引防重复购买

【自测】

  1. 为什么金融幂等必须有 DB 唯一索引,不能只用 Redis? 参考答案:Redis 主从切换可能丢写、宕机可能丢数据;唯一索引依赖 DB ACID 是最终防线。Redis 只是前置拦截减压。
  2. 同流水号但金额不同,应该怎么处理? 参考答案:这不是重试而是篡改或 bug,必须拒绝+告警,不能静默当成重复请求。
  3. 为什么说金融幂等是“宁可拒绝,不可重复”? 参考答案:重复扣款是资金差错(监管投诉、账务不平、客户信任);拒绝服务代价可控。拿不准时拒绝。

214. 客户信息要脱敏,但客服还要能查到(银行级数据安全与脱敏) ​

【考察内容】数据分级分类 + 动态脱敏 + 受控解密 + 审计留痕

【题目】监管要求客户手机号、身份证号、银行卡号在系统里必须脱敏展示;但客服在核身通过后又需要看到完整信息。请设计一套方案,兼顾合规与业务可用。

【参考答案】

  1. 分级分类:先给数据定级——L1 公开、L2 内部、L3 敏感(手机号 / 身份证 / 卡号)、L4 核心(密码 / 密钥)。不同级别不同策略;

  2. 存储层:敏感字段加密存储(如 AES + KMS 托管密钥),密码类用加盐哈希(BCrypt / Argon2),不可逆;需要检索的字段(如手机号)存“加密值 + 哈希索引”两列,用哈希列做等值查询;

  3. 展示层(动态脱敏):默认接口返回脱敏值(138****8888),在网关 / 序列化层统一做,避免每个业务代码各写一遍;脱敏规则配置化(不同角色不同规则),不硬编码;

  4. 明文获取(受控解密):独立“解密服务”,需二次授权(业务系统申请 + 权限校验 + 事由填写);解密操作全量审计(谁、何时、查了谁的什么字段、什么理由),审计日志不可篡改、独立存储;支持按需授权(如客服核身后限时 5 分钟可见)、次数限制、异常行为告警;

  5. 其他:数据传输全程 HTTPS / 国密;日志与埋点中禁止出现明文(日志脱敏中间件);测试环境用假数据。

  6. 容量估算: 脱敏规则与性能:展示层脱敏 CPU 开销低;密文检索用盲索引/保序加密要评估安全与性能。客服查询审计日志按查询次数全量保存。权限模型:角色数×字段策略,避免组合爆炸。国密算法改造时接口加解密 RT 增量压测。

  7. 失败与降级: 脱敏服务故障:默认不展示明文(fail-closed),提供工单紧急授权通道。密钥服务不可用时暂停需要解密的查询,核心交易用缓存 DEK 限时。

【原理溯源】

  • 为什么脱敏要在网关/序列化层统一做? 业务代码分散在几十上百个服务里,让每个开发者记得脱敏,必然漏。漏一处=一处泄露面。在网关/序列化层统一拦截,所有出口流量走同一套规则——把安全控制从业务逻辑中抽离,用架构保证而不是靠人的自觉。这也是“默认不可见”原则的工程落地。
  • 为什么“客服核身后可见”不破坏脱敏的价值? 脱敏的意义是把“默认可见”反转成“默认不可见”。原本所有接口、所有日志、所有导出都可能带明文;改后明文获取变成需要二次授权、事由填写、全量留痕的例外操作。暴露面从“无处不在”收窄到“受控通道”,且通道内每一次访问都可追溯——这是合规检查的核心逻辑。
  • 为什么密码用哈希而手机号用加密? 密码只需要验证对错,不需要还原——加盐哈希(BCrypt/Argon2)不可逆,库被拖也无法直接得到明文。手机号/身份证需要支持查询和核对——加密可逆,配合密钥管理;再存一列哈希做等值索引。选可逆还是不可逆,取决于业务是否需要还原。
  • 为什么审计日志必须独立存储且不可篡改? 若审计日志与业务库同权限,拿到业务库权限的人可以直接改日志抹掉“谁看过什么”的痕迹——审计就失去“不可否认”的价值。独立存储+独立权限+append-only,是审计可信的前提。金融行业“谁看了客户信息”和“谁改了客户信息”同等重要。
  • 为什么密钥要 KMS 托管、与数据分离? 密钥和密文放在一起,等于没加密。KMS 托管实现密钥与数据分离存储、权限控制、使用审计、定期轮换。即使数据库被拖,没有 KMS 权限也解不开——这是纵深防御的一层。

【选型判断树】

敏感数据方案,按数据分级决策:
1. 先分级
   ├─ L4 核心(密码/密钥)→ 加盐哈希,不可逆
   ├─ L3 敏感(手机/身份证/卡号)→ 加密存储 + 哈希索引 + 动态脱敏
   ├─ L2 内部 → 按角色可见,关键操作审计
   └─ L1 公开 → 无需特殊处理
2. 展示层
   └─ 默认脱敏(网关/序列化层统一),角色可配置
3. 明文获取
   ├─ 独立解密服务
   ├─ 二次授权 + 事由填写
   ├─ 限时 + 限次
   └─ 全量审计(独立存储、不可篡改)
4. 配套
   ├─ 日志/埋点禁止明文
   ├─ 密钥 KMS 托管、定期轮换
   └─ 测试环境用假数据

口诀:默认不可见,明文是例外;例外必须留痕。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“兼顾合规与业务,核心是把默认可见反转成默认不可见”
0:30–1:30分级存储L1–L4 分级;密码哈希不可逆;敏感字段加密+哈希索引
1:30–2:30动态脱敏网关/序列化层统一做;规则配置化;不靠业务代码自觉
2:30–3:30受控解密独立服务;二次授权+事由;限时限次;全量审计
3:30–4:30审计独立独立存储、不可篡改;“谁看了”与“谁改了”同等重要
4:30–5:00收尾“一句话:脱敏把明文从默认变成例外,例外全部留痕可追溯”

【关键数字】

参数经验值说明
数据分级L1 公开 / L2 内部 / L3 敏感 / L4 核心级别决定策略
客服明文可见时长核身后 5–15 分钟限时授权
明文查询次数限制日上限(如 50–200 次)防批量倒卖
加密算法AES-256;国密 SM4传输 HTTPS/国密
密码哈希BCrypt / Argon2加盐,不可逆
审计留存金融 ≥ 5 年独立存储
密钥轮换90–180 天KMS 托管
日志脱敏禁止明文写入 L3/L4 字段日志中间件统一

【追问链】(三层)

L1|“客服要看完整信息,那脱敏还有意义吗?” → 有。意义在于把“默认可见”反转成“默认不可见”,把明文获取变成需要留痕的例外操作,大幅收窄暴露面。原本所有接口/日志/导出都可能带明文;改后只有受控通道,且每次访问可追溯。

L2|“加密后还能按手机号查询吗?” → 存“加密值 + 哈希索引”两列:查询时对输入手机号做同样哈希后在哈希列上等值匹配。范围查询需另建辅助索引或用可搜索加密。关键不是“确定性哈希”而是带密钥的确定性:裸哈希(如 SHA256(手机号))可枚举反推——有效号段约 7×10^9(13x–19x),比 10^11 的表观空间小一个量级但仍可穷举,必须用 HMAC(密钥放 KMS)或本题【容量估算】提到的盲索引,并按租户加盐。

L3|“密钥怎么管?万一泄露怎么办?” → KMS 托管,密钥与数据分离存储;定期轮换(90–180 天);密钥使用本身有审计。泄露应急:立即轮换密钥→用新密钥重加密数据→排查泄露范围→按监管要求上报。

【评分标准】

档位答案特征
60 分知道接口返回时打星号
80 分有分级分类;区分加密与哈希;默认脱敏+受控解密双轨
95 分主动提审计留痕独立存储;网关层统一脱敏的架构理由;密码不可逆vs手机号可逆的选型依据;密钥KMS托管;“默认不可见”的合规逻辑

【关联题】

  • 互联网安全版: 第 193 题(敏感数据加密)、第 196 题(日志合规)
  • 审计专题: 第 220 题(审计留痕与等保)——受控解密的下游审计
  • 情景题: 第 227 题(明文密码)——发现不合规时的推动
  • 登录认证: 第 209 题(高可用登录)——认证体系的数据安全面

【自测】

  1. 为什么密码用哈希、手机号用加密? 参考答案:密码只需验证对错不需要还原→加盐哈希不可逆;手机号需支持查询和核对→加密可逆+哈希索引。
  2. 脱敏在业务代码里做还是网关层做?为什么? 参考答案:网关/序列化层统一做。业务代码分散必然漏,架构保证比人的自觉可靠。
  3. 审计日志为什么要独立存储? 参考答案:同库同权限时,拿业务权限就能改日志抹痕,审计失去不可否认价值。

215. 全国 1 亿用户数据单库扛不住(金融数据分片) ​

【考察内容】分片策略设计 + 金融场景的分片键选择

【题目】全国 1 亿宽带用户信息存在一张表里,单库单表已经扛不住写入和查询压力。请设计分片方案,并说明分片键怎么选。

【参考答案】

  1. 分片键选择(最关键):候选有用户 ID、手机号、省份(province_id)、地市。按省份 / 地市分片天然贴合电信业务的查询习惯(大部分查询带地域维度),且各省数据量相对均衡,运维可按省隔离、按省扩容;若业务查询以用户维度为主,则用用户 ID 哈希分片,保证单用户查询落在单分片;实践中常见两级分片——先按省(业务维度,便于隔离与合规),省内再按用户 ID 哈希(数据均衡);但两级分片成立的前提是「查询能带上第一级键」:题干若用户点查不带省份(或用户 ID 里没编码省份),路由层就只能对 31 个省各查一遍再归并,反而比单层按 user_id 哈希慢一个数量级。所以先问两件事:① 查询是否总带地域维度(报表/按省稽核→带;App 查自己的账单→通常不带);② 能否让 user_id 本身编码省份段(或维护一张 user→province 路由表并在写入时固化)。两者都不成立就别硬套两级分片,直接按 user_id 哈希+异构出「按省」的汇总表;

  2. 分片方式:范围分片(易扩容、易热点)vs 哈希分片(均衡、扩容需迁移);金融场景更看重稳定,常用“预分片 + 一致性哈希 / 双倍扩容”降低迁移成本;

  3. 路由与中间件:用 ShardingSphere / 自研路由,SQL 解析后按分片键路由;分片键必须出现在查询条件里,否则广播查询;

  4. 跨分片查询:跨省统计走数仓 / 分布式 SQL 引擎(如 Presto / ClickHouse),不在线上库做全分片扫描;

  5. 配套:全局唯一 ID(雪花算法,注意时钟回拨)、分布式事务(分片后跨库事务)、分片扩容方案(双写迁移 + 校验 + 切流)。

  6. 容量估算: 1 亿用户:账户主数据单行 KB 级约 100GB+,单库难扛扩展与DDL。分片键选择:用户号取模/范围;热点产品账户可能倾斜需二次散列。每分片目标 <5000 万行、磁盘水位 <60%。全局唯一 ID、跨片查询走索引表/ES。迁移期双写与校验抽样比例。

  7. 失败与降级: 单分片故障:影响该分片用户,需快速切换/重建;跨分片事务用最终一致+补偿,不阻塞全局。路由服务要做多级缓存,防止路由表故障全局不可用。

【原理溯源】

  • 为什么分片键选择比索引优化重要得多? 索引解决“单库内怎么查快”,分片键决定“数据落在哪、查询路由到哪”。分片键选错:查询带不上分片键→广播全部分片;数据倾斜→热点分片打满。分片键一旦定下,迁移成本极高——所以是分片设计的第一决策。
  • 为什么金融/电信场景常用“按省分片”? ①业务查询天然带地域(按省出报表、按省监管报送);②运维可按省隔离——某省故障不影响他省,符合国企“局部故障不扩散”的稳定性要求;③合规上数据可按省留存。这是业务维度优先于技术维度的选型思路。
  • 为什么还要省内再哈希? 按省分片时人口大省数据量是小省的数倍,直接按省到库会造成倾斜。省内再按用户 ID 哈希拆子片,既保留“按省路由、按省运维”的优势,又保证数据均衡——两级分片 = 业务隔离 + 技术均衡。
  • 为什么跨分片查询要走数仓? 线上库的职责是点查/小范围查;跨省统计、全量报表是分析型负载——扫描量大、延迟容忍度高。把分析负载扔到线上库会拖垮交易。在线与分析分离,是亿级数据架构的基本原则。
  • 为什么金融场景偏好预分片? 取模分片扩容时模数变化→几乎所有数据要重新分布。预分片(逻辑分片数远大于物理分片数)扩容时只迁移部分逻辑片,迁移量是 1/N。金融系统重视稳定,宁可初期多分几片,也不要扩容时全量搬迁。

【选型判断树】

分片键怎么选?先看查询模式:
├─ 查询 90%+ 带地域维度(电信/政务)
│   → 按省分片;大省再哈希拆子片(两级分片;要求查询能带第一级键,否则退化为广播)
├─ 查询以用户维度为主(转账/账单)
│   → 用户 ID 哈希分片;保证单用户落单分片
├─ 既要地域隔离又要用户均衡
│   → 两级:先按省路由,省内按用户 ID 哈希(**前提:查询带省或 user_id 已编码省**;都不带时只能广播 31 省,别用两级)
└─ 分片方式
    ├─ 金融偏好 → 预分片(逻辑片 >> 物理库)+ 扩容平滑
    └─ 热点明显 → 范围分片 + 大热点单独隔离

硬约束:分片键必须进查询条件,否则广播;跨片分析走数仓。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“分片键选择决定数据布局与查询路由,是第一决策”
0:30–1:30选型先问「查询带不带省」:带 → 按省分片贴合业务与运维隔离、省内再哈希保均衡;不带 → 直接按 user_id 哈希,另出按省汇总表
1:30–2:30分片方式范围 vs 哈希;预分片降低扩容迁移成本
2:30–3:30路由与跨片分片键必须进条件;跨省统计走数仓不走线上
3:30–4:30配套全局 ID(雪花);分布式事务;双写迁移+校验+切流
4:30–5:00收尾“一句话:先按业务查询模式选分片键,再用预分片保扩容平滑”

【关键数字】

参数经验值说明
数据规模1 亿用户单表必须分片
单分片容量千万级行再大索引/备份都吃力
预分片逻辑片物理库数 × 64–1024扩容时只迁 1/N
两级分片省 → 省内用户 ID 哈希隔离 + 均衡;成立前提=查询带第一级键(或 ID 编码省份)
跨片查询走数仓/Presto不在线上广播
全局 ID雪花算法注意时钟回拨
扩容方式双写迁移 + 校验 + 切流金融偏好可回滚
单用户查询必须落单分片分片键=用户 ID

【追问链】(三层)

L1|“扩容时取模变了怎么办?” → 取模分片扩容需数据迁移。改用预分片(逻辑分片数远大于物理库数)或一致性哈希:扩容时只迁移部分逻辑片到新库,迁移量是 1/N。金融场景偏好预分片。

L2|“按省分片会不会数据倾斜?” → 会,人口大省数据多。对大省再按用户 ID 哈希拆子片(两级分片);或按“省+哈希”混合。关键是保留“按省路由、按省运维”的业务优势,同时消除技术倾斜。

L3|“跨省查询怎么做?” → 离线/报表走数仓(Presto/ClickHouse);在线需跨省的场景建异构索引表或 ES。不在线上库做全分片广播扫描。

【评分标准】

档位答案特征
60 分知道按 ID 取模分片
80 分结合业务查询模式选分片键;分片键必须进条件;预分片
95 分两级分片(省+哈希)的隔离与均衡论证,并能说出它要求查询带第一级键、否则只能广播;跨片分析走数仓;扩容双写迁移可回滚;全局 ID 与分布式事务的配套意识

【关联题】

  • 分页专题: 第 210 题(亿级流水分页)——分片后的分页
  • 分布式事务: 第 218 题(金融分布式事务)——分片后跨库事务
  • 读写分离: 第 216 题(主从延迟)——分片+读写的组合
  • 互联网版: 分库分表通用知识——本题强调金融/电信业务维度选型

【自测】

  1. 为什么金融/电信场景常按省分片而不是按用户 ID 哈希? 参考答案:业务查询天然带地域;运维可按省隔离;合规可按省留存。大省再哈希拆子片解决倾斜。
  2. 预分片为什么能降低扩容成本? 参考答案:逻辑分片数远大于物理库数,扩容时只迁移部分逻辑片到新库,迁移量是 1/N。
  3. 跨省统计应该怎么做? 参考答案:走数仓/OLAP 引擎,不在线上库广播扫描;在线跨省需求建异构索引或 ES。

216. 核心库读压力大,读写分离后主从延迟(金融读写分离) ​

【考察内容】读写分离架构 + 主从延迟的业务处理

【题目】核心账务库读压力大,做了读写分离(写主库、读从库)后,出现“客户刚转账成功,刷新却查不到这笔记录”。请说明原因和解决方案。

【参考答案】

  1. 原因:MySQL 主从复制是异步(或半同步)的,从库回放有延迟(网络 + 单线程/多线程回放),秒级到分钟级都可能。写主库后立刻读从库,就会读到旧数据(读己之写问题);

  2. 解决方案(按业务影响面排序):

    • 写后强制读主:写操作后对该用户的短时间窗口(如 3–5 秒)内的读请求路由到主库,窗口过后回从库;实现方式:写时在 Redis / 本地缓存打一个“用户级标记”,读时判断;
    • 按业务分流:账务类“刚发生的交易”必须读主;历史流水查询、统计类读从库;
    • 会话粘性:同一用户在同一会话内的读写都走主库;
    • 半同步复制 / 组复制(MGR):至少保证从库收到 binlog 才返回成功,把延迟压到最低(代价是写入变慢);
    • GTID + 位点校验:读从库前校验位点是否已追平,未追平则等待或降级读主;
  3. 兜底:对“读不到”的场景给出明确提示(如“交易处理中,请稍后查看”),并在前端做乐观展示。

  4. 容量估算: 读写分离:主库写 QPS 与从库读 QPS 分开压测。延迟预算:核心“读己之写”路径强制主库;报表读从库。金融日终批量时延迟可能激增,要隔离。从库数量按读峰值/单从能力。连接路由中间件本身单点风险要双活。

  5. 失败与降级: 延迟超过阈值时只把「该用户这笔写后读」切回主库,不做「关键读整体切主」:题干前提就是核心账务库读压力大才做读写分离,整体切主正是本块判死的「全部读主=读写分离白做」,再靠主库限流会把客户从「查不到」变成「被拒」;正解是动态把写后窗口拉长到当前延迟 P99、只对该用户该笔走主库+异步补推与前端提示,从库确实不可用才从连接池摘除。从库挂了从连接池摘除。日终对账期间暂停非核心读。

【原理溯源】

  • 为什么异步复制必然有延迟? 主库提交事务后立即返回,binlog 异步发送到从库并回放。延迟 = 网络传输 + 从库回放耗时。回放若是单线程,大事务会堵住后续所有事务。这是可用性和性能换一致性的典型取舍。
  • 为什么金融账务不能接受“读到旧数据”? 客户刚转账成功,刷新却看不到——这不只是体验问题,会引发“钱丢了”的恐慌、客服投诉、甚至监管问询。金融查询的语义是“账务事实”,不是“可能的近似值”。所以账务类刚发生的交易必须读主。
  • 为什么“写后读主”比“全部读主”好? 全部读主:读流量回到主库,读写分离白做。写后读主:只把该用户写后的短窗口(覆盖复制延迟 P99)内的读路由到主库,其余仍读从。用最小的主库增量换取读己之写的正确性——精准升级,而不是一刀切。
  • 为什么半同步不是万能的? 半同步要求至少一个从库收到 binlog 才返回成功,延迟增加约一次网络 RTT。且超时后会退化为异步(保证可用性优先)。所以半同步是“把延迟压到最低”而非“消灭延迟”;配合写后读主,双保险。
  • 为什么前端要做乐观展示? 即使后端做了写后读主,网络抖动、缓存过期等仍可能短暂查不到。前端在用户完成转账后本地先展示“待确认/处理中”,后台确认后刷新为“成功”——用户感知是连续的。

【选型判断树】

读写分离后读到旧数据,按业务分级处理:
├─ 账务刚发生的交易(转账、扣款)
│   → 写后读主(用户级标记,窗口=复制延迟 P99)
│   → 或会话粘性:同会话读写都走主
├─ 历史流水、统计报表
│   → 读从库,容忍秒级延迟
├─ 复制延迟压不下来
│   → 半同步 / MGR(代价:写变慢)
│   → GTID 位点校验,未追平则等待或降级读主
└─ 兜底
    └─ 前端乐观展示 + “处理中”提示

口诀:账务读主,历史读从;写后窗口精准升级,不一刀切。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“读己之写问题:异步复制导致从库落后”
0:30–1:30机制主库提交即返回,binlog 异步回放;延迟=网络+回放
1:30–2:30分层方案写后读主(精准窗口);账务读主/历史读从;会话粘性
2:30–3:30压延迟半同步/MGR;GTID 位点校验
3:30–4:30金融约束账务查询是“事实”不是“近似”;前端乐观展示
4:30–5:00收尾“一句话:按业务分级路由,账务写后读主,历史读从”

【关键数字】

参数经验值说明
异步复制延迟正常 <1s,异常可达分钟级网络/大事务
写后读主窗口3–5 秒(取延迟 P99)可配置
半同步延迟增加约 1 次网络 RTT同城 <2ms
半同步超时退化超时后降为异步可用性优先
会话粘性同用户同会话走主实现简单但主库压力大
前端乐观展示转账后本地“处理中”避免感知断裂

【追问链】(三层)

L1|“写后读主的窗口设多久?” → 取复制延迟的 P99(本题按 3–5 秒),窗口内读主,窗口外读从。窗口本身要可配置,根据监控的延迟分布动态调整。

L2|“半同步会不会拖慢写入?” → 会,增加约一次网络 RTT。所以通常只在核心账务库用,且设置超时降级为异步。或用 MGR/并行复制缓解。金融场景为正确性付这点延迟是值得的。

L3|“读不到时直接报错行不行?” → 不行,客户会恐慌“钱丢了”。应给明确提示“交易处理中,请稍后查看”,前端做乐观展示。关键是不制造焦虑。

【评分标准】

档位答案特征
60 分知道主从延迟导致读旧数据
80 分说清读己之写;写后读主+业务分流+半同步组合
95 分按业务分级路由(账务读主/历史读从);窗口取延迟 P99;前端乐观展示的体验意识;金融账务“事实而非近似”的语义约束

【关联题】

  • 互联网版原型: 第 59 题(读写分离延迟)——本题是金融口径改造
  • CAP 落地: 第 212 题(CAP 金融取舍)——查询 AP 的具体问题
  • 分页查询: 第 210 题(亿级流水分页)——历史查询读从
  • 容灾: 第 222 题(同城双活)——强同步复制的另一个应用

【自测】

  1. 什么是读己之写问题? 参考答案:写主库后立刻读从库,因复制延迟读到旧数据。刚转账成功刷新却查不到。
  2. 为什么不用“全部读主”解决? 参考答案:读流量回到主库,读写分离白做。应写后读主:只把写后短窗口的读路由到主,其余读从。
  3. 账务查询和历史查询的路由策略有什么不同? 参考答案:账务刚发生的交易必须读主(事实语义);历史流水/统计读从(容忍秒级延迟)。

217. 大促式流量下核心系统不能停(金融级服务降级) ​

【考察内容】降级设计 + 业务影响面控制

【题目】某银行做营销活动,流量是平时的 10 倍,核心账务系统压力剧增。要求在流量峰值时“保证核心业务可用、非核心功能可牺牲”。请设计降级方案。

【参考答案】

  1. 先做业务分级(降级的前提):P0 不可降——转账、扣款、账务记账、登录;P1 可延迟——账单查询、历史流水、消息推送、积分更新;P2 可关闭——活动页个性化推荐、排行榜、弹窗广告、非必要的埋点上报;

  2. 降级手段:读降级(非核心查询直接返回缓存 / 默认值 / “系统繁忙,请稍后”);写降级(非核心写如积分、埋点、日志异步化或本地落盘后补);功能降级(关闭个性化推荐、简化页面、关闭非必要风控规则需审批);依赖降级(下游超时立即熔断,返回兜底值,不阻塞主链路);

  3. 触发机制:自动(错误率 / RT / 线程池水位超阈值自动降级)+ 手动(开关在配置中心,值班可一键切换);必须有开关、有灰度、有回滚;

  4. 前置准备:容量压测确认阈值、降级预案演练、开关默认值评审、降级期间的客户提示话术;

  5. 事后:降级期间记录明细,恢复后补数据(如积分补发),并复盘是否要永久优化。

  6. 容量估算: 金融降级分级:L1 营销/推荐可弃;L2 非核心查询只读/缓存;L3 核心转账排队但不丢。流量按“必须服务的最小功能集”反推机器与 DB 容量。限流阈值分层:网关全局、服务、用户、渠道。演练分两件事:预案切换演练每季度至少 1 次(验证降级/切流真能生效),全链路压测每年至少 1 次(验证容量水位),别把两者合成一句“每年一次”。

  7. 失败与降级: 预案必须可一键执行:开关中心化、有权限、有审计。降级期间 SLA 口径要提前定义(排队成功率、最长等待)。恢复时按反序慢慢放量,防止二次冲击。

【原理溯源】

  • 为什么降级的前提是“业务分级”而不是先上熔断器? 熔断器只回答“依赖挂了怎么办”,不回答“该牺牲谁”。没有业务分级,降级变成随机丢弃——可能把转账也降了。P0/P1/P2 分级的本质是在资源紧张时明确资源分配的优先级。这是业务决策,不是技术决策。
  • 为什么金融降级不能“关掉风控”? 风控是资金安全的防线。关掉风控=打开欺诈窗口,活动期间正是攻击者活跃期。若非核心风控规则可降,需审批+白名单+事后加强审计;核心风控(转账反欺诈)绝不可降。降级降的是体验,不是安全。
  • 为什么开关必须“有灰度、有回滚”? 降级开关配错可能把 P0 关了——比不降级更糟。灰度:先对 1% 流量生效,观察无异常再全量;回滚:一键恢复;白名单:核心功能的开关在代码层面硬编码为不可降。这是用发布工程的严谨对待降级操作。
  • 为什么降级后要“补数据”? 写降级时积分/埋点落本地或丢弃,恢复后必须补发——否则客户积分少了是投诉,埋点丢了是数据缺口。降级是临时手段,业务语义必须最终完整。这也符合金融“对账闭环”思维。
  • 为什么自动降级和手动降级都要有? 自动降级反应快(错误率超阈值秒级触发),但可能误判;手动降级准确(值班结合业务判断),但反应慢。两者互补:自动兜住突发故障,手动处理复杂场景。

【选型判断树】

降级方案设计,按步骤:
1. 业务分级(前提)
   ├─ P0 不可降:转账、扣款、记账、登录、核心风控
   ├─ P1 可延迟:账单查询、历史流水、推送、积分
   └─ P2 可关闭:推荐、排行榜、弹窗、非必要埋点
2. 降级手段
   ├─ 读降级:非核心查询返回缓存/默认值
   ├─ 写降级:积分/埋点异步化或落盘后补
   ├─ 功能降级:关闭个性化(核心风控除外)
   └─ 依赖降级:下游超时熔断,返回兜底值
3. 触发与控制
   ├─ 自动:错误率/RT/线程池水位
   ├─ 手动:配置中心一键切换
   └─ 硬约束:开关可灰度、可回滚、核心功能白名单
4. 事后
   └─ 补数据(积分补发)+ 复盘

口诀:先分级,再降非核心;降体验不降安全;降完要补。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“降级的前提是业务分级,核心是影响面控制”
0:30–1:30P0/P1/P2转账记账登录不可降;查询推送可延迟;推荐弹窗可关
1:30–2:30四类手段读降级、写降级、功能降级、依赖降级
2:30–3:30触发控制自动+手动;开关灰度回滚;核心功能白名单硬编码
3:30–4:30金融约束风控不可随意降;降完补数据;压测与演练前置
4:30–5:00收尾“一句话:降级是资源再分配,降体验不降安全,降完要闭环”

【关键数字】

参数经验值说明
流量倍数平时 10 倍活动峰值
自动降级触发错误率 >1% 或 RT P99 >1s可配置
开关生效时间秒级(配置中心推送)必须预置
灰度比例先 1% 观察再全量防开关配错
核心功能白名单转账/扣款/记账/登录/核心风控代码层不可降
降级补数据恢复后 24h 内积分/优惠券补发
演练频率每季度至少 1 次预案有效性验证

【追问链】(三层)

L1|“降级开关配错了把核心功能关了怎么办?” → 核心功能开关在代码层硬编码为不可降,配置中心改不了;或需双人审批+灰度发布+自动校验(配置变更后比对白名单)。

L2|“降级期间客户投诉怎么办?” → 前端明确提示(“系统繁忙,推荐暂时关闭”);客服话术预案;事后主动补偿(积分/优惠券)。关键是不静默降级——用户要知道发生了什么。

L3|“能不能把风控也降了换性能?” → 不能。风控是资金安全防线,活动期正是攻击者活跃期。非核心风控规则可降但需审批+事后加强审计;核心风控(转账反欺诈)绝不可降。降级降的是体验,不是安全。

【评分标准】

档位答案特征
60 分知道用熔断器、限流
80 分先业务分级;四类降级手段;开关灰度回滚
95 分论证“降体验不降安全”(风控不可随意降);核心功能白名单硬编码;降完补数据的闭环;压测演练前置;自动+手动互补

【关联题】

  • 互联网版原型: 第 22 题(降级兜底)——本题是金融口径改造
  • 高可用登录: 第 209 题——依赖降级的具体场景
  • CAP 落地: 第 212 题——分级混用的理论基础
  • 对账闭环: 第 219 题——降级后补数据的最终保障

【自测】

  1. 为什么降级前必须先做业务分级? 参考答案:没有分级,降级变成随机丢弃,可能把转账也降了。P0/P1/P2 是资源紧张时的优先级决策。
  2. 风控能不能降级? 参考答案:核心风控不可降;非核心风控可降但需审批+白名单+事后加强审计。降级降体验不降安全。
  3. 降级后为什么要补数据? 参考答案:积分少了是投诉,埋点丢了是数据缺口。降级是临时手段,业务语义必须最终完整。

218. 跨行转账跨 5 个系统,怎么保证钱不错(金融分布式事务) ​

【考察内容】金融分布式事务方案选型

【题目】一笔跨行转账要经过“本行账户扣款 → 本行记账 → 人行清算系统 → 他行入账 → 结果回执”5 个环节,涉及 5 个系统。请设计事务方案,保证钱不错。

【参考答案】

  1. 先明确约束:跨机构转账不能要求全局强一致事务(对方系统不受你控制),只能用最终一致 + 对账;

  2. 本行内部(可控部分):主路径要按题干的「5 个系统」来答——扣款与记账分属两个系统,跨服务只能 TCC;「用本地事务保证原子」只是特例(当且仅当两者同库同事务时最省,成本最低),答题要先说明这个前提再提它,别把它当通用方案;跨服务用 TCC——Try(冻结额度)→ Confirm(实际扣减 + 记账)→ Cancel(解冻)。资金类场景 TCC 比 Saga 更合适,因为冻结机制天然防止“钱花了但没转出去”;或用本地消息表 + MQ;

  3. 跨机构(不可控部分):状态机驱动——转账单有明确状态(已受理 → 已发出 → 对方已入账 → 已完成 / 已退回),每个环节幂等推进;超时未收到回执 → 进入查询-重试-冲正流程;长时间未确认 → 挂起并进人工处理队列;

  4. 最终兜底:日终对账——与人行清算系统、他行逐笔核对;不平的进差错处理流程;

  5. 关键细节:全链路唯一业务流水号贯穿 5 个系统;每步操作幂等;资金冻结有超时自动解冻。

  6. 容量估算: 跨行转账跨系统:典型状态机(受理→人行/网联→账务→通知)。超时与对账窗口:人行支付系统运行时段外只能预约。分布式事务不选 2PC 打满所有系统,金融常用本地事务+消息+对账+差错处理。峰值按代发工资日、节假日前后估算。

  7. 失败与降级: 中间机构失败:转账挂起进“处理中”,禁止自动重复扣款;超时未明确结果的查询状态接口+人工/自动查询查复。账务系统以“最终账”为准,渠道结果靠对账补齐。客户侧要展示明确处理中状态,避免投诉升级。

【原理溯源】

  • 为什么跨机构不能用 2PC/TCC 这类强一致事务? 强一致事务要求所有参与方在同一事务管理器协调下。跨机构时对方系统不受你控制:你无法让对方“执行但不提交”,也无法在对方超时时强制回滚。技术上不可行,组织上也不允许——跨机构只能约定接口协议+对账。
  • 为什么资金场景 TCC 比 Saga 更合适? Saga 用补偿事务回滚:钱已经扣了,失败时再转回来——中间窗口内客户余额少了,若补偿失败则资金悬空。TCC 的 Try 阶段只冻结不扣减:余额显示“冻结中”,Confirm 才真正扣,Cancel 解冻。冻结期间钱还在客户账上(只是不可用),Cancel 失败可重试,超时自动解冻——资金不会凭空消失。
  • 为什么状态机是跨机构协作的正确模型? 跨机构没有分布式锁、没有全局事务,只能靠“双方各自推进状态+异步通知”。明确的状态机让每个参与方知道“当前在哪一步、下一步该干什么、超时了怎么处理”。每步幂等,重复通知不会导致重复入账。
  • 为什么日终对账是最终兜底而非可选项? 运行时的所有机制(TCC、状态机、重试)都可能失效:网络分区丢消息、对方系统 bug、人工误操作。对账是独立于运行时的最终防线。金融系统的可靠性哲学是分层设防,对账是最外层。
  • 为什么全链路唯一流水号至关重要? 5 个系统各自记账,没有统一标识就无法关联“这 5 条记录是同一笔转账”。对账时要靠流水号匹配;排查时要靠流水号串联;冲正时要靠流水号定位。流水号是跨系统的“主键”。

【选型判断树】

跨行转账事务方案,按可控性分层:
├─ 本行单库(扣款+记账)
│   → 本地 ACID 事务
├─ 本行跨服务
│   → TCC(Try冻结→Confirm扣减→Cancel解冻)
│   → 或本地消息表 + MQ
│   → 资金场景优先 TCC:冻结防资金悬空
├─ 跨机构(不可控)
│   → 状态机驱动:已受理→已发出→对方入账→完成/退回
│   → 超时:查询-重试-冲正
│   → 长时间未确认:挂起+人工队列
└─ 最终兜底
    └─ 日终对账 + 差错处理(自动冲正/人工双人复核)

硬约束:全链路唯一流水号;每步幂等;冻结超时自动解冻。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“跨机构无法强一致,只能最终一致+对账”
0:30–1:30本行内部单库本地事务;跨服务 TCC(冻结防悬空)或本地消息表
1:30–2:30跨机构状态机驱动;超时查询重试冲正;挂起人工
2:30–3:30对账兜底日终与人行/他行逐笔核对;差错处理闭环
3:30–4:30关键细节全链路流水号;每步幂等;冻结超时解冻
4:30–5:00收尾“一句话:可控部分 TCC,不可控部分状态机,最终靠对账”

【关键数字】

参数经验值说明
环节数5 个系统扣款→记账→人行→他行→回执
TCC 超时解冻15–30 分钟自动 Cancel 兜底
状态机超时查询发出后 30s–5min 无回执则查询可配置
挂起人工阈值24h 未终态进人工队列
对账周期T+0 准实时 + T+1 日终双保险
幂等键全链路唯一业务流水号贯穿 5 系统
差错人工复核超阈值(如 5 万)双人;阈值须与第 219 题对齐(同一差错链两题阈值差 50 倍会漏复核或占满人工)调账留痕

【追问链】(三层)

L1|“TCC 的 Cancel 失败怎么办?” → Cancel 必须幂等且可重试;重试仍失败则告警进人工;冻结额度有超时自动解冻兜底——即使一切失败,钱最终回到客户账上。这正是 TCC 优于 Saga 的地方:资金不会悬空。

L2|“对方入账了但我方没收到回执怎么办?” → 状态机停在“已发出”,超时后主动查询对方状态;日终对账最终确认。若对方已入账而我方未知,对账时发现后补记“已完成”;重复入账由对方幂等键拦截。

L3|“为什么不用 Seata AT 模式?” → AT 依赖代理数据源自动解析 SQL 生成回滚日志,只能在同一种数据库、同一事务管理器下工作。跨机构时对方系统不受控,AT 根本接不进去。本行内部同构库可用 AT,但资金场景更推荐 TCC——冻结机制语义更清晰。

【评分标准】

档位答案特征
60 分知道用分布式事务、消息队列
80 分识别“跨机构无法强一致”;本行 TCC/本地消息表,跨机构状态机+对账
95 分论证 TCC 冻结优于 Saga 补偿(防资金悬空);日终对账是独立最终防线;全链路流水号贯穿;每步幂等;超时自动解冻

【关联题】

  • 互联网版原型: 第 99–105 题(分布式事务)——本题是金融口径改造
  • CAP 落地: 第 212 题——账务 CP 的具体实现
  • 对账专题: 第 219 题(日终对账)——最终兜底的详细设计
  • 幂等: 第 213 题(金融级幂等)——状态机每步幂等

【自测】

  1. 为什么跨机构不能用强一致事务? 参考答案:对方系统不受控,无法协调提交/回滚;技术上不可行,组织上也不允许。只能接口协议+对账。
  2. 为什么资金场景 TCC 比 Saga 好? 参考答案:TCC 的 Try 只冻结不扣减,Cancel 失败可重试+超时自动解冻,资金不悬空;Saga 先扣再补偿,补偿失败则资金悬空。
  3. 日终对账为什么是必须的? 参考答案:运行时机制(TCC/状态机/重试)都可能失效;对账是独立于运行时的最终防线,发现一切差异并走差错处理。

219. 日终对账发现账不平(对账与差错处理) ​

【考察内容】对账体系设计 + 差错处理流程

【题目】每天凌晨做日终对账,发现本行流水与清算系统有 3 笔金额对不上。请说明对账系统怎么设计,以及发现不平后如何处理。

【参考答案】

  1. 对账体系设计:数据来源为本方交易流水(业务库)+ 对方对账文件(人行 / 银联 / 他行);对账分两层——总账对账(总额、总笔数)→ 明细对账(逐笔比对,以业务流水号 / 清算流水号为键);差异分三类——本方有对方无(长款)、对方有本方无(短款)、双方都有但金额不一致(口径先说清:本库按支付行业惯例「我方有、对方无=长款」;银行柜面现金口径是「实际>账面=长款」,两者字面相反,面试先报口径);时效上 T+1 日终批量为主,重要业务可做准实时对账(分钟级);工程上用分片并行 + 哈希分桶比对,对账结果落库留痕、支持追溯;

  2. 发现不平后的处理流程(差错处理):自动分类(按差异类型和金额阈值分流)→ 自动处理(明显的挂账 / 重复记账可自动冲正;小额差异按规则自动调账)→ 人工介入(金额超阈值或类型不明的进人工队列,需双人复核)→ 闭环(每笔差错有处理状态、处理人、处理时间、处理结果,全部留痕);

  3. 防复发:差异归因分析 → 修复根因(如幂等漏洞、超时未回执)→ 补监控规则;

  4. 监控:对账不平率、未处理差错数、超时未闭环数作为核心指标告警。

  5. 容量估算: 日终对账:流水量×比对算法成本;先哈希聚合再 diff 可降复杂度。差错率经验:正常应 <0.01%,突增必查。差错处理 SLA:当日发现当日挂账,T+1 内人工清理。存储:对账文件与结果按监管年限留存。

  6. 失败与降级: 对账系统挂了:不能“假装平账”,要告警并人工抽对;核心入账不依赖对账系统实时可用(对账是事后控制)。发现不平:冻结可疑差错资金分录,按制度调账,保留审计轨迹。

【原理溯源】

  • 为什么对账要分“总账”和“明细”两层? 总账对账(总额、总笔数)先跑,秒级判断“有没有问题”;但总账平推不出明细没问题:等额一长一短、串户(A 的钱记到 B)都会被总额互抵掩盖。所以总账只作廉价快速筛查与预警,资金账平的判据仍是逐笔轧平 + 借贷平衡,明细比对不能省。这是先粗后细、分层降本——亿级流水全量逐笔比对代价高,总账是廉价的快速筛查。
  • 为什么差异要分三类? 长款(我有他无):可能是我方多记或对方漏记;短款(他有我无):可能是我方漏记或对方多记;金额不一致:可能部分成功或篡改。三类差异的处理逻辑完全不同。分类是自动处理的前提。
  • 为什么差错处理必须“自动分流+人工复核+全量留痕”? 全自动:大额差错自动调账风险太高;全人工:海量小额差错淹没人工。分流:小额有明确规则的自动处理,大额/不明的进人工双人复核。留痕:每笔差错的处理过程可审计——监管检查时要能回答“这 3 笔差异是怎么处理的”。
  • 为什么调账本身也要留痕? 调账是资金操作,与交易同等重要。谁调的、调了多少、依据什么规则、审批记录——全部要可追溯。否则调账可能成为“掩盖问题”的通道。金融的审计逻辑是:一切资金变动都必须可解释。
  • 为什么对账是“闭环”而不是“找出差异”? 找出差异只是开始。差异必须有处理状态、处理人、处理时间、处理结果。超时未闭环的要告警升级。没有闭环的对账等于没做——差异放在那里不会自己消失,只会变成资金损失或监管问题。

【选型判断树】

对账体系设计,按层次:
1. 数据来源
   ├─ 本方:业务库交易流水
   └─ 对方:人行/银联/他行对账文件
2. 对账层次
   ├─ 总账对账:总额+总笔数(先跑,快速筛查)
   └─ 明细对账:逐笔比对(流水号为键)
3. 差异分类
   ├─ 长款(我有他无)→ 查我方是否重复/对方是否漏
   ├─ 短款(他有我无)→ 查我方是否漏记
   └─ 金额不一致 → 查哪边对、是否部分成功
4. 差错处理
   ├─ 自动分流:按类型+金额阈值
   ├─ 自动处理:有规则的小额
   ├─ 人工双人:大额/不明
   └─ 闭环:状态/处理人/时间/结果全留痕
5. 时效
   ├─ T+1 日终批量(全量)
   └─ 准实时(分钟级,重要业务)

硬约束:调账本身留痕;超时未闭环告警;归因防复发。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“对账是金融系统的最终防线,找出差异只是开始”
0:30–1:30体系设计总账→明细两层;三类差异;T+1+准实时
1:30–2:30差错处理自动分流→自动/人工→闭环留痕
2:30–3:30调账合规调账也是资金操作,必须可追溯
3:30–4:30防复发归因分析→修根因→补监控
4:30–5:00收尾“一句话:对账找差异,差错处理闭环,归因防复发”

【关键数字】

参数经验值说明
对账层次总账先跑,明细后跑分层降本
差异类型长款/短款/金额不一致处理逻辑不同
日终对账窗口凌晨低峰,数小时内完成亿级流水需并行
准实时对账分钟级重要业务
自动调账阈值≤1000 元自动规则;1000 元~5 万规则+抽检;>5 万人工双人与第 218 题「超 5 万双人」同一阶梯
人工复核超阈值双人调账留痕
闭环超时告警24–72h 未闭环升级处理
不平率监控日告警阈值(如 >0.01%)核心指标

【追问链】(三层)

L1|“对账不平能不能自动调账?” → 分情况:有明确规则的小额差异可自动(如重复记账自动冲正);金额大、类型不明的必须人工双人复核。且调账本身要留痕可审计——调账也是资金操作。

L2|“实时对账和日终对账怎么配合?” → 实时对账做快速发现与止损(分钟级,重要业务);日终对账做全面核对与最终确认(T+1,全量)。两者互补:实时抓住问题快速处理,日终兜住漏网的。

L3|“差异归因怎么防复发?” → 分析差异根因:幂等漏洞→修复幂等;超时未回执→优化超时与查询;人工操作失误→加校验。修根因后补监控规则,同类问题再发生时主动告警而不是等对账发现。对账是发现手段,归因修复才是根治。

【评分标准】

档位答案特征
60 分知道要比对两边数据找差异
80 分总账+明细两层;三类差异;自动分流+人工闭环
95 分论证“对账是最终防线”的金融约束;调账本身留痕;归因防复发;准实时+日终配合;超时未闭环告警

【关联题】

  • 互联网版原型: 第 132/133 题(支付/对账)——本题是金融口径深化
  • 分布式事务: 第 218 题——对账是跨机构事务的最终兜底
  • 幂等: 第 213 题——幂等失效会导致对账差异
  • 审计: 第 220 题——差错处理留痕的合规要求

【自测】

  1. 为什么对账要分总账和明细两层? 参考答案:总账(总额+总笔数)秒级快速筛查;不平再跑明细逐笔定位。分层降本,亿级流水全量比对代价高。
  2. 三类差异分别怎么处理? 参考答案:长款(我有他无)查我方是否重复;短款(他有我无)查我方是否漏记;金额不一致查哪边对、是否部分成功。
  3. 为什么调账本身也要留痕? 参考答案:调账是资金操作,与交易同等重要。谁调的、依据什么、审批记录都要可追溯,否则调账可能成为掩盖问题的通道。

220. 监管要求数据可追溯(审计留痕与等保合规) ​

【考察内容】审计日志设计 + 等保 2.0 / 个保法合规

【题目】监管检查要求:任何一笔数据变更都能追溯到“谁、什么时候、改了什么、为什么改”。请设计审计留痕方案,并说明等保 2.0 和个保法对系统有哪些硬性要求。

【参考答案】

  1. 审计留痕设计:

    • 记录要素:操作人(账号 + 角色 + IP + 设备)、时间(精确到毫秒)、操作类型、对象(表 / 记录 ID)、变更前后值(diff)、事由(工单号 / 审批单号)、结果(成功 / 失败);
    • 覆盖范围:所有敏感数据的增删改查,尤其是“查询”——金融行业“谁看了客户信息”同样要留痕;
    • 实现方式:应用层 AOP / 拦截器统一埋点(避免业务代码各写各的);数据库层 binlog 解析作为独立第二来源,与应用层日志交叉校验(防止应用层日志被篡改或漏记)——但 binlog 只记数据变更、不记 SELECT:本块【原理溯源】自己认定最大风险之一是「内部人员批量查询客户信息后倒卖」,这类只读行为在 binlog 里完全无痕迹,等于查询留痕只有应用层一个来源,DBA 直连与运维通道更是空白。必须再补一条独立来源:数据库全 SQL 审计(MySQL audit log / Percona audit / 代理层记录 SQL+来源账号+客户端 IP)+禁止绕过访问网关直连库,才真的做到「查询也可追溯」;日志写入独立的审计库,与业务库物理隔离;
    • 不可篡改:日志只追加不修改、独立权限,必要时做哈希链 / 区块链存证;
    • 留存期限:金融行业通常 ≥ 5 年(按监管要求,部分业务更长);
  2. 等保 2.0 相关要求:身份鉴别(双因子)、访问控制(最小权限)、安全审计(上面这套)、入侵防范、数据完整性与保密性(加密 + 校验)、个人信息保护;

  3. 个保法相关要求:告知同意、最小必要、目的限定、可删除(被遗忘权)、跨境传输限制、个人信息处理记录;

  4. 落地要点:日志本身也要脱敏(不能把明文身份证写进审计日志)、审计日志的查阅本身也要留痕、定期做合规自查与演练。

  5. 容量估算: 审计日志量:关键操作全量,查询类可采样+风险触发全量。存储:日增×保留年限(等保/金融常见数年),冷热分层。防篡改:只追加存储、哈希链、异地备份。审计查询接口性能要与生产库隔离,避免审计拖垮业务。

  6. 失败与降级: 审计写入失败:金融场景通常 fail-closed 或本地队列缓冲(有丢失风险需告警);不可静默丢。审计中心故障时业务可降级先本地落盘后补传,补传成功与否要监控。

【原理溯源】

  • 为什么审计日志必须独立存储? 如果审计日志和业务库在同一个库、用同一套权限,攻击者(或内部人员)拿到业务库权限后可以直接改日志抹掉痕迹——审计就失去了“不可否认”的价值。独立存储 + 独立权限是审计可信的前提。
  • 为什么要“双来源交叉校验”? 应用层日志由业务代码写入,可能因代码 bug 漏记、或因被入侵而篡改。数据库 binlog 是 DB 引擎层的客观记录,不受应用代码影响。两者比对不一致即说明有问题——这是“用独立证据互相验证”的思路。
  • 为什么“查询”也必须留痕? 多数人只想到增删改。但金融行业最大的风险之一是内部人员批量查询客户信息后倒卖。只记录“谁改了”而不记录“谁看了”,就抓不到这类行为。
  • 为什么日志要“只追加不修改”? 审计日志的价值在于不可否认性。一旦允许修改,“谁改了什么”就无法作为证据。所以采用 append-only + 哈希链(每条日志含上一条的哈希),任何篡改都会导致链断裂。

【选型判断树】

审计留痕方案设计,按风险等级决策:

1. 先给数据分级
   ├─ L3 敏感(手机号 / 身份证 / 卡号)→ 全量记录增删改查
   ├─ L4 核心(密码 / 密钥)→ 全量记录 + 禁止明文落日志
   └─ L1 / L2 → 记录关键变更即可
2. 按合规强度选实现
   ├─ 一般要求 → 应用层 AOP 统一埋点 + 独立审计库
   ├─ 强合规(金融)→ 上述 + DB binlog 双来源 + 哈希链防篡改(**binlog 不记 SELECT,查询留痕要再加全 SQL 审计/访问网关+禁直连**)
   └─ 极高要求 → 上述 + 定期存证(第三方 / 区块链)
3. 明文查询授权
   ├─ 默认不可查明文(脱敏展示)
   └─ 需要明文 → 二次授权 + 事由填写 + 限时 + 全程留痕

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“审计留痕要回答四个问题:记什么、记在哪、怎么防篡改、谁能看”
0:30–2:00记什么七个要素(人 / 时间 / 类型 / 对象 / 前后值 / 事由 / 结果)+ 覆盖查询操作
2:00–3:30记在哪 + 防篡改独立审计库、binlog 双来源(只覆盖写,查询要另配全 SQL 审计)、append-only + 哈希链
3:30–4:30合规要求等保 2.0 六项 + 个保法六项
4:30–5:00收尾“一句话:审计的本质是让‘谁对数据做了什么’不可否认”

【关键数字】

参数经验值说明
留存期限金融行业 ≥ 5 年网络安全法要求网络日志 ≥ 6 个月
时间精度毫秒级用于还原操作顺序
等保 2.0 分级1–5 级金融核心系统通常三级及以上
个保法处罚上限5000 万元以下或上一年度营业额 5%以下两档择一由监管裁量,不是"固定取高者"
双因子要求等保三级要求两种以上鉴别方式组合口令 + 短信 / UKey / 生物识别
日志脱敏禁止明文写入身份证 / 手机号 / 卡号审计日志本身也要脱敏

【追问链】(三层)

L1|“审计日志会不会泄露隐私?” → 会,所以审计日志本身必须脱敏——敏感字段只记哈希或掩码。而且“查阅审计日志”这个动作本身也要授权 + 留痕,否则审计系统会变成新的泄露渠道。

L2|“应用层日志被改了怎么办?” → 这正是要引入数据库 binlog 作为独立第二来源的原因。binlog 由 DB 引擎产生,应用代码改不了;两者比对不一致即告警。再加 append-only + 哈希链,篡改会导致链断裂,可被发现。

L3|“等保三级和个保法对系统分别有什么硬性要求?” → 等保三级:身份鉴别(双因子)、访问控制(最小权限)、安全审计、入侵防范、数据完整性与保密性(加密 + 校验)、个人信息保护。个保法:告知同意、最小必要、目的限定、可删除(被遗忘权)、跨境传输限制、处理活动记录。落地时要做合规自查与演练。

【评分标准】

档位答案特征
60 分能说出要记录操作人、时间、内容,写日志
80 分能给出完整记录要素(尤其变更前后值与事由),提到独立审计库
95 分主动提“查询也要留痕”,并说清 binlog 不记 SELECT,查询留痕要靠全 SQL 审计/统一访问网关+禁直连;再讲 binlog 双来源交叉校验、append-only + 哈希链防篡改;能列出等保 2.0 与个保法的具体条目;指出审计日志本身要脱敏、查阅审计日志也要留痕

【关联题】

  • 同一知识簇(安全与合规): 第 193 题(敏感数据加密)、第 194 题(HTTPS/TLS)、第 195 题(JWT 安全)、第 196 题(日志合规)、第 197 题(越权漏洞)
  • 上游: 第 214 题(数据脱敏与受控解密)——审计与脱敏是同一套数据分级的下游落地
  • 金融版延伸: 第 219 题(对账与差错处理的留痕)、第 222 题(容灾与演练)

【自测】

  1. 为什么审计日志不能和业务库放在一起? 参考答案: 同库同权限意味着拿到业务权限就能改日志抹痕,审计失去“不可否认”的价值。必须独立存储 + 独立权限。
  2. 判断:只记录数据的“增删改”就够了,查询不需要记录。 参考答案: 错。内部人员批量查询客户信息后倒卖是金融业高发风险,只记改不记查就抓不到。查询必须留痕。
  3. 什么是 append-only + 哈希链?它解决什么问题? 参考答案: 日志只追加不修改,每条日志包含上一条的哈希形成链。任何一条被篡改都会导致后续哈希不匹配、链断裂即可发现——解决“日志被篡改后无法察觉”的问题。

221. 核心系统要迁到信创数据库(信创适配与迁移) ​

【考察内容】国产化替代方案 + 迁移风险控制

【题目】行里要求核心系统从 Oracle 迁移到国产数据库(信创要求),业务不能停,数据不能丢。请给出迁移方案。

【参考答案】

  1. 先做兼容性评估:语法差异(存储过程、函数、序列、分页语法、数据类型、隐式转换);性能特征差异(执行计划、索引策略、并发模型、锁机制);周边生态(驱动、连接池、ORM 框架、监控工具、备份工具);输出改造清单与工作量评估;

  2. 分阶段迁移(不能一步到位):外围先行(先把非核心系统如报表、查询、日志迁过去,积累经验、验证工具链)→ 双轨并行(核心系统双写 / 双跑,新旧库同时写,定期比对一致性)→ 灰度切流(按业务模块或用户分桶,先切读流量再切写流量)→ 回滚预案(保留旧库可回切,明确回滚触发条件与操作步骤);

  3. 数据迁移:全量 + 增量(停写窗口用增量追平);迁移后做逐表行数 + 抽样内容 + 校验和三重比对;

  4. 性能验证:用生产流量回放做压测,对比新旧库的 RT / QPS / 资源占用;针对慢 SQL 做专项优化;

  5. 上线后:双跑期监控数据一致性、性能指标、错误日志;逐步关停旧库。

  6. 容量估算(迁移): 信创迁移工作量≈对象数量(表/存储过程/视图/作业)×兼容改造系数。数据迁移窗口=数据量/迁移工具吞吐(全量+增量追平)。双跑期建议至少 1–2 个完整业务周期(含日终、月末)。性能基线:迁移后核心接口 RT 不劣化 >10%。

  7. 失败与降级: 迁移失败回退源库(必须演练过);双写期以源库为准。新库异常时按功能开关切回。SQL 兼容问题在网关/中间件层做语法改写只是临时手段。

【原理溯源】

  • 为什么信创迁移不能“一步到位”? Oracle 到国产库的差异不只是“换个连接串”:存储过程语法、隐式类型转换、执行计划、锁模型、甚至 NULL 排序规则都可能不同。一步切换的风险是“所有差异同时爆发”,故障面不可控。分阶段(外围先行→双轨→灰度→切流)把风险拆解到每一步可控范围内——用时间换确定性。
  • 为什么“外围先行”是关键第一步? 外围系统(报表、日志、查询)业务影响小、出错可快速回退,是验证工具链(迁移工具、比对工具、监控)和积累经验的安全沙盒。直接上核心系统等于拿最重要的资产当试验品——金融/国企的稳定性文化不允许。
  • 为什么必须“双写比对”而不是直接切? 双写期间新旧库同时写入,定期比对数据一致性:能发现迁移遗漏、语法兼容性问题、并发冲突等。比对一致才切流——这是用运行数据验证正确性,比人工 review 代码可靠得多。
  • 为什么数据要比对三重(行数+内容+校验和)? 行数比对最快,能发现“漏迁了整表”;抽样内容比对能发现“字段值转换错误”(如日期格式、字符集);校验和比对能发现“个别行被篡改或截断”。三重层层递进,成本递增、精度递增。
  • 为什么存储过程要尽量改写到应用层? 存储过程是数据库方言的重灾区:Oracle 的 PL/SQL 与国产库的存储过程语言差异大,改写工作量高且难测试。改写到应用层(Java/Python)后,逻辑与数据库解耦,长期更可维护、更容易做单元测试。短期改写成本高,但消除了对数据库方言的长期依赖。

【选型判断树】

信创迁移,按阶段决策:
1. 评估先行
   └─ 语法/性能/生态差异清单 + 工作量评估
2. 阶段推进
   ├─ 外围先行:报表/日志/查询先迁,验证工具链
   ├─ 双轨并行:核心系统双写,定期比对一致性
   ├─ 灰度切流:先读后写,按模块/用户分桶
   └─ 回滚预案:保留旧库,明确触发条件与步骤
3. 数据迁移
   └─ 全量+增量;行数+内容+校验和三重比对
4. 性能验证
   └─ 生产流量回放压测;慢 SQL 专项优化
5. 上线后
   └─ 双跑监控一致性/性能/错误日志;逐步关停旧库

硬约束:业务不能停、数据不能丢、必须可回滚。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“信创迁移的本质是风险控制,不是换个连接串”
0:30–1:30评估语法/性能/生态差异清单;存储过程改造策略
1:30–2:30分阶段外围先行→双轨比对→灰度切流→回滚预案
2:30–3:30数据迁移全量+增量;行数+内容+校验和三重比对
3:30–4:30性能验证生产流量回放;慢 SQL 优化
4:30–5:00收尾“一句话:外围验证工具链,双跑比对保正确,灰度切流控风险,保留回滚保底线”

【关键数字】

参数经验值说明
迁移阶段4 阶段:外围→双轨→灰度→切流不可一步到位
双写比对周期每日或每小时发现不一致及时修
数据三重比对行数 + 抽样内容 + 校验和层层递进
灰度切流先读后写;按模块/用户 5%→20%→50%→100%可回滚
回滚窗口切流后至少 1–2 周保留旧库明确触发条件
停写窗口尽量短(分钟级);增量追平业务不能停
压测方式生产流量回放比合成压测更真实

【追问链】(三层)

L1|“迁移后性能下降怎么办?” → 先定位是 SQL 写法问题还是数据库特性问题(执行计划不同、索引策略不同)。做 SQL 改写、索引重建、参数调优;必要时对特定场景做架构调整(热点表拆表)。压测阶段就应发现,不要等上线。

L2|“双写期间数据不一致怎么办?” → 以旧库为准,新库异步修正;定时比对+差异自动修复;切流前必须比对一致。不一致率超过阈值则暂停推进,先修根因。

L3|“存储过程怎么办?” → 尽量改写到应用层,减少对数据库方言的依赖,长期看反而更可维护。短期改写成本高,但消除了对方言的长期绑定。无法改写的(复杂批处理)做兼容层或用国产库的兼容模式过渡。

【评分标准】

档位答案特征
60 分知道用迁移工具导数据
80 分先做兼容性评估;分阶段+双轨+灰度+可回滚;数据三重比对
95 分论证“外围先行”的风险控制逻辑;存储过程改写到应用层的长期收益;生产流量回放压测;回滚触发条件明确;双跑期监控一致性

【关联题】

  • 容灾: 第 222 题(同城双活)——迁移期间的业务连续性保障
  • 应急: 第 225 题(生产库 CPU 100%)——迁移出问题时的应急
  • 数据分片: 第 215 题——迁移后可能的分片改造
  • 情景题: 第 228 题(遗留系统)——渐进式改造的方法论

【自测】

  1. 为什么信创迁移要“外围先行”? 参考答案:外围系统业务影响小、出错可回退,是验证工具链和积累经验的安全沙盒。直接上核心系统风险不可控。
  2. 双写比对发现不一致怎么办? 参考答案:以旧库为准,新库异步修正;定时比对+差异自动修复;切流前必须比对一致。不一致率超阈值暂停推进。
  3. 为什么存储过程要改写到应用层? 参考答案:存储过程是数据库方言重灾区,改写到应用层后逻辑与数据库解耦,长期更可维护、可测试,消除对方言的长期依赖。

222. 同城机房故障业务不能中断(同城双活与两地三中心) ​

【考察内容】容灾架构设计 + RTO / RPO 指标

【题目】行里要求核心系统达到“同城双活、两地三中心”标准,任一同城机房整体故障时业务不中断。请设计容灾架构并说明关键指标。

【参考答案】

  1. 先明确两个指标:RTO(恢复时间目标)——机房故障到业务恢复的时间,同城双活要求 RTO ≈ 0(秒级切流);RPO(恢复点目标)——允许丢失的数据量,核心账务要求 RPO = 0(不能丢数据);

  2. 架构设计:同城双活——两个同城机房同时承载流量,应用层无状态、通过 DNS / GSLB 做流量调度,数据库用强同步复制(多数派提交)保证 RPO = 0;两地三中心——同城双活(生产)+ 异地灾备中心(数据异步复制),用于应对城市级灾难,异地中心 RPO 可放宽(分钟级),RTO 数十分钟——放宽到什么程度必须先由业务/监管定口径,两种答法要分开:① 若核心账务要求任何灾难档位都 RPO=0(本块【原理溯源】正是论证「丢一笔已确认转账=资金差错」),那异地也必须同步/半同步+第三仲裁点,代价是每笔写入多一次跨城 RTT(几十 ms)且跨城抖动会直接拖累交易,通常要靠「单元化+同单元内同步」把跨城写降到可接受;② 若允许城市级 RPO 分钟级,则异步复制即可,但必须书面确认该口径已获批准,并配「切换后按对账与差错处理补齐未同步交易」的流程(客户侧表现为「已扣款未到账」的待补偿状态,要有客服与监管报备口径)。答题先给口径归属(业务方/监管),再给架构;单元化 / 多活——把流量按用户维度切分成多个单元,单元内闭环,单元间不互相依赖,避免故障扩散;

  3. 关键技术点:流量调度(DNS / GSLB 健康检查 + 秒级切流,客户端多 IP 兜底);数据同步(强同步 + 异步分级);配置与发布(多机房配置一致性与灰度发布);依赖治理(避免跨机房同步调用,会放大延迟和故障面);

  4. 演练:定期做真实切流演练(不是纸上推演),验证 RTO / RPO 是否达标,暴露问题并整改。

  5. 容量估算: 两地三中心:同城双活常态各承担约 50% 流量(两侧相加不超过 100%),容量按任一侧可独扛 100% 预留。RPO/RTO 目标金融核心常 RPO≈0(同步复制)、同城秒级切流、异地灾备 RTO 数十分钟(分钟级异地要额外具备流量预热与自动切换能力,不是标配),两个指标不要混写。数据同步链路带宽≥峰值写入×冗余。演练频率按本题【关键数字】表「每季度至少 1 次」执行,年度另做一次全链路切换演练并留实测 RTO。

  6. 失败与降级: 机房级故障:自动/半自动切流;应用无状态+数据层同步是前提。切流期间限流防幸存机房被打爆。跨机房分布式事务要降级为单机房主,避免脑裂。

【原理溯源】

  • 为什么核心账务要求 RPO=0? RPO>0 意味着允许丢失数据。对账务,丢失一笔已确认的转账=客户钱扣了但对方没收到,这是资金差错。所以核心账务必须强同步复制:多数派节点写入成功才返回客户端,任一机房故障时已确认的数据不丢。代价是写入延迟增加约一次同城 RTT(<2ms),可接受。
  • 为什么同城双活 RTO≈0 而异地灾备 RTO 可到数十分钟? 同城两机房网络延迟低(<2ms)、带宽充足,流量可秒级切换;异地跨城市延迟高(几十 ms)、带宽有限,且异地中心通常不承载日常流量(灾备模式),启动+切流需要更长时间。RTO 的设计要匹配物理约束,不能拍脑袋。
  • 为什么异地不做双活? 跨城延迟(几十 ms)会让每次写入都多一次跨城 RTT,核心账务的写入延迟从 <5ms 涨到 50ms+,客户可感知。且跨城网络不稳定时会频繁触发 CP 行为(拒绝服务)。所以异地做灾备(异步复制+定期验证可切换),不做双活——用异地的 RTO 换同城的性能。
  • 为什么“单元化”能避免故障扩散? 传统架构中一个机房故障,所有依赖该机房的服务都受影响。单元化把用户按维度切分到多个单元,单元内闭环(应用+数据+依赖都在单元内),单元间不互相依赖。一个单元故障只影响该单元的用户,不扩散——故障半径=单元大小。
  • 为什么必须做“真实切流演练”? 纸面设计的 RTO/RPO 是假设值,真实切流才能发现:DNS 切换是否真的秒级生效、健康检查是否有脑裂、数据同步是否有延迟、客户端是否能正确重试。国企/金融面试官特别看重“做过真实演练”——这是落地能力的证明。

【选型判断树】

容灾架构选型,按指标要求:
1. 核心账务(RPO=0,RTO≈0)
   → 同城双活 + 强同步复制(多数派提交)
   → DNS/GSLB 秒级切流 + 客户端多 IP 兜底
2. 非核心业务(RPO 分钟级,RTO 分钟级)
   → 同城双活 + 异步复制
   → 或单机房 + 快速恢复
3. 城市级灾难
   → 两地三中心:同城双活 + 异地灾备
   → 异地异步复制,RPO 分钟级,RTO 数十分钟(**该放宽必须先由业务/监管确认口径**;若核心账务要求任何灾难档位 RPO=0,异地也要同步/半同步+第三仲裁点,代价是跨城 RTT 与可用性)
4. 避免故障扩散
   → 单元化:用户维度切分,单元内闭环
5. 演练
   └─ 定期真实切流,验证 RTO/RPO 达标

硬约束:核心账务 RPO=0;切流必须秒级;演练必须真实。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“容灾的核心指标是 RTO 和 RPO,设计要匹配业务要求”
0:30–1:30指标定义RTO=恢复时间,RPO=数据丢失量;核心账务 RPO=0、RTO≈0
1:30–2:30同城双活两机房同时承载;强同步复制保 RPO=0;DNS/GSLB 秒级切流
2:30–3:30两地三中心同城双活+异地灾备;异地 RPO 分钟级、RTO 数十分钟
3:30–4:30单元化用户维度切分;单元内闭环;故障半径=单元大小
4:30–5:00收尾“一句话:同城双活保 RPO=0,异地灾备防城市级灾难,演练验证达标”

【关键数字】

参数经验值说明
核心账务 RPO0强同步复制
核心账务 RTO≈0(秒级切流)检测+切换 <60s
同城机房延迟<2ms强同步可接受
异地灾备 RPO分钟级(前提:业务/监管已确认城市级可放宽)异步复制;未确认前核心账务仍按 RPO=0 设计
异地灾备 RTO数十分钟灾备模式启动+切流
切流方式DNS/GSLB 健康检查客户端多 IP 兜底
演练频率每季度至少 1 次真实切流不是纸上推演
单元化粒度按用户维度故障不扩散

【追问链】(三层)

L1|“同城双活怎么保证 RPO=0?” → 数据库强同步复制:多数派节点写入成功才返回客户端。任一机房故障时,已确认的写入至少在一个存活节点上有副本。代价是写入延迟增加约一次同城 RTT(<2ms),可接受。

L2|“异地灾备要不要也双活?” → 通常不做。跨城延迟高(几十 ms),双活会拖慢写入;跨城网络不稳定时频繁触发 CP 行为。异地做灾备(异步复制+定期验证可切换),用异地的 RTO 换同城的性能。

L3|“切流演练会不会影响生产?” → 在业务低峰做,小流量灰度验证,准备好回切。演练本身就是容灾能力的一部分——不演练的容灾是纸上谈兵。国企面试官很看重“做过真实演练”。

【评分标准】

档位答案特征
60 分知道做备份、搭从库
80 分准确说出 RTO/RPO;同城双活 vs 两地三中心的区别;强同步保 RPO=0
95 分给出核心账务的具体目标值(RPO=0、RTO≈0);单元化避免故障扩散;强调真实切流演练;异地不做双活的理由;客户端多 IP 兜底

【关联题】

  • 高可用登录: 第 209 题——同城双活的具体应用场景
  • 读写分离: 第 216 题——强同步复制的另一个应用
  • 降级: 第 217 题——机房故障时的降级预案
  • 应急: 第 225 题——容灾演练发现问题后的整改

【自测】

  1. RTO 和 RPO 分别是什么?核心账务的目标值是多少? 参考答案:RTO=恢复时间目标,RPO=数据丢失量目标。核心账务:RPO=0(不能丢数据)、RTO≈0(秒级切流)。
  2. 为什么异地不做双活? 参考答案:跨城延迟高会拖慢写入;网络不稳定时频繁触发 CP 行为。异地做灾备,用 RTO 换同城性能。
  3. 为什么必须做真实切流演练? 参考答案:纸面 RTO/RPO 是假设值;真实切流才能发现 DNS 生效延迟、健康检查脑裂、数据同步延迟等问题。不演练的容灾是纸上谈兵。

223. 现场分析一段 GC 日志(日志分析实战) ​

【考察内容】JVM 日志解读与问题定位

【题目】给你一段线上 GC 日志(或:某城商行面试要求现场分析 GC 日志),请说出你从日志里能看出什么问题,以及下一步怎么排查。

【参考答案】

  1. 看日志先抓四个信息:GC 类型(Young GC / Full GC,用的哪种收集器);频率(单位时间 GC 次数,如 Full GC 每 2 分钟一次即异常;本库统一危险线为“≥每 5 分钟 1 次”);耗时(单次 STW 时长,如 Young GC 50ms 正常,Full GC 1s+ 会明显影响 RT);回收效果(GC 前后堆占用,如 Full GC 后老年代只降了 5% → 大概率内存泄漏);

  2. 典型异常模式与判断:Full GC 频繁 + 回收效果差 → 内存泄漏或老年代对象增长过快;Young GC 频繁且耗时短 → 新生代太小或对象分配速率过高;单次 GC 耗时突增 → 大对象 / 大数组、或堆太大导致标记耗时长;promotion failed / concurrent mode failure → 晋升失败 / CMS 并发失败,需调 Survivor 比例或换收集器;

  3. 下一步排查:加 -XX:+HeapDumpOnOutOfMemoryError 或手动 jmap -dump 拿堆快照,用 MAT / JProfiler 分析支配树找大对象;jstat -gcutil <pid> 1000 持续观察;结合业务日志定位是哪个功能在大量创建对象;

  4. 处置:先止血(扩容 / 重启 / 限流),再根治(修代码里的内存泄漏、调 JVM 参数、必要时换 G1 / ZGC)。

  5. 容量估算(日志分析实战): 看懂关键字段:[Times: user, sys, real]、GC 原因(Allocation Failure / Metadata GC / System.gc())、堆前后大小。经验:user+sys ≫ real 才说明多线程(并行/并发)GC 在起作用(user/sys 是所有 GC 线程 CPU 时间的累加,Parallel/G1 典型 user ≈ 2~4×real);若 real ≈ user+sys,说明这次回收实际是单线程/串行跑的(线程数=1、退化或 STW 串行阶段),要检查 -XX:ParallelGCThreads 与容器可见 CPU 数。日志量按 GC 频率保留至少 7 天。健康线:Young GC <50ms(50–100ms 属需关注)、Full GC 少且可控。

  6. 失败与降级: 日志分析同时业务不能停:先限流/扩容争取时间。若分析指向泄漏且无法快修:摘非核心、扩堆、安排发布窗口。把 GC 日志接入持续观测,避免下次又是人肉看。

【原理溯源】

  • 为什么看 GC 日志要抓“类型、频率、耗时、回收效果”四个维度? 只看一个维度会误判:只看频率高可能是正常的高并发;只看耗时长可能是堆配得太大。四个维度组合才能区分:是参数问题(可通过调参解决)还是代码问题(必须改代码)。这是从现象到根因的分析框架。
  • 为什么 Full GC 后老年代只降了 5% 说明内存泄漏? Full GC 会回收所有不可达对象。若回收后老年代几乎没降,说明绝大部分对象都是可达的——被某个长生命周期对象(静态集合、缓存、ThreadLocal)持有引用,无法释放。这是内存泄漏的典型特征。正常情况下 Full GC 后老年代应显著下降。
  • 为什么换 G1/ZGC 解决不了内存泄漏? 新收集器改善的是 STW 时长(更短的停顿),不解决“对象无法释放”的根本问题。内存泄漏是代码 bug(引用未清理),必须改代码。换收集器只能缓解症状(STW 更短,客户感知更小),不能根治。
  • 为什么生产环境拿堆快照要谨慎? jmap -dump 会触发 Full GC 并 STW,大堆(几十 GB)可能停顿数秒到十几秒。金融系统在业务高峰期 STW 数秒=大量请求超时。所以要在低峰做,或用 -XX:+HeapDumpOnOutOfMemoryError 让它在 OOM 时自动 dump(虽然 OOM 了业务已受损,但至少有现场)。
  • 为什么国企/银行面试爱考 GC 日志分析? 这是现场实战能力的直接考察:给你一段真实日志,看你能不能读出问题、给出排查方向。比“背 GC 参数”更能证明你真正处理过线上问题。某城商行明确要求现场分析 GC 日志——这是国企面试的特色题型。

【选型判断树】

GC 日志分析,按四维度决策:
1. 看类型
   ├─ Young GC 频繁 → 新生代小或对象分配速率高
   └─ Full GC 频繁 → 老年代满或内存泄漏
2. 看频率
   ├─ Young GC 每秒多次 → 调大新生代
   └─ Full GC ≥ 每 5 分钟 1 次 → 异常,需排查(题干“每 2 分钟一次”属严重异常)
3. 看耗时
   ├─ Young GC <50ms → 正常
   ├─ Full GC >1s → 影响 RT,需优化
   └─ 突增 → 大对象/堆太大
4. 看回收效果
   ├─ Full GC 后老年代显著下降 → 正常
   └─ Full GC 后老年代只降 5% → 内存泄漏
5. 下一步
   ├─ 堆快照 + MAT 支配树找大对象
   ├─ jstat 持续观察
   └─ 结合业务日志定位功能
6. 处置
   ├─ 先止血:扩容/重启/限流
   └─ 再根治:修泄漏/调参/换收集器

口诀:类型频率耗时效果,四维组合定根因;先止血再根治。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“GC 日志分析抓四个维度:类型、频率、耗时、回收效果”
0:30–1:30四维度各维度看什么、什么算异常
1:30–2:30典型模式Full GC 频繁+回收差=内存泄漏;Young GC 频繁=新生代小
2:30–3:30排查动作堆快照+MAT 支配树;jstat 观察;业务日志定位
3:30–4:30处置先止血(扩容/重启/限流)再根治(修代码/调参/换收集器)
4:30–5:00收尾“一句话:四维组合定根因,先止血再根治,泄漏必须改代码”

【关键数字】

参数经验值说明
Young GC 耗时<50ms 正常50–100ms 需关注,与正文同口径
Full GC 耗时>1s 影响 RT金融场景敏感
Full GC 频率≥每 5 分钟 1 次=异常正常应很少(日均个位数)
回收效果Full GC 后老年代应显著下降只降 5%=泄漏
堆快照 STW大堆可能数秒–十几秒低峰做
jstat 观察间隔1000ms持续观察趋势
推荐收集器G1(平衡)/ ZGC(超低延迟)按业务选

【追问链】(三层)

L1|“Full GC 后内存只降了 5% 说明什么?” → 说明大部分对象都存活,典型内存泄漏特征。要拿堆快照找是谁在持有引用——通常是静态集合、缓存未清理、ThreadLocal 未 remove。

L2|“换 G1 能解决吗?” → 能缓解 STW 时长,但解决不了内存泄漏。如果是泄漏必须改代码。G1 改善的是“停多久”,不解决“对象释放不了”。

L3|“生产环境怎么安全拿堆快照?” → jmap 会 STW,大堆可能停顿数秒。建议在业务低峰做;或用 -XX:+HeapDumpOnOutOfMemoryError 让它在 OOM 时自动 dump。金融场景高峰期 STW 数秒=大量请求超时,必须谨慎。

【评分标准】

档位答案特征
60 分知道 GC 频繁是问题,要加内存
80 分能从日志读出类型/频率/耗时/回收效果;判断内存泄漏 vs 参数问题
95 分四维度组合分析框架;堆快照+MAT 支配树的标准动作;先止血再根治的顺序;换收集器解决不了泄漏的论证;生产环境拿快照的风险意识

【关联题】

  • 互联网版原型: 第 70/163/165 题(故障排查)——本题是金融现场题改造
  • 应急: 第 225 题(生产库 CPU 100%)——GC 问题可能是诱因之一
  • 高可用: 第 209 题——GC 停顿影响登录可用性
  • 容灾: 第 222 题——GC 问题在切流演练中可能暴露

【自测】

  1. GC 日志分析的四个维度是什么? 参考答案:类型(Young/Full)、频率(单位时间次数)、耗时(单次 STW)、回收效果(GC 前后堆占用变化)。
  2. Full GC 后老年代只降 5% 说明什么? 参考答案:大部分对象存活,典型内存泄漏。要拿堆快照找持有引用的对象。
  3. 换 G1/ZGC 能解决内存泄漏吗? 参考答案:不能。新收集器改善 STW 时长,不解决对象无法释放的问题。泄漏必须改代码。

224. 现场画出 Spring Bean 的生命周期(Spring 原理) ​

【考察内容】Spring IoC 容器核心原理

【题目】请画出 / 说出 Spring Bean 的完整生命周期,并说明各阶段的作用。(某国有银行面试原题:现场绘制 Spring Bean 生命周期流程图。)

【参考答案】

  1. 实例化前:BeanDefinition 加载(扫描 / 解析配置,注册 BeanDefinition)→ BeanFactoryPostProcessor(在 Bean 实例化之前修改 BeanDefinition,如 PropertySourcesPlaceholderConfigurer 处理 ${} 占位符);

  2. 实例化与初始化:

    • 实例化(createBeanInstance):反射 / 工厂方法创建对象(此时对象还没注入属性);
    • 属性填充(populateBean):依赖注入(@Autowired / @Value);
    • Aware 接口回调:BeanNameAware → BeanFactoryAware → ApplicationContextAware(按顺序注入容器相关对象);
    • BeanPostProcessor 前置(postProcessBeforeInitialization):如 @PostConstruct 就是在这里被 CommonAnnotationBeanPostProcessor 处理的;
    • 初始化:InitializingBean.afterPropertiesSet() → 自定义 init-method;
    • BeanPostProcessor 后置(postProcessAfterInitialization):AOP 代理就是在这一步生成的(AbstractAutoProxyCreator 返回代理对象);
  3. 使用与销毁:Bean 就绪,放入单例池(singletonObjects)供使用;容器关闭时 DisposableBean.destroy() → 自定义 destroy-method;

  4. 补充要点:循环依赖——Spring 通过三级缓存解决单例的字段注入循环依赖(singletonObjects 一级、earlySingletonObjects 二级、singletonFactories 三级);构造器注入的循环依赖无法解决。AOP 代理时机——在 BeanPostProcessor 后置阶段生成,所以注入到其他 Bean 里的是代理对象。

  5. 容量估算与要点: Spring Bean 生命周期作图必须包含:实例化 → 属性注入 → Aware → BeanPostProcessor#before → InitializingBean/init-method → after → 使用 → 销毁回调。循环依赖三级缓存只解决 setter 注入的单例,构造器循环仍会失败。启动慢时对应:扫描范围、条件装配、懒加载、Bean 数量。

  6. 失败与降级: 生产启动失败:保留完整启动日志与 autoconfig report;分环境差异配置用 profile 隔离。热修复困难时优先回滚版本。对启动关键 Bean 失败要有明确健康检查。

【原理溯源】

  • 为什么属性填充在 Aware 回调之前? 属性填充(populateBean)注入的是业务依赖(@Autowired 的 Service/Repository);Aware 回调注入的是容器自身的引用(BeanName、BeanFactory、ApplicationContext)。先注入业务依赖再注入容器引用,是因为业务依赖是 Bean 正常工作的前提,而容器引用主要用于高级扩展点。顺序反了会导致某些依赖在 Aware 回调时还不可用。
  • 为什么 AOP 代理在 BPP 后置阶段生成? AOP 需要在 Bean 完全初始化后(属性注入完、@PostConstruct 执行完)才能创建代理——代理对象要包装的是一个“准备好的 Bean”。若在实例化阶段就代理,属性还没注入,代理对象内部是空的。BPP 后置是最后一个能拦截 Bean 的扩展点,在这里返回代理对象,后续所有使用者拿到的都是代理。
  • 为什么需要三级缓存解决循环依赖? 一级缓存存成品(完全初始化的 Bean);二级缓存存半成品(实例化但未初始化的早期引用);三级缓存存 ObjectFactory(延迟生成早期引用的工厂)。关键是提前暴露引用:A 创建时发现依赖 B,B 创建时发现依赖 A,此时 A 还未初始化完成——从三级缓存拿到 ObjectFactory,生成 A 的早期引用(可能是 AOP 代理)注入给 B。三级而非两级的原因:ObjectFactory 保证只在需要时才生成早期引用,且能处理 AOP 代理的提前暴露。
  • 为什么构造器注入的循环依赖无法解决? 构造器注入时 Bean 还没实例化完成,无法提前暴露引用。字段注入/Setter 注入可以在实例化后(属性填充阶段)暴露早期引用,构造器注入不行。所以 Spring 官方推荐构造器注入(虽然会暴露循环依赖问题,但迫使你正视设计缺陷)。
  • 为什么国企/银行爱考 Spring Bean 生命周期? 这是 Java 后端的底层原理题,考察候选人是否真正理解框架而不只是会用注解。能按顺序说出完整生命周期、明确 AOP 代理时机、解释三级缓存——这些是区分“会用 Spring”和“懂 Spring”的关键。某国有银行原题要求现场画图,说明他们看重系统性理解。

【选型判断树】

Spring Bean 生命周期,按阶段记忆:
1. 实例化前
   ├─ BeanDefinition 加载
   └─ BeanFactoryPostProcessor(改定义,如 ${} 占位符)
2. 实例化与初始化
   ├─ 实例化(createBeanInstance):反射创建对象
   ├─ 属性填充(populateBean):@Autowired 注入
   ├─ Aware 回调:BeanName→BeanFactory→ApplicationContext
   ├─ BPP 前置:@PostConstruct 在这里处理
   ├─ 初始化:afterPropertiesSet() → init-method
   └─ BPP 后置:AOP 代理在这一步生成 ★
3. 使用
   └─ 放入单例池(singletonObjects)
4. 销毁
   └─ DisposableBean.destroy() → destroy-method
5. 循环依赖
   ├─ 三级缓解决字段注入循环依赖
   └─ 构造器注入无法解决

口诀:定义→实例化→填充→Aware→BPP前→初始化→BPP后(AOP)→使用→销毁。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“Bean 生命周期是 IoC 容器的核心,分实例化前、实例化初始化、使用销毁三段”
0:30–2:00主线按顺序:定义加载→实例化→属性填充→Aware→BPP前→初始化→BPP后→使用→销毁
2:00–3:00重点AOP 代理在 BPP 后置生成(最常被追问);@PostConstruct 在 BPP 前置处理
3:00–4:00循环依赖三级缓存;提前暴露引用;构造器注入无法解决
4:00–5:00收尾“一句话:主线是实例化→填充→初始化,AOP 在 BPP 后置,循环依赖靠三级缓存”

【关键数字】

参数经验值说明
生命周期阶段数本题正文清单列 10 步(口述骨架主线压成 9 项:定义加载→实例化→属性填充→Aware→BPP前→初始化→BPP后→使用→销毁)定义→…→销毁;阶段数随拆分粒度 8~10,答题按自己列的清单说清
三级缓存singletonObjects / earlySingletonObjects / singletonFactories解决循环依赖
Aware 顺序BeanName→BeanFactory→ApplicationContext按依赖程度递增
AOP 代理时机BPP postProcessAfterInitialization最后拦截点
循环依赖限制构造器注入、prototype 无法解决字段/Setter 可以
BeanFactoryPostProcessor在实例化之前改 BeanDefinition
BeanPostProcessor初始化前后各一次(postProcessBefore/AfterInitialization)扩展点;实例化≠初始化

【追问链】(三层)

L1|“AOP 代理什么时候生成?” → BeanPostProcessor 的 postProcessAfterInitialization 阶段,由 AbstractAutoProxyCreator 完成。所以注入到其他 Bean 里的是代理对象,不是原始对象。

L2|“循环依赖怎么解决?为什么需要三级缓存?” → 三级缓存:一级存成品、二级存半成品、三级存 ObjectFactory。关键是提前暴露引用(ObjectFactory)。需要三级是因为 ObjectFactory 保证只在需要时才生成早期引用,并能处理 AOP 代理的提前暴露——两级无法兼顾代理对象。

L3|“构造器注入的循环依赖为什么解决不了?” → 构造器注入时 Bean 还没实例化完成,无法提前暴露引用。字段注入/Setter 注入可以在实例化后暴露早期引用。所以 Spring 官方推荐构造器注入——虽然会暴露循环依赖问题,但迫使你正视设计缺陷。

【评分标准】

档位答案特征
60 分能说出实例化、初始化、销毁
80 分按顺序说清完整主线;明确 AOP 在 BPP 后置;知道三级缓存
95 分能解释属性填充与 Aware 的顺序原因;论证三级缓存为何优于两级;构造器注入无法解决循环依赖的原因;@PostConstruct 处理时机

【关联题】

  • Java 基础: 第 185–200 题(微服务·安全·工程化)中的 Java 原理类
  • 金融场景: 第 209 题(高可用登录)——Spring 应用的生命周期管理
  • 应急: 第 225 题——Bean 初始化失败可能导致启动异常
  • 信创迁移: 第 221 题——框架层兼容性问题

【自测】

  1. Spring Bean 生命周期的主线是什么? 参考答案:BeanDefinition 加载→实例化→属性填充→Aware 回调→BPP 前置→初始化→BPP 后置→使用→销毁。
  2. AOP 代理在哪个阶段生成?为什么? 参考答案:BPP 后置(postProcessAfterInitialization)。因为需要在 Bean 完全初始化后才能创建代理,这里返回代理对象,后续使用者拿到的都是代理。
  3. 为什么构造器注入的循环依赖无法解决? 参考答案:构造器注入时 Bean 还没实例化完成,无法提前暴露引用。字段/Setter 注入可以在实例化后暴露早期引用。

225. 生产库 CPU 100%,客户无法转账(金融应急) ​

【考察内容】线上应急流程 + 数据库层排查

【题目】下午 3 点(业务高峰),监控告警核心数据库 CPU 持续 100%,转账接口大面积超时,客户无法转账。作为值班工程师,你怎么处理?

【参考答案】

  1. 先止损,后定位(金融场景第一原则:业务优先):立即拉应急群,同步业务 / 客服 / 运维,启动应急预案;若确认为异常 SQL 或异常流量,先 kill 掉问题 SQL / 限流问题来源(如封禁异常 IP / 关闭异常功能开关),先恢复业务;若有备用链路(只读库、备用机房),按预案切流;

  2. 定位(与止损并行):top -Hp <pid> 找到高 CPU 的线程 → printf "%x\n" <tid> 转十六进制 → jstack <pid> | grep <hex> 定位到具体代码;数据库侧 SHOW PROCESSLIST 看当前慢查询与会话,SHOW ENGINE INNODB STATUS 看锁等待;慢查询日志 / APM 链路追踪定位是哪条 SQL、哪个上游服务;检查是否有全表扫描、缺索引、大事务、锁冲突、突发流量、定时任务撞车;

  3. 常见根因与处置:慢 SQL / 缺索引 → 加索引(注意在线 DDL 的锁影响)或改写 SQL;大事务 / 批量任务撞上业务高峰 → 暂停任务,改到低峰执行;突发流量 / 爬虫 / 攻击 → 限流 + 封禁;锁冲突 / 死锁 → 找到持锁会话,必要时 kill 并回滚;连接池打满 → 扩容连接池 + 排查连接泄漏;

  4. 收尾:确认业务恢复 → 数据一致性校验(有没有少记 / 重复记账)→ 复盘 → 补监控与预案。

  5. 容量估算(应急): 生产库 CPU 100%:先看是 SQL、锁等待、连接打满还是备份/DDL。金融应急时限:对外公告时限、系统切换时限要有制度数字。限流将 DB QPS 压回安全水位(如峰值 60%)。杀会话权限与双人复核。

  6. 失败与降级: 立即保护核心转账:非核心查询/报表停掉;从库/只读接口降级;必要时切备库(数据新鲜度确认)。客户侧排队提示优于失败报错。全过程操作留痕,事后给监管可读报告。

【原理溯源】

  • 为什么金融应急是“先止损,后定位”? 业务高峰期每分钟都有大量转账在排队,CPU 100% 意味着客户无法转账——这是资金业务的直接损失。定位根因可能要半小时,客户等不起。先 kill 问题 SQL / 限流 / 切流,把业务恢复到可用状态,再慢慢定位根因。这是金融场景“业务优先”原则的直接体现。
  • 为什么要“止损与定位并行”? 一个人止损、另一个人定位——应急群里要分工。只止损不定位:恢复后问题可能复发;只定位不止损:客户持续受损。并行处理:止损争取时间,定位防止复发。
  • 为什么 kill SQL 前要确认影响面? kill 会回滚该事务。若事务已部分成功(如扣了款但未记账),kill 后回滚可能导致数据不一致。所以要先看事务状态:资金类事务优先让它跑完或走补偿,不能盲目 kill。金融场景的每一次操作都要考虑资金安全。
  • 为什么收尾要“数据一致性校验”? 应急过程中可能有事务被 kill、有请求超时重试、有降级返回——这些都可能造成资金差错。业务恢复后必须校验:有没有少记账、重复记账、金额错误。这是金融应急与互联网应急的关键差异——互联网关心服务恢复,金融还要关心账务正确。
  • 为什么国企/银行面试爱考应急题? 考察的是现场处理能力与流程意识:能不能在高压下有序处理、先止损后定位、同步业务方、收尾做校验。这些不是背技术能背出来的,是实战经验的体现。金融行业对“出事后怎么处理”比“怎么避免出事”更关注——因为故障不可避免,应对能力才是关键。

【选型判断树】

生产库 CPU 100% 应急,按步骤:
1. 立即止损(业务优先)
   ├─ 拉应急群,同步业务/客服/运维
   ├─ 确认异常 SQL/流量 → kill / 限流 / 封禁
   └─ 有备用链路 → 按预案切流
2. 并行定位
   ├─ 应用侧:top -Hp → jstack 定位线程
   ├─ 数据库侧:SHOW PROCESSLIST / INNODB STATUS
   └─ APM/慢日志:定位 SQL 和上游服务
3. 常见根因处置
   ├─ 慢 SQL → kill + 后续加索引/改写
   ├─ 大事务/定时任务 → 暂停,改低峰
   ├─ 突发流量/攻击 → 限流 + 封禁
   ├─ 锁冲突/死锁 → kill 持锁会话
   └─ 连接池满 → 扩容 + 排查泄漏
4. 收尾
   ├─ 确认业务恢复
   ├─ 数据一致性校验(资金差错检查)★
   └─ 复盘 + 补监控与预案

口诀:先止损再定位,止损定位要并行;恢复后必须校验账务。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“金融应急第一原则:先止损后定位,业务优先”
0:30–1:30止损动作拉应急群;kill 问题 SQL / 限流;备用链路切流
1:30–2:30定位动作top -Hp + jstack;SHOW PROCESSLIST;APM 链路
2:30–3:30根因处置慢 SQL/大事务/突发流量/锁冲突/连接池,分类处理
3:30–4:30收尾数据一致性校验(金融特有);复盘补监控
4:30–5:00收尾“一句话:先止损再定位,恢复后必须校验账务正确性”

【关键数字】

参数经验值说明
止损目标分钟级恢复业务客户等不起
定位手段top -Hp + jstack应用侧线程定位
数据库排查SHOW PROCESSLIST / INNODB STATUS慢查询/锁等待
kill 影响事务回滚资金类事务要谨慎
数据校验恢复后必做少记/重复记/金额错误
复盘时限24–48h 内补监控与预案
定时任务避开业务高峰撞车是常见根因

【追问链】(三层)

L1|“kill SQL 会不会影响正在执行的事务?” → 会,kill 会回滚该事务。需先确认影响面(涉及多少资金、是否已部分成功);资金类事务优先让它跑完或走补偿,不能盲目 kill。

L2|“加索引会不会锁表?” → MySQL 5.6 起(5.7/8.0 沿用)的 Online DDL 让 ADD INDEX 走 INPLACE:不复制整表、期间允许并发 DML,但不是"完全不锁表"——开始与结束仍要拿 MDL(元数据锁),长事务未提交会把后面的 DML 堵死;同时仍消耗 IO 与 undo。高峰期谨慎,优先用限流止血;加索引放到低峰或维护窗口。

L3|“为什么收尾要做数据一致性校验?” → 应急过程中可能有事务被 kill、请求超时重试、降级返回——都可能造成资金差错。业务恢复后必须校验有没有少记账、重复记账、金额错误。这是金融应急与互联网应急的关键差异。

【评分标准】

档位答案特征
60 分知道重启、加索引
80 分先止损后定位的顺序;top -Hp + jstack 完整链路;常见根因清单
95 分止损与定位并行的分工意识;kill 前确认影响面(资金安全);收尾数据一致性校验(金融特有);定时任务避开高峰;复盘补监控

【关联题】

  • 互联网版原型: 第 163/165/70 题(故障排查)——本题是金融口径改造
  • GC 日志: 第 223 题——CPU 高可能是 GC 导致
  • 情景题: 第 226 题(无法转账)——技术应急的沟通面
  • 对账: 第 219 题——应急后数据校验的兜底

【自测】

  1. 金融应急的第一原则是什么? 参考答案:先止损后定位,业务优先。先恢复业务(kill SQL/限流/切流),再定位根因。
  2. 为什么 kill SQL 前要确认影响面? 参考答案:kill 会回滚事务。资金类事务可能已部分成功,盲目 kill 可能造成数据不一致。
  3. 为什么收尾要做数据一致性校验? 参考答案:应急过程中可能有事务被 kill、超时重试、降级返回,都可能造成资金差错。必须校验少记/重复记/金额错误。

226. 系统突然无法转账,客户投诉,你怎么办(情景题) ​

【考察内容】应急沟通 + 流程意识(国企综合面试高频)

【题目】系统突然无法转账,客户在网点闹起来了,领导让你去处理。你怎么办?

【参考答案】

  1. 第一时间:止损 + 上报(并行)——立刻联系技术团队确认故障范围与预估恢复时间;按故障分级上报,不隐瞒、不拖延(金融行业最忌“捂盖子”);

  2. 安抚客户 + 给出确定性信息——对客户诚恳说明情况,给出明确的时间预期(“预计 30 分钟内恢复”),提供替代方案(柜台手工处理、引导至其他渠道);避免说“不知道”“不关我事”,也避免过度承诺;

  3. 协同处置——与技术、运维、客服、业务部门拉通,明确谁对外、谁对内;记录客户诉求与联系方式,恢复后主动回访;

  4. 事后:复盘 + 改进——分析根因、评估影响面(涉及多少客户、多少笔、有无资金差错);修复问题、补监控与预案;对受影响的客户主动补偿或解释。

  5. 容量估算(情景应对): “无法转账”分诊:全渠道 vs 单渠道;全客户 vs 部分;有报错 vs 超时。影响面数字:失败笔数、涉及客户数、资金是否在途。内部升级路径时间盒:5 分钟技术定位、15 分钟业务通报、30 分钟对外口径。

  6. 失败与降级: 先保资金安全:在途交易状态优先澄清;暂停可疑自动重试。渠道故障则切备用通道或引导延后。客服话术与技术状态同步,避免口径不一。

【原理溯源】

  • 为什么“止损与上报并行”而不是先修好再上报? 金融行业最忌“捂盖子”。故障瞒不住——客户在闹、网点在投诉,拖延上报只会让领导从其他渠道得知,被动挨打。主动上报体现责任心,也便于协调资源(备用方案、客户话术、监管沟通)。不隐瞒是金融从业者的底线。
  • 为什么对客户要给“确定性信息”而不是说“正在处理”? “正在处理”是空话,客户不知道要等多久,焦虑会升级。“预计 30 分钟内恢复”给了明确预期,即使最后超时,客户也能理解。提供替代方案(柜台手工、其他渠道)让客户有路可走——降低不确定性是安抚的关键。
  • 为什么不能过度承诺? 说“10 分钟就好”结果 1 小时没好,客户信任彻底崩塌。宁可保守估计(“预计 1 小时内”)超预期完成,也不要激进承诺然后跳票。金融行业的信任比效率更重要。
  • 为什么要有“谁对外、谁对内”的分工? 多头对外会让客户收到矛盾信息(一个说 30 分钟、一个说 1 小时);多头对内会重复协调。明确一人对外统一口径,其他人对内协调技术——这是应急沟通的基本纪律。
  • 为什么国企面试特别看重情景题? 国企综合面试考察的是“遇到问题时的处理逻辑与责任心”,不是技术深度。答题结构建议用“止损 → 上报 → 安抚 → 协同 → 复盘”五步——体现系统性思维、对客户负责、对组织透明。这是国企价值观的直接考察。

【选型判断树】

客户投诉情景题,按五步决策:
1. 止损 + 上报(并行)
   ├─ 联系技术确认故障范围与恢复时间
   ├─ 按故障分级上报,不隐瞒
2. 安抚客户
   ├─ 诚恳说明情况
   ├─ 给明确时间预期(不说“不知道”)
   ├─ 提供替代方案(柜台手工/其他渠道)
   └─ 不过度承诺
3. 协同处置
   ├─ 明确谁对外、谁对内
   ├─ 记录客户诉求与联系方式
   └─ 恢复后主动回访
4. 事后复盘
   ├─ 根因分析 + 影响面评估
   ├─ 修复 + 补监控预案
   └─ 客户补偿或解释
5. 底线
   └─ 不隐瞒、不拖延、不过度承诺

口诀:止损上报并行,安抚给确定性,协同分内外,复盘补短板。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“这是应急沟通题,核心是止损与上报并行、对客户给确定性”
0:30–1:30止损上报联系技术确认范围与恢复时间;按分级上报不隐瞒
1:30–2:30安抚客户诚恳说明;给明确时间预期;提供替代方案;不过度承诺
2:30–3:30协同处置谁对外谁对内;记录诉求;恢复后回访
3:30–4:30事后复盘根因+影响面;修复补监控;客户补偿
4:30–5:00收尾“一句话:止损上报并行,安抚给确定性,复盘补短板”

【关键数字】

参数经验值说明
上报时限确认故障后立即不隐瞒不拖延
时间预期给明确区间(如 30 分钟)保守估计
替代方案柜台手工/其他渠道让客户有路可走
回访时限恢复后 24h 内主动联系
复盘时限48h 内评估影响面
分工一人对外统一口径防矛盾信息

【追问链】(三层)

L1|“客户要求赔偿怎么办?” → 不当场承诺金额,记录诉求并转交有权处理的部门;同时明确银行的责任边界。赔偿是合规流程,不是现场决策。

L2|“如果故障是你的代码引起的怎么办?” → 第一时间如实上报,不隐瞒;先配合恢复业务,责任认定和复盘放到事后;隐瞒的代价远大于承认。金融行业“诚实”比“面子”重要。

L3|“领导让你先别上报,自己处理怎么办?” → 委婉但坚持:说明故障影响面(客户在闹、可能有资金差错),按流程需要上报。若领导仍坚持,书面留痕(邮件/工单)后按合规流程处理——这是履行合规义务,也是保护领导和自己。

【评分标准】

档位答案特征
60 分知道要联系技术、安抚客户
80 分止损与上报并行;给确定性时间预期;提供替代方案;五步结构
95 分主动提“不隐瞒”的金融合规意识;不过度承诺的信任逻辑;谁对外谁对内的分工;事后回访与补偿;情景题的完整闭环

【关联题】

  • 技术应急: 第 225 题(生产库 CPU 100%)——技术面的应急处理
  • 情景题簇: 第 227 题(明文密码)、第 228 题(遗留系统)——国企综合面试系列
  • 合规: 第 220 题(审计留痕)——故障追溯的合规要求
  • 对账: 第 219 题——故障后资金差错的兜底

【自测】

  1. 情景题的五步结构是什么? 参考答案:止损→上报→安抚→协同→复盘。
  2. 为什么不能说“不知道”? 参考答案:客户需要确定性信息。说“不知道”会让焦虑升级;给明确时间预期(即使保守)+替代方案,才能安抚。
  3. 故障是自己代码引起的,怎么办? 参考答案:第一时间如实上报,不隐瞒;先配合恢复业务;责任认定和复盘放事后。隐瞒的代价远大于承认。

227. 发现明文存储密码,但领导说“暂时没出事”(情景题) ​

【考察内容】合规意识 + 推动能力(国企综合面试高频)

【题目】你在代码审查中发现某个老系统把用户密码明文存在数据库里。你向领导反映,领导说“这个系统跑了十年了,暂时也没出事,先别动”。你怎么办?

【参考答案】

  1. 先把风险说清楚(用合规语言,不用技术语言):这是等保 2.0 与个保法的明确不合规项,不是“有没有出事”的问题,而是“检查到了就是问题”;一旦泄露,影响的是全部存量用户,且属于监管通报级别的事件;给出量化影响——涉及多少用户、可能的处罚与舆情后果;

  2. 给出可落地的低成本方案(不只提问题,要给方案):分层整改——新用户 / 新密码立即改为加盐哈希,存量用户走“下次登录时静默升级”(登录校验通过后用哈希覆盖原值),不需要停机、不需要强制改密——但静默升级只覆盖「还会登录」的账号:十年老系统里休眠/僵尸账号的明文会永久残留,不合规项并未闭合,而强制全员改密又会被业务否掉。所以要再加两条收口:① 收口期限(如连续 12 个月未登录→账号转冻结,激活时强制改密;或到期批量重置+首登强制改密,并按监管口径提前公告);② 可验证的清零指标(SELECT COUNT(*) FROM user WHERE password NOT LIKE '$2%' 必须为 0,即「库里已无明文」可举证),否则无法向检查方证明整改完成;若短期无法改造,先做数据库访问权限收敛 + 加密存储介质 + 加强审计,降低暴露面;

  3. 留痕 + 推动:把风险说明与整改建议书面提交(邮件 / 工单),形成记录;推动排期,定期跟进;若长期无响应且风险等级高,按公司合规上报渠道升级(如安全部门 / 合规部门);

  4. 态度:对事不对人,目标是解决问题而不是追责;同时守住底线——不能因为“领导说先别动”就假装没看见。

  5. 容量估算与风险量化: 明文密码风险:撞库成功率、涉及账号数、监管处罚案例。改造成本:哈希加盐(bcrypt/argon2/国密 SM3+盐)迁移方案——登录时透明升级或强制重置。性能:慢哈希故意慢,登录接口 CPU 会涨,要压测并设并发上限。

  6. 失败与降级: 领导要求拖延时的底线:书面风险提示留痕;先做访问控制与审计降低泄露面;网关限流撞库。已泄露应对:强制改密、Token 吊销、监管报告路径。不能以“暂时没出事”代替控制措施。

【原理溯源】

  • 为什么“暂时没出事”不是不整改的理由? 明文密码是定时炸弹:没炸不代表不会炸。等保 2.0 要求"采用密码技术保证重要数据(含鉴别信息)存储的保密性",个保法要求采取加密、去标识化等安全技术措施——法条没有把口令的存储方式写成"可逆加密",落到口令上的正确实现是不可逆哈希+盐(见第 214 题);无论采用哪种实现,明文存储都属不合规,这是合规义务而非最佳实践。监管检查到了就是问题,与“有没有出过事”无关。且一旦泄露,影响的是全部存量用户,属于监管通报级别的事件。合规是底线,不是加分项。
  • 为什么要用“合规语言”而不是“技术语言”? 领导可能不懂 BCrypt 和哈希的区别,但一定懂“等保不合规”“监管处罚”“个保法 5000 万罚款”。用合规风险和量化影响(涉及多少用户、可能的处罚)沟通,比说“技术上不安全”有效得多。向上沟通要翻译成对方听得懂的语言。
  • 为什么“给方案”比“提问题”重要? 只提问题:领导觉得你在制造麻烦。给方案:领导觉得你在帮忙解决问题。“静默升级”方案(下次登录时用哈希覆盖)不需要停机、不需要强制改密、成本极低——领导没有理由拒绝。推动成功的关键是降低决策门槛。
  • 为什么要“书面留痕”? 口头反映无据可查,领导可以说“没听你说过”。书面提交(邮件/工单)形成记录:你已尽到提示义务,领导已知悉风险。若将来出事,书面记录是你的免责证明。留痕是自我保护,也是推动手段(领导看到书面记录会更重视)。
  • 为什么不能“领导说不动就不动”? 金融/国企从业者的合规义务不因领导指示而免除。若长期无响应且风险等级高,应按公司合规上报渠道升级(安全部门/合规部门)。这不是“打小报告”,是履行合规义务——也是保护领导和你自己。

【选型判断树】

发现合规风险但领导不重视,按步骤:
1. 沟通策略
   ├─ 用合规语言(等保/个保法/监管处罚),不用技术黑话
   ├─ 量化影响:涉及多少用户、可能的处罚
2. 给方案
   ├─ 低成本:新用户立即哈希,存量静默升级**+收口期限(休眠账号冻结/批量重置)+清零指标可举证**
   ├─ 短期缓解:权限收敛 + 加密存储 + 加强审计
   └─ 降低决策门槛:不需停机、不需强制改密
3. 留痕推动
   ├─ 书面提交(邮件/工单)
   ├─ 定期跟进排期
   └─ 长期无响应 → 合规渠道升级
4. 底线
   ├─ 对事不对人
   └─ 不能假装没看见

口诀:合规语言说风险,给方案降门槛,书面留痕保自己,底线不能退。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“这是合规风险,不是技术债;领导说没出事不代表合规”
0:30–1:30说风险等保/个保法明确不合规;量化影响(用户数/处罚/舆情)
1:30–2:30给方案静默升级(不需停机)+休眠账号收口期限与清零校验(否则明文永久残留、合规项没闭合);短期缓解(权限收敛+审计)
2:30–3:30留痕推动书面提交;定期跟进;长期无响应合规升级
3:30–4:30态度对事不对人;守住底线不假装没看见
4:30–5:00收尾“一句话:合规是底线不是加分项,推动靠方案和留痕”

【关键数字】

参数经验值说明
静默升级下次登录时哈希覆盖不需停机/强制改密;只覆盖「还会登录」的账号→须配收口期限(如 12 个月未登录转冻结)+清零校验(库内非哈希口令数=0)
短期缓解权限收敛+加密存储+审计降低暴露面
书面留痕邮件/工单自我保护+推动手段
合规升级长期无响应时安全部门/合规部门
个保法处罚上限5000 万以下或营业额 5%以下择一上限,由监管裁量(非"取高者")
等保/审计口径口令须不可逆哈希+盐存储可逆加密属明确不合规项

【追问链】(三层)

L1|“领导还是不同意怎么办?” → 把书面风险提示留痕后,按公司合规/安全上报流程处理。这不是打小报告,是履行合规义务,也是保护领导和你自己。

L2|“静默升级具体怎么做?” → 用户登录时,先用旧方式(明文比对)验证;验证通过后用 BCrypt/Argon2 生成哈希,覆盖数据库中的明文。下次登录就走哈希比对。不需停机、不需强制改密,用户无感。

L3|“为什么不直接强制所有用户改密?” → 强制改密体验差、客户投诉多、业务部门会反对。静默升级用户无感,业务部门也容易接受。推动合规改造要兼顾业务体验,否则推不动。

【评分标准】

档位答案特征
60 分知道要向领导反映
80 分用合规语言说风险;给低成本方案;书面留痕
95 分主动提等保/个保法的具体条款;静默升级的技术方案(含只覆盖活跃账号的边界与收口期限);量化影响;合规升级渠道意识;“对事不对人”的态度

【关联题】

  • 数据安全: 第 214 题(脱敏与受控解密)——密码存储是数据安全的一部分
  • 审计: 第 220 题(审计留痕与等保)——合规要求的具体条目
  • 情景题簇: 第 226 题(无法转账)、第 228 题(遗留系统)——国企综合面试系列
  • 信创迁移: 第 221 题——老系统改造的渐进式方法

【自测】

  1. 为什么“暂时没出事”不是不整改的理由? 参考答案:明文密码是等保/个保法的明确不合规项,监管检查到了就是问题。合规是底线不是加分项。
  2. 静默升级具体怎么做? 参考答案:登录时先用旧方式验证;通过后生成哈希覆盖明文。下次登录走哈希比对。不需停机、不需强制改密。
  3. 领导长期不同意怎么办? 参考答案:书面留痕后按公司合规/安全上报流程升级。这是履行合规义务,也是保护领导和自己。

228. 历史遗留系统有重大风险,没人敢动(情景题) ​

【考察内容】风险推动 + 渐进式改造思路

【题目】你接手了一个跑了十几年的核心老系统,代码没人看得懂、文档缺失、还有重大安全隐患。但它是核心业务,没人敢动。你怎么办?

【参考答案】

  1. 先评估、不冒进:先做风险清单——梳理安全隐患、性能瓶颈、单点、依赖关系,标注严重程度与影响面;建立可观测性——补日志、补监控、补告警,先把“看不见”变成“看得见”(这是所有改造的前提);补最小必要文档——核心链路、关键表、上下游依赖,不追求完整;

  2. 划边界:不改核心,先加外壳:在外部加防腐层 / 适配层,把老系统包起来,新功能走新架构,老逻辑保持不动;用绞杀者模式(Strangler Fig)——从外围功能(报表、查询、非核心接口)开始,逐个用新实现替换,逐步缩小老系统边界;

  3. 争取资源:用数据说话——故障次数、影响客户数、潜在合规风险、每次救火的工时,形成改造提案;提出分阶段方案(不是“推倒重来”),每阶段有明确收益,降低决策门槛;

  4. 守住底线:在改造完成前,对已知重大风险(如明文密码、越权接口)先做低成本缓解(权限收敛、访问审计、加网关拦截);关键操作留痕,出问题时能自证已尽到提示义务。

  5. 容量估算(改造排期): 风险打分=可能性×影响;按“每季度消除几个高风险项”定路线图。绞杀者模式新服务承接流量比例阶梯:1%→10%→50%→100%。可观测性投入通常 ROI 最高,优先做。预算:人月估算用接口数量与变更频率。

  6. 失败与降级: 改造中老系统仍是生产:任何外壳/适配层故障要能一键切回老入口。新系统 bug 不扩大化:灰度+自动回滚。团队无人敢动时,先用旁路只读分析与混沌小范围演练建立信心,而不是强行重写。

【原理溯源】

  • 为什么“先补可观测性再谈改造”? 没有日志、监控、告警的老系统是黑盒——你不知道它怎么工作、哪里会出问题、改了会怎样。补可观测性是把黑盒变灰盒的第一步:有了监控才能知道现状(性能瓶颈在哪、哪些接口被调用、故障频率),有了日志才能在改造后对比行为是否一致。没有可观测性,任何改造都是盲改。
  • 为什么用“绞杀者模式”而不是“推倒重写”? 推倒重写:老系统还在承载核心业务,重写期间业务怎么办?重写完成后怎么验证与老系统行为一致?重写失败怎么回退?风险极高且往往失败(著名的“第二系统效应”)。绞杀者模式:在入口加路由层,按功能/URL 把流量分流到新老实现;老实现只读不改,新功能全走新的;逐块替换,每块替换后观察一段时间再继续——风险可控、可回退、业务不中断。
  • 为什么要“补最小必要文档”而不是写完整文档? 完整文档工作量巨大且很快过时,没人会维护。最小必要文档(核心链路、关键表、上下游依赖)覆盖了“理解系统所需的最少知识”,成本可控且真正有用。文档的价值在于可用,不在于完整。
  • 为什么用“数据说话”争取资源? “这个系统很危险”是主观判断,领导无感。“过去一年故障 15 次、影响 200 万客户、每次救火平均 8 人时、潜在合规罚款 500 万”是客观数据,领导必须面对。把技术风险翻译成业务语言(客户数、资金、工时、罚款),决策者才能评估投入产出。
  • 为什么改造前要“低成本缓解”已知重大风险? 改造需要时间(几个月到几年),但明文密码、越权接口这些风险是当下就存在的。不能等改造完成再修——万一这期间泄露了呢?低成本缓解(权限收敛、访问审计、网关拦截)不需要大改代码,能快速降低暴露面。边改造边缓解,两线并行。

【选型判断树】

遗留系统改造,按步骤:
1. 先评估(不冒进)
   ├─ 风险清单:安全隐患/性能/单点/依赖
   ├─ 可观测性:补日志/监控/告警 ★
   └─ 最小必要文档:核心链路/关键表/依赖
2. 划边界(不改核心)
   ├─ 防腐层/适配层:包住老系统
   ├─ 绞杀者模式:外围功能逐个替换
   └─ 新功能走新架构,老逻辑不动
3. 争取资源
   ├─ 数据说话:故障次数/客户数/工时/罚款
   └─ 分阶段方案,每阶段有明确收益
4. 守住底线
   ├─ 已知重大风险低成本缓解
   ├─ 关键操作留痕
   └─ 出问题能自证已尽提示义务
5. 禁忌
   ├─ 不要推倒重写
   └─ 不要“风险太大先放着”

口诀:先看见再改造,绞杀者渐进替换,数据争取资源,底线不能丢。

【口述骨架】(5 分钟)

时间任务内容
0:00–0:30定性“遗留系统改造的核心是风险控制,不是技术炫技”
0:30–1:30先评估风险清单;补可观测性(日志/监控/告警);最小必要文档
1:30–2:30划边界防腐层包住老系统;绞杀者模式外围逐个替换
2:30–3:30争取资源数据说话(故障/客户/工时/罚款);分阶段方案
3:30–4:30守住底线已知风险低成本缓解;关键操作留痕
4:30–5:00收尾“一句话:先补可观测性,绞杀者渐进替换,数据争取资源,底线不能丢”

【关键数字】

参数经验值说明
可观测性优先级第一步没有监控无法改造
绞杀者替换粒度每次一个功能/接口观察后再继续
防腐层入口路由分流新老老实现只读不改
文档范围最小必要:核心链路/关键表/依赖不追求完整
低成本缓解权限收敛/审计/网关拦截快速降低暴露面
数据说服故障次数/客户数/工时/罚款业务语言
分阶段每阶段有明确收益降低决策门槛

【追问链】(三层)

L1|“绞杀者模式具体怎么做?” → 在入口加路由层,按 URL/功能开关把流量分流到新老实现;老实现只读不改,新功能全走新的;逐块替换,每块替换后观察一段时间再继续。风险可控、可回退、业务不中断。

L2|“怎么说服领导投入资源?” → 把风险量化成业务语言(影响多少客户、多少资金、可能的监管处罚),并给出分阶段、低风险、有阶段性收益的方案。领导关心的是投入产出和风险,不是技术细节。

L3|“为什么不推倒重写?” → 核心系统推倒重写风险极高且往往失败:重写期间业务怎么办?怎么验证行为一致?失败怎么回退?著名的“第二系统效应”就是重写失败的教训。绞杀者模式用时间换确定性。

【评分标准】

档位答案特征
60 分知道要重构、补文档
80 分先补可观测性;绞杀者模式/防腐层;数据说话争取资源
95 分论证“先看见再改造”的顺序逻辑;绞杀者 vs 推倒重写的风险对比;已知风险低成本缓解;分阶段方案降低决策门槛;“既敢推动又不冒进”的度

【关联题】

  • 信创迁移: 第 221 题——渐进式迁移的方法论
  • 情景题簇: 第 226 题(无法转账)、第 227 题(明文密码)——国企综合面试系列
  • 数据安全: 第 214 题——遗留系统的脱敏改造
  • 应急: 第 225 题——遗留系统出问题时的应急

【自测】

  1. 为什么改造前要先补可观测性? 参考答案:没有日志/监控/告警的老系统是黑盒,任何改造都是盲改。补可观测性是把黑盒变灰盒的第一步。
  2. 绞杀者模式和推倒重写的核心区别是什么? 参考答案:绞杀者模式渐进替换、可回退、业务不中断;推倒重写风险极高且往往失败(第二系统效应)。
  3. 怎么说服领导投入资源改造? 参考答案:用数据说话(故障次数/客户数/工时/罚款),翻译成业务语言;给分阶段、低风险、有阶段性收益的方案。

说明: 以下为 AI 算法场景专题(AI-01 ~ AI-54),独立于后端 1–228 题编号体系。

持续学习,持续积累。