第十章 国企 / 金融场景专题(第209-228题)
209. 手机银行登录系统要高可用,怎么设计(高可用登录架构)
【考察内容】高可用架构设计 + 认证体系 + 金融可用性要求
【题目】行里要求手机银行登录系统全年可用率不低于 99.99%(全年停机不超过 53 分钟),日活 3000 万,早高峰 8:00–9:00 登录 QPS 峰值 3 万。请设计这套登录系统,并说明如何做到高可用。
【参考答案】按“先保可用、再谈体验”的思路:
分层设计:接入层用多机房 DNS 智能调度 + 四层/七层负载(LVS + Nginx),客户端 SDK 内置多 IP 兜底与自动重试;应用层登录服务无状态化(Session 外置到 Redis 集群),支持水平扩容;数据层用户认证库主从 + 读写分离,凭证校验走缓存;
认证链路:设备指纹 + 图形/短信验证码(前置风控)→ 密码/生物识别校验 → 颁发短时效 AccessToken + 长时效 RefreshToken,敏感操作二次认证;
高可用手段:同城双活(两机房同时承载,任一故障秒级切流);依赖降级(先把依赖拆开再谈降级:第 2 条里图形验证码与短信验证码同属「验证码服务」,所以「验证码服务挂」时拿短信当备用因子是走不通的(同来源一起挂)。分两种情况答:① 只有图形/风控验证码组件挂 → 降级为「密码+设备指纹+短信验证码」,保持认证强度;② 短信网关也挂(或与短信链路同源故障)→ 降级为「密码+设备指纹+人脸/UKey/口令」等不依赖短信的因子,并临时限制敏感操作、二次认证改用可用因子。两条路径都要留可审计记录。风控服务不可用时降级为“放行但加强事后审计”);限流熔断(按用户 / IP / 设备维度,防撞库打满);灰度与回滚(新版本按用户分桶灰度,异常自动回滚);
监控与演练:登录成功率、P99 耗时、验证码下发成功率、各依赖可用率;定期做故障演练(机房切换、依赖宕机)。
容量估算: 手机银行登录峰值经验:早高峰/还款日可达日常 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 分钟)。
失败与降级: 验证码服务挂→密码+设备指纹;风控挂→限额放行+事后审计;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 题(金融级服务降级)——依赖降级的通用方法论
【自测】
- 99.99% 可用率对应的全年停机预算是多少分钟?这对切流速度有什么要求? 参考答案:约 53 分钟。单次机房故障的检测+切流必须压到 1 分钟内,否则一年只允许几次故障。
- 验证码服务不可用时,金融登录能否直接放行?正确做法是什么? 参考答案:不能。登录是资金入口,直接放行会放大撞库风险。应降为备用认证因子(密码+设备指纹+短信),保持认证强度;若部分放行,敏感操作仍强制二次认证并全量审计。
- 为什么 AccessToken 要短时效、RefreshToken 要长时效且可撤销? 参考答案:短时效压缩 Token 被盗后的可利用窗口;长 Refresh 支持无感续期且可随时撤销(踢人)。敏感操作再强制二次认证,即使 Access 被盗也转不走钱。
210. 亿级账户流水表翻页越来越慢(亿级数据分页查询)
【考察内容】深分页优化 + 亿级数据查询设计
【题目】账户流水表有 8 亿行数据,客户在 App 上翻看历史流水,翻到后面几十页时接口要 5 秒以上,客户投诉。请给出优化方案,并说明如果要设计一个“亿级数据的分页查询方案”,你的整体思路是什么。
【参考答案】
先定位:
EXPLAIN看是否全表扫描;深分页LIMIT 1000000, 20的本质是扫描并丢弃前 100 万行,代价随页数线性增长——但题干是「翻到后面几十页」,20 条/页时 offset 只有约千级(几十×20≈1000,与 100 万差约 1000 倍),千级 offset 本不该 5 秒,所以第一步要按「offset 不大却仍慢」这个分支定位:ORDER BY字段无索引/无覆盖索引导致全表 filesort、SELECT *宽行回表放大、分库分表下每片都要取offset+n条再跨片归并、页面另外还发了COUNT(*)全量统计。游标分页只治「offset 大」那一支,不先 EXPLAIN 就答游标分页属于没对症;优化手段(按性价比排序):
- 游标分页(推荐):改用“上一页最后一条的 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 个月热数据在线上库,历史数据归档到历史库 / 数仓,查询路由到不同库;
- 覆盖索引:把常用查询字段(流水号、时间、金额、对手方)做成联合索引,避免回表;
- 游标分页(推荐):改用“上一页最后一条的 id/时间”作为游标,
分页查询方案的通用骨架:明确查询维度(按时间 / 按卡号 / 按类型)→ 选择分页方式(游标分页优先,跳页需求才用 offset)→ 设计索引(查询字段顺序 = 索引顺序,最左前缀)→ 控制结果集大小 → 冷热分层 → 加缓存(首页 / 热门页)。
容量估算: 亿级流水表:单行按 1KB → 1 亿行 ≈ 100GB;宽表按 3~8KB/行 → 300GB~800GB;若已到 8 亿行 ×1KB ≈ 800GB 才谈得上 TB 级——「数百 GB~TB」要说清按几 KB/行、多少行。深分页
LIMIT 1000000,20会扫过百万行,必须改写。优化:① 游标/seek(WHERE id/时间 > last);② 延迟关联先查主键再回表;③ 按用户+时间分区/分表;④ 热数据近线存储。翻页深度产品上限(如 100 页)从源头限制。查询 P99 目标金融柜面常 <2s。失败与降级: 历史查询走离线/归档库异步导出,核心在线库只服务近期;归档库不可用时提示稍后重试而不是拖垮主库。分析型需求强制走数仓。
【原理溯源】
- 为什么
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 题(日终对账)——归档/缓存出错时的最终防线
【自测】
LIMIT 1000000, 20为什么慢?加索引能解决吗? 参考答案:引擎必须扫描并丢弃前 100 万行,页数越深代价线性增长。加索引救不了扫描丢弃本身,应改游标分页。- 游标分页的代价是什么?金融流水场景能否接受? 参考答案:不能随机跳页。流水浏览用户行为本就是往下刷,跳页需求极低,完全可接受;真要跳页改为条件检索。
- 历史流水为什么归档而不是删除?归档后查询怎么办? 参考答案:监管要求流水可追溯多年(通常≥5年)。归档到历史库/数仓,查询路由到另一条链路,可接受秒级延迟,但必须可查。
211. 理财开售瞬间被抢空(金融秒杀场景)
【考察内容】金融场景下的高并发抢购 + 合规与公平性
【题目】一款年化 4.5% 的理财产品今日 10:00 开售,额度 5 亿元,预计 100 万客户同时抢购。要求:不超卖、不重复购买、系统不崩,且监管要求“销售过程可追溯、不得有内部插队”。请设计方案。
【参考答案】
先与互联网秒杀区分:金融抢购多两条硬约束——额度是钱(不能超卖)、过程要可追溯(监管审计);
削峰:开售前页面静态化 + 倒计时本地渲染;开售瞬间用答题 / 验证码 / 预约资格做前置拦截,把并发打散到几十秒;
库存控制:额度预扣在 Redis(按份数用
DECR、按金额用DECRBY,或 Lua 脚本保证原子性),扣减成功才进入下单;Redis 与 DB 最终一致靠 MQ 异步落库 + 定时对账补偿,DB 层再用UPDATE ... WHERE 剩余额度 >= :amount条件更新兜底,双重防超卖;每个客户限购 1 份用唯一索引(客户号 + 产品号)挡重复,或 Redis SETNX 预占;公平性与可追溯:全流程流水落库(谁、何时、以什么请求号、扣了多少额度),请求号全局唯一便于审计;拒绝任何“内部通道”,所有流量走同一入口,防止插队质疑;
兜底:排队机制(超阈值直接返回“排队中”)、降级(只保下单主链路)、限流(网关 + 用户维度)。
容量估算: 理财秒杀:额度 N 份、预约用户 M 人,峰值 QPS 可按“M×瞬时点击率”粗估,常见远高于日常百倍。库存扣减必须原子(DB 乐观锁/Redis Lua/预扣号段)。单机 Redis 扣减 10 万+ QPS 可扛热点;DB 最终落账异步化。超卖零容忍;少卖可接受。带宽与风控也要算。
失败与降级: 系统过载时:排队页/资格抽签,而不是让用户请求打死核心账务。扣减成功但下单失败必须有自动退回额度任务。支付通道失败保留额度锁定时限(如 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 题(审计与等保)——可追溯的合规要求
【自测】
- 金融抢购与电商秒杀的两条本质差异是什么? 参考答案:额度是钱(超卖即资金差错,不能补发解决);过程必须可追溯、不得内部插队(监管合规义务)。
- 为什么要 Redis 预扣 + DB 条件更新双重防超卖? 参考答案:Redis 管性能挡并发,但不是账本;DB 条件更新从 SQL 层面杜绝超卖,是正确性底线。
- 客户怀疑有内部插队,如何自证清白? 参考答案:全链路请求号留痕,每笔请求的进入时间、来源、结果可查;证明所有流量走同一入口、无旁路通道。
212. 核心账务与营销系统的 CAP 怎么取舍(CAP 在金融落地)
【考察内容】分布式理论在金融场景的实际选型
【题目】面试官问:CAP 理论在银行系统里怎么取舍?核心账务系统和营销活动系统应该选 CP 还是 AP?为什么?
【参考答案】
先纠一个常见误解:CAP 的“三选二”是在发生网络分区(P)时才需要取舍;正常情况下 C 和 A 都能满足。所以真正的问题是——分区发生时,你要保一致性还是保可用性;
核心账务系统 → CP:钱的账不能错。分区时宁可拒绝服务(返回“系统繁忙,请稍后重试”),也不能两边各自记账导致账不平。落地手段:同城双活用强同步复制(两副本场景下"多数派"即全部确认,需再配第三仲裁点才是真 quorum)、分布式事务(TCC / 本地消息表)、日终对账兜底;
营销活动系统 → 可选 AP:领券、积分、活动页这类短暂不一致可接受(用户刷新一下就对了),可用性优先。落地手段:异步复制、最终一致、MQ 补偿;
更进一步的答法:实际系统是按业务分级混用——同一个银行里,账务 CP、支付准 CP、营销 AP、查询类 AP(走从库);并用 BASE 思想对非核心链路做柔性事务。
容量估算与取舍落地: 核心账务选 CP(一致性优先):宁可短暂不可用,不可错账;营销/浏览选 AP。同步复制延迟与吞吐需压测:核心库集群节点数、半同步超时。账务日切窗口与批量任务资源隔离。监管可用性与时效要求写进 SLO。
失败与降级: 一致性组件(强同步)故障时:核心转账可暂停或排队,不允许“先成功后对不齐”;营销系统可降级 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 的具体问题
【自测】
- 为什么账务不能选最终一致? 参考答案:不一致窗口内的错误记账是资金差错,进监管投诉、影响账务平衡;事后补偿代价远大于分区期暂时拒绝服务。
- 营销系统为什么可以 AP? 参考答案:券/积分短暂不一致用户无感,错了可补偿,错误代价低;用不一致换可用性划算。
- 为什么 CP 了还要做对账? 参考答案:CP 只保证分区时不制造不一致,不能防应用 bug、消息丢失、人工误操作。对账是独立于运行时协议的最终防线,分层设防。
213. 转账接口被重复调用导致重复扣款(金融级接口幂等)
【考察内容】金融场景的幂等设计
【题目】客户点了一次“转账”,但因为网络超时客户端自动重试,后端收到两次请求,客户被扣了两次钱。请说明如何设计幂等来根治,并解释为什么这个场景比普通电商的幂等要求更严。
【参考答案】
幂等键设计:客户端生成全局唯一请求流水号(UUID 或 业务号+时间戳+随机数),服务端以该流水号为幂等键;
存储与判定:用唯一索引(或 Redis SETNX)挡重复——
INSERT INTO txn_log(request_id, ...) UNIQUE KEY(request_id),插入失败即为重复请求,直接返回首次结果;状态机:转账单有明确状态流转(待处理 → 处理中 → 成功 / 失败),幂等判定要结合状态:同流水号 + 同状态 → 返回原结果;同流水号 + 不同参数 → 拒绝并告警(防篡改);
与业务的一致性:幂等记录与业务扣款必须在同一个本地事务里提交(或“先落幂等记录,再走业务,最后更新状态”的本地消息表模式),否则会出现“幂等记录有了但钱没扣”或“钱扣了但幂等记录没落”;
为什么比电商严:电商重复下单可取消、钱能退;银行重复扣款是资金差错,会进监管投诉、影响账务平衡,且客户感知极强。因此必须做到“宁可拒绝,不可重复”,并配套对账与差错处理。
容量估算: 幂等键存储:按日交易量×保留期(金融常 1–7 年)。如日 1000 万笔×1 年≈36 亿条,需分库分表或归档。幂等键长度与索引要考虑。重复请求命中率监控。接口超时重试策略与幂等配合(客户端 1 次+服务端去重)。
失败与降级: 幂等存储不可用:金融资金接口 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_id | DB 层最终防线 |
| 幂等有效期 | 热层 1–7 年可查,终态归档长期留存 | 审计与对账需要;"永久"指归档层,不是热库 |
| 重试策略 | 客户端指数退避 + 最多 3–5 次 | 减少无效重试 |
| 状态机终态 | 成功/失败/已退回 | 处理中可轮询 |
【追问链】(三层)
L1|“Redis 挂了怎么办?” → 唯一索引是最终防线。Redis 只是前置拦截,挂了流量直达 DB,DB 唯一索引仍能挡重复。代价是 DB 压力增大,需要限流保护。正确性不依赖 Redis,这是金融幂等的设计原则。
L2|“同流水号不同金额怎么处理?” → 这不是重试,是篡改或客户端 bug。必须拒绝请求并告警,不能当成重复请求返回首次结果——否则攻击者可能用同一流水号、不同金额反复试探。金融安全要求语义严格匹配。
L3|“幂等记录和业务扣款为什么要同事务?分两步不行吗?” → 分两步会出现半吊子:先写幂等后扣款,中间宕机→有幂等无扣款,重试被拦截,转账永远失败;先扣款后写幂等,中间宕机→有钱无幂等,重试再扣一次。同事务保证要么都在要么都不在——这是本地 ACID 在金融幂等中的核心价值。
【评分标准】
| 档位 | 答案特征 |
|---|---|
| 60 分 | 知道用 Redis 或唯一索引防重复 |
| 80 分 | 双层防线;结合状态机判定;幂等与业务同事务 |
| 95 分 | 论证“宁可拒绝不可重复”的金融约束;同流水号不同参数=篡改要拒绝;幂等有效期覆盖审计需求;能对比电商幂等的严格程度差异 |
【关联题】
- 互联网版原型: 第 110 题(接口幂等)——本题是金融口径改造
- 分布式事务: 第 218 题(金融分布式事务)——TCC 中的幂等
- 对账兜底: 第 219 题(日终对账)——幂等失效后的最终防线
- 秒杀防重: 第 211 题(金融抢购)——唯一索引防重复购买
【自测】
- 为什么金融幂等必须有 DB 唯一索引,不能只用 Redis? 参考答案:Redis 主从切换可能丢写、宕机可能丢数据;唯一索引依赖 DB ACID 是最终防线。Redis 只是前置拦截减压。
- 同流水号但金额不同,应该怎么处理? 参考答案:这不是重试而是篡改或 bug,必须拒绝+告警,不能静默当成重复请求。
- 为什么说金融幂等是“宁可拒绝,不可重复”? 参考答案:重复扣款是资金差错(监管投诉、账务不平、客户信任);拒绝服务代价可控。拿不准时拒绝。
214. 客户信息要脱敏,但客服还要能查到(银行级数据安全与脱敏)
【考察内容】数据分级分类 + 动态脱敏 + 受控解密 + 审计留痕
【题目】监管要求客户手机号、身份证号、银行卡号在系统里必须脱敏展示;但客服在核身通过后又需要看到完整信息。请设计一套方案,兼顾合规与业务可用。
【参考答案】
分级分类:先给数据定级——L1 公开、L2 内部、L3 敏感(手机号 / 身份证 / 卡号)、L4 核心(密码 / 密钥)。不同级别不同策略;
存储层:敏感字段加密存储(如 AES + KMS 托管密钥),密码类用加盐哈希(BCrypt / Argon2),不可逆;需要检索的字段(如手机号)存“加密值 + 哈希索引”两列,用哈希列做等值查询;
展示层(动态脱敏):默认接口返回脱敏值(
138****8888),在网关 / 序列化层统一做,避免每个业务代码各写一遍;脱敏规则配置化(不同角色不同规则),不硬编码;明文获取(受控解密):独立“解密服务”,需二次授权(业务系统申请 + 权限校验 + 事由填写);解密操作全量审计(谁、何时、查了谁的什么字段、什么理由),审计日志不可篡改、独立存储;支持按需授权(如客服核身后限时 5 分钟可见)、次数限制、异常行为告警;
其他:数据传输全程 HTTPS / 国密;日志与埋点中禁止出现明文(日志脱敏中间件);测试环境用假数据。
容量估算: 脱敏规则与性能:展示层脱敏 CPU 开销低;密文检索用盲索引/保序加密要评估安全与性能。客服查询审计日志按查询次数全量保存。权限模型:角色数×字段策略,避免组合爆炸。国密算法改造时接口加解密 RT 增量压测。
失败与降级: 脱敏服务故障:默认不展示明文(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 题(高可用登录)——认证体系的数据安全面
【自测】
- 为什么密码用哈希、手机号用加密? 参考答案:密码只需验证对错不需要还原→加盐哈希不可逆;手机号需支持查询和核对→加密可逆+哈希索引。
- 脱敏在业务代码里做还是网关层做?为什么? 参考答案:网关/序列化层统一做。业务代码分散必然漏,架构保证比人的自觉可靠。
- 审计日志为什么要独立存储? 参考答案:同库同权限时,拿业务权限就能改日志抹痕,审计失去不可否认价值。
215. 全国 1 亿用户数据单库扛不住(金融数据分片)
【考察内容】分片策略设计 + 金融场景的分片键选择
【题目】全国 1 亿宽带用户信息存在一张表里,单库单表已经扛不住写入和查询压力。请设计分片方案,并说明分片键怎么选。
【参考答案】
分片键选择(最关键):候选有用户 ID、手机号、省份(
province_id)、地市。按省份 / 地市分片天然贴合电信业务的查询习惯(大部分查询带地域维度),且各省数据量相对均衡,运维可按省隔离、按省扩容;若业务查询以用户维度为主,则用用户 ID 哈希分片,保证单用户查询落在单分片;实践中常见两级分片——先按省(业务维度,便于隔离与合规),省内再按用户 ID 哈希(数据均衡);但两级分片成立的前提是「查询能带上第一级键」:题干若用户点查不带省份(或用户 ID 里没编码省份),路由层就只能对 31 个省各查一遍再归并,反而比单层按 user_id 哈希慢一个数量级。所以先问两件事:① 查询是否总带地域维度(报表/按省稽核→带;App 查自己的账单→通常不带);② 能否让 user_id 本身编码省份段(或维护一张 user→province 路由表并在写入时固化)。两者都不成立就别硬套两级分片,直接按 user_id 哈希+异构出「按省」的汇总表;分片方式:范围分片(易扩容、易热点)vs 哈希分片(均衡、扩容需迁移);金融场景更看重稳定,常用“预分片 + 一致性哈希 / 双倍扩容”降低迁移成本;
路由与中间件:用 ShardingSphere / 自研路由,SQL 解析后按分片键路由;分片键必须出现在查询条件里,否则广播查询;
跨分片查询:跨省统计走数仓 / 分布式 SQL 引擎(如 Presto / ClickHouse),不在线上库做全分片扫描;
配套:全局唯一 ID(雪花算法,注意时钟回拨)、分布式事务(分片后跨库事务)、分片扩容方案(双写迁移 + 校验 + 切流)。
容量估算: 1 亿用户:账户主数据单行 KB 级约 100GB+,单库难扛扩展与DDL。分片键选择:用户号取模/范围;热点产品账户可能倾斜需二次散列。每分片目标 <5000 万行、磁盘水位 <60%。全局唯一 ID、跨片查询走索引表/ES。迁移期双写与校验抽样比例。
失败与降级: 单分片故障:影响该分片用户,需快速切换/重建;跨分片事务用最终一致+补偿,不阻塞全局。路由服务要做多级缓存,防止路由表故障全局不可用。
【原理溯源】
- 为什么分片键选择比索引优化重要得多? 索引解决“单库内怎么查快”,分片键决定“数据落在哪、查询路由到哪”。分片键选错:查询带不上分片键→广播全部分片;数据倾斜→热点分片打满。分片键一旦定下,迁移成本极高——所以是分片设计的第一决策。
- 为什么金融/电信场景常用“按省分片”? ①业务查询天然带地域(按省出报表、按省监管报送);②运维可按省隔离——某省故障不影响他省,符合国企“局部故障不扩散”的稳定性要求;③合规上数据可按省留存。这是业务维度优先于技术维度的选型思路。
- 为什么还要省内再哈希? 按省分片时人口大省数据量是小省的数倍,直接按省到库会造成倾斜。省内再按用户 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 题(主从延迟)——分片+读写的组合
- 互联网版: 分库分表通用知识——本题强调金融/电信业务维度选型
【自测】
- 为什么金融/电信场景常按省分片而不是按用户 ID 哈希? 参考答案:业务查询天然带地域;运维可按省隔离;合规可按省留存。大省再哈希拆子片解决倾斜。
- 预分片为什么能降低扩容成本? 参考答案:逻辑分片数远大于物理库数,扩容时只迁移部分逻辑片到新库,迁移量是 1/N。
- 跨省统计应该怎么做? 参考答案:走数仓/OLAP 引擎,不在线上库广播扫描;在线跨省需求建异构索引或 ES。
216. 核心库读压力大,读写分离后主从延迟(金融读写分离)
【考察内容】读写分离架构 + 主从延迟的业务处理
【题目】核心账务库读压力大,做了读写分离(写主库、读从库)后,出现“客户刚转账成功,刷新却查不到这笔记录”。请说明原因和解决方案。
【参考答案】
原因:MySQL 主从复制是异步(或半同步)的,从库回放有延迟(网络 + 单线程/多线程回放),秒级到分钟级都可能。写主库后立刻读从库,就会读到旧数据(读己之写问题);
解决方案(按业务影响面排序):
- 写后强制读主:写操作后对该用户的短时间窗口(如 3–5 秒)内的读请求路由到主库,窗口过后回从库;实现方式:写时在 Redis / 本地缓存打一个“用户级标记”,读时判断;
- 按业务分流:账务类“刚发生的交易”必须读主;历史流水查询、统计类读从库;
- 会话粘性:同一用户在同一会话内的读写都走主库;
- 半同步复制 / 组复制(MGR):至少保证从库收到 binlog 才返回成功,把延迟压到最低(代价是写入变慢);
- GTID + 位点校验:读从库前校验位点是否已追平,未追平则等待或降级读主;
兜底:对“读不到”的场景给出明确提示(如“交易处理中,请稍后查看”),并在前端做乐观展示。
容量估算: 读写分离:主库写 QPS 与从库读 QPS 分开压测。延迟预算:核心“读己之写”路径强制主库;报表读从库。金融日终批量时延迟可能激增,要隔离。从库数量按读峰值/单从能力。连接路由中间件本身单点风险要双活。
失败与降级: 延迟超过阈值时只把「该用户这笔写后读」切回主库,不做「关键读整体切主」:题干前提就是核心账务库读压力大才做读写分离,整体切主正是本块判死的「全部读主=读写分离白做」,再靠主库限流会把客户从「查不到」变成「被拒」;正解是动态把写后窗口拉长到当前延迟 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 题(同城双活)——强同步复制的另一个应用
【自测】
- 什么是读己之写问题? 参考答案:写主库后立刻读从库,因复制延迟读到旧数据。刚转账成功刷新却查不到。
- 为什么不用“全部读主”解决? 参考答案:读流量回到主库,读写分离白做。应写后读主:只把写后短窗口的读路由到主,其余读从。
- 账务查询和历史查询的路由策略有什么不同? 参考答案:账务刚发生的交易必须读主(事实语义);历史流水/统计读从(容忍秒级延迟)。
217. 大促式流量下核心系统不能停(金融级服务降级)
【考察内容】降级设计 + 业务影响面控制
【题目】某银行做营销活动,流量是平时的 10 倍,核心账务系统压力剧增。要求在流量峰值时“保证核心业务可用、非核心功能可牺牲”。请设计降级方案。
【参考答案】
先做业务分级(降级的前提):P0 不可降——转账、扣款、账务记账、登录;P1 可延迟——账单查询、历史流水、消息推送、积分更新;P2 可关闭——活动页个性化推荐、排行榜、弹窗广告、非必要的埋点上报;
降级手段:读降级(非核心查询直接返回缓存 / 默认值 / “系统繁忙,请稍后”);写降级(非核心写如积分、埋点、日志异步化或本地落盘后补);功能降级(关闭个性化推荐、简化页面、关闭非必要风控规则需审批);依赖降级(下游超时立即熔断,返回兜底值,不阻塞主链路);
触发机制:自动(错误率 / RT / 线程池水位超阈值自动降级)+ 手动(开关在配置中心,值班可一键切换);必须有开关、有灰度、有回滚;
前置准备:容量压测确认阈值、降级预案演练、开关默认值评审、降级期间的客户提示话术;
事后:降级期间记录明细,恢复后补数据(如积分补发),并复盘是否要永久优化。
容量估算: 金融降级分级:L1 营销/推荐可弃;L2 非核心查询只读/缓存;L3 核心转账排队但不丢。流量按“必须服务的最小功能集”反推机器与 DB 容量。限流阈值分层:网关全局、服务、用户、渠道。演练分两件事:预案切换演练每季度至少 1 次(验证降级/切流真能生效),全链路压测每年至少 1 次(验证容量水位),别把两者合成一句“每年一次”。
失败与降级: 预案必须可一键执行:开关中心化、有权限、有审计。降级期间 SLA 口径要提前定义(排队成功率、最长等待)。恢复时按反序慢慢放量,防止二次冲击。
【原理溯源】
- 为什么降级的前提是“业务分级”而不是先上熔断器? 熔断器只回答“依赖挂了怎么办”,不回答“该牺牲谁”。没有业务分级,降级变成随机丢弃——可能把转账也降了。P0/P1/P2 分级的本质是在资源紧张时明确资源分配的优先级。这是业务决策,不是技术决策。
- 为什么金融降级不能“关掉风控”? 风控是资金安全的防线。关掉风控=打开欺诈窗口,活动期间正是攻击者活跃期。若非核心风控规则可降,需审批+白名单+事后加强审计;核心风控(转账反欺诈)绝不可降。降级降的是体验,不是安全。
- 为什么开关必须“有灰度、有回滚”? 降级开关配错可能把 P0 关了——比不降级更糟。灰度:先对 1% 流量生效,观察无异常再全量;回滚:一键恢复;白名单:核心功能的开关在代码层面硬编码为不可降。这是用发布工程的严谨对待降级操作。
- 为什么降级后要“补数据”? 写降级时积分/埋点落本地或丢弃,恢复后必须补发——否则客户积分少了是投诉,埋点丢了是数据缺口。降级是临时手段,业务语义必须最终完整。这也符合金融“对账闭环”思维。
- 为什么自动降级和手动降级都要有? 自动降级反应快(错误率超阈值秒级触发),但可能误判;手动降级准确(值班结合业务判断),但反应慢。两者互补:自动兜住突发故障,手动处理复杂场景。
【选型判断树】
降级方案设计,按步骤:
1. 业务分级(前提)
├─ P0 不可降:转账、扣款、记账、登录、核心风控
├─ P1 可延迟:账单查询、历史流水、推送、积分
└─ P2 可关闭:推荐、排行榜、弹窗、非必要埋点
2. 降级手段
├─ 读降级:非核心查询返回缓存/默认值
├─ 写降级:积分/埋点异步化或落盘后补
├─ 功能降级:关闭个性化(核心风控除外)
└─ 依赖降级:下游超时熔断,返回兜底值
3. 触发与控制
├─ 自动:错误率/RT/线程池水位
├─ 手动:配置中心一键切换
└─ 硬约束:开关可灰度、可回滚、核心功能白名单
4. 事后
└─ 补数据(积分补发)+ 复盘
口诀:先分级,再降非核心;降体验不降安全;降完要补。【口述骨架】(5 分钟)
| 时间 | 任务 | 内容 |
|---|---|---|
| 0:00–0:30 | 定性 | “降级的前提是业务分级,核心是影响面控制” |
| 0:30–1:30 | P0/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 题——降级后补数据的最终保障
【自测】
- 为什么降级前必须先做业务分级? 参考答案:没有分级,降级变成随机丢弃,可能把转账也降了。P0/P1/P2 是资源紧张时的优先级决策。
- 风控能不能降级? 参考答案:核心风控不可降;非核心风控可降但需审批+白名单+事后加强审计。降级降体验不降安全。
- 降级后为什么要补数据? 参考答案:积分少了是投诉,埋点丢了是数据缺口。降级是临时手段,业务语义必须最终完整。
218. 跨行转账跨 5 个系统,怎么保证钱不错(金融分布式事务)
【考察内容】金融分布式事务方案选型
【题目】一笔跨行转账要经过“本行账户扣款 → 本行记账 → 人行清算系统 → 他行入账 → 结果回执”5 个环节,涉及 5 个系统。请设计事务方案,保证钱不错。
【参考答案】
先明确约束:跨机构转账不能要求全局强一致事务(对方系统不受你控制),只能用最终一致 + 对账;
本行内部(可控部分):主路径要按题干的「5 个系统」来答——扣款与记账分属两个系统,跨服务只能 TCC;「用本地事务保证原子」只是特例(当且仅当两者同库同事务时最省,成本最低),答题要先说明这个前提再提它,别把它当通用方案;跨服务用 TCC——Try(冻结额度)→ Confirm(实际扣减 + 记账)→ Cancel(解冻)。资金类场景 TCC 比 Saga 更合适,因为冻结机制天然防止“钱花了但没转出去”;或用本地消息表 + MQ;
跨机构(不可控部分):状态机驱动——转账单有明确状态(已受理 → 已发出 → 对方已入账 → 已完成 / 已退回),每个环节幂等推进;超时未收到回执 → 进入查询-重试-冲正流程;长时间未确认 → 挂起并进人工处理队列;
最终兜底:日终对账——与人行清算系统、他行逐笔核对;不平的进差错处理流程;
关键细节:全链路唯一业务流水号贯穿 5 个系统;每步操作幂等;资金冻结有超时自动解冻。
容量估算: 跨行转账跨系统:典型状态机(受理→人行/网联→账务→通知)。超时与对账窗口:人行支付系统运行时段外只能预约。分布式事务不选 2PC 打满所有系统,金融常用本地事务+消息+对账+差错处理。峰值按代发工资日、节假日前后估算。
失败与降级: 中间机构失败:转账挂起进“处理中”,禁止自动重复扣款;超时未明确结果的查询状态接口+人工/自动查询查复。账务系统以“最终账”为准,渠道结果靠对账补齐。客户侧要展示明确处理中状态,避免投诉升级。
【原理溯源】
- 为什么跨机构不能用 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 题(金融级幂等)——状态机每步幂等
【自测】
- 为什么跨机构不能用强一致事务? 参考答案:对方系统不受控,无法协调提交/回滚;技术上不可行,组织上也不允许。只能接口协议+对账。
- 为什么资金场景 TCC 比 Saga 好? 参考答案:TCC 的 Try 只冻结不扣减,Cancel 失败可重试+超时自动解冻,资金不悬空;Saga 先扣再补偿,补偿失败则资金悬空。
- 日终对账为什么是必须的? 参考答案:运行时机制(TCC/状态机/重试)都可能失效;对账是独立于运行时的最终防线,发现一切差异并走差错处理。
219. 日终对账发现账不平(对账与差错处理)
【考察内容】对账体系设计 + 差错处理流程
【题目】每天凌晨做日终对账,发现本行流水与清算系统有 3 笔金额对不上。请说明对账系统怎么设计,以及发现不平后如何处理。
【参考答案】
对账体系设计:数据来源为本方交易流水(业务库)+ 对方对账文件(人行 / 银联 / 他行);对账分两层——总账对账(总额、总笔数)→ 明细对账(逐笔比对,以业务流水号 / 清算流水号为键);差异分三类——本方有对方无(长款)、对方有本方无(短款)、双方都有但金额不一致(口径先说清:本库按支付行业惯例「我方有、对方无=长款」;银行柜面现金口径是「实际>账面=长款」,两者字面相反,面试先报口径);时效上 T+1 日终批量为主,重要业务可做准实时对账(分钟级);工程上用分片并行 + 哈希分桶比对,对账结果落库留痕、支持追溯;
发现不平后的处理流程(差错处理):自动分类(按差异类型和金额阈值分流)→ 自动处理(明显的挂账 / 重复记账可自动冲正;小额差异按规则自动调账)→ 人工介入(金额超阈值或类型不明的进人工队列,需双人复核)→ 闭环(每笔差错有处理状态、处理人、处理时间、处理结果,全部留痕);
防复发:差异归因分析 → 修复根因(如幂等漏洞、超时未回执)→ 补监控规则;
监控:对账不平率、未处理差错数、超时未闭环数作为核心指标告警。
容量估算: 日终对账:流水量×比对算法成本;先哈希聚合再 diff 可降复杂度。差错率经验:正常应 <0.01%,突增必查。差错处理 SLA:当日发现当日挂账,T+1 内人工清理。存储:对账文件与结果按监管年限留存。
失败与降级: 对账系统挂了:不能“假装平账”,要告警并人工抽对;核心入账不依赖对账系统实时可用(对账是事后控制)。发现不平:冻结可疑差错资金分录,按制度调账,保留审计轨迹。
【原理溯源】
- 为什么对账要分“总账”和“明细”两层? 总账对账(总额、总笔数)先跑,秒级判断“有没有问题”;但总账平推不出明细没问题:等额一长一短、串户(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 题——差错处理留痕的合规要求
【自测】
- 为什么对账要分总账和明细两层? 参考答案:总账(总额+总笔数)秒级快速筛查;不平再跑明细逐笔定位。分层降本,亿级流水全量比对代价高。
- 三类差异分别怎么处理? 参考答案:长款(我有他无)查我方是否重复;短款(他有我无)查我方是否漏记;金额不一致查哪边对、是否部分成功。
- 为什么调账本身也要留痕? 参考答案:调账是资金操作,与交易同等重要。谁调的、依据什么、审批记录都要可追溯,否则调账可能成为掩盖问题的通道。
220. 监管要求数据可追溯(审计留痕与等保合规)
【考察内容】审计日志设计 + 等保 2.0 / 个保法合规
【题目】监管检查要求:任何一笔数据变更都能追溯到“谁、什么时候、改了什么、为什么改”。请设计审计留痕方案,并说明等保 2.0 和个保法对系统有哪些硬性要求。
【参考答案】
审计留痕设计:
- 记录要素:操作人(账号 + 角色 + IP + 设备)、时间(精确到毫秒)、操作类型、对象(表 / 记录 ID)、变更前后值(diff)、事由(工单号 / 审批单号)、结果(成功 / 失败);
- 覆盖范围:所有敏感数据的增删改查,尤其是“查询”——金融行业“谁看了客户信息”同样要留痕;
- 实现方式:应用层 AOP / 拦截器统一埋点(避免业务代码各写各的);数据库层 binlog 解析作为独立第二来源,与应用层日志交叉校验(防止应用层日志被篡改或漏记)——但 binlog 只记数据变更、不记 SELECT:本块【原理溯源】自己认定最大风险之一是「内部人员批量查询客户信息后倒卖」,这类只读行为在 binlog 里完全无痕迹,等于查询留痕只有应用层一个来源,DBA 直连与运维通道更是空白。必须再补一条独立来源:数据库全 SQL 审计(MySQL audit log / Percona audit / 代理层记录 SQL+来源账号+客户端 IP)+禁止绕过访问网关直连库,才真的做到「查询也可追溯」;日志写入独立的审计库,与业务库物理隔离;
- 不可篡改:日志只追加不修改、独立权限,必要时做哈希链 / 区块链存证;
- 留存期限:金融行业通常 ≥ 5 年(按监管要求,部分业务更长);
等保 2.0 相关要求:身份鉴别(双因子)、访问控制(最小权限)、安全审计(上面这套)、入侵防范、数据完整性与保密性(加密 + 校验)、个人信息保护;
个保法相关要求:告知同意、最小必要、目的限定、可删除(被遗忘权)、跨境传输限制、个人信息处理记录;
落地要点:日志本身也要脱敏(不能把明文身份证写进审计日志)、审计日志的查阅本身也要留痕、定期做合规自查与演练。
容量估算: 审计日志量:关键操作全量,查询类可采样+风险触发全量。存储:日增×保留年限(等保/金融常见数年),冷热分层。防篡改:只追加存储、哈希链、异地备份。审计查询接口性能要与生产库隔离,避免审计拖垮业务。
失败与降级: 审计写入失败:金融场景通常 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 题(容灾与演练)
【自测】
- 为什么审计日志不能和业务库放在一起? 参考答案: 同库同权限意味着拿到业务权限就能改日志抹痕,审计失去“不可否认”的价值。必须独立存储 + 独立权限。
- 判断:只记录数据的“增删改”就够了,查询不需要记录。 参考答案: 错。内部人员批量查询客户信息后倒卖是金融业高发风险,只记改不记查就抓不到。查询必须留痕。
- 什么是 append-only + 哈希链?它解决什么问题? 参考答案: 日志只追加不修改,每条日志包含上一条的哈希形成链。任何一条被篡改都会导致后续哈希不匹配、链断裂即可发现——解决“日志被篡改后无法察觉”的问题。
221. 核心系统要迁到信创数据库(信创适配与迁移)
【考察内容】国产化替代方案 + 迁移风险控制
【题目】行里要求核心系统从 Oracle 迁移到国产数据库(信创要求),业务不能停,数据不能丢。请给出迁移方案。
【参考答案】
先做兼容性评估:语法差异(存储过程、函数、序列、分页语法、数据类型、隐式转换);性能特征差异(执行计划、索引策略、并发模型、锁机制);周边生态(驱动、连接池、ORM 框架、监控工具、备份工具);输出改造清单与工作量评估;
分阶段迁移(不能一步到位):外围先行(先把非核心系统如报表、查询、日志迁过去,积累经验、验证工具链)→ 双轨并行(核心系统双写 / 双跑,新旧库同时写,定期比对一致性)→ 灰度切流(按业务模块或用户分桶,先切读流量再切写流量)→ 回滚预案(保留旧库可回切,明确回滚触发条件与操作步骤);
数据迁移:全量 + 增量(停写窗口用增量追平);迁移后做逐表行数 + 抽样内容 + 校验和三重比对;
性能验证:用生产流量回放做压测,对比新旧库的 RT / QPS / 资源占用;针对慢 SQL 做专项优化;
上线后:双跑期监控数据一致性、性能指标、错误日志;逐步关停旧库。
容量估算(迁移): 信创迁移工作量≈对象数量(表/存储过程/视图/作业)×兼容改造系数。数据迁移窗口=数据量/迁移工具吞吐(全量+增量追平)。双跑期建议至少 1–2 个完整业务周期(含日终、月末)。性能基线:迁移后核心接口 RT 不劣化 >10%。
失败与降级: 迁移失败回退源库(必须演练过);双写期以源库为准。新库异常时按功能开关切回。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 题(遗留系统)——渐进式改造的方法论
【自测】
- 为什么信创迁移要“外围先行”? 参考答案:外围系统业务影响小、出错可回退,是验证工具链和积累经验的安全沙盒。直接上核心系统风险不可控。
- 双写比对发现不一致怎么办? 参考答案:以旧库为准,新库异步修正;定时比对+差异自动修复;切流前必须比对一致。不一致率超阈值暂停推进。
- 为什么存储过程要改写到应用层? 参考答案:存储过程是数据库方言重灾区,改写到应用层后逻辑与数据库解耦,长期更可维护、可测试,消除对方言的长期依赖。
222. 同城机房故障业务不能中断(同城双活与两地三中心)
【考察内容】容灾架构设计 + RTO / RPO 指标
【题目】行里要求核心系统达到“同城双活、两地三中心”标准,任一同城机房整体故障时业务不中断。请设计容灾架构并说明关键指标。
【参考答案】
先明确两个指标:RTO(恢复时间目标)——机房故障到业务恢复的时间,同城双活要求 RTO ≈ 0(秒级切流);RPO(恢复点目标)——允许丢失的数据量,核心账务要求 RPO = 0(不能丢数据);
架构设计:同城双活——两个同城机房同时承载流量,应用层无状态、通过 DNS / GSLB 做流量调度,数据库用强同步复制(多数派提交)保证 RPO = 0;两地三中心——同城双活(生产)+ 异地灾备中心(数据异步复制),用于应对城市级灾难,异地中心 RPO 可放宽(分钟级),RTO 数十分钟——放宽到什么程度必须先由业务/监管定口径,两种答法要分开:① 若核心账务要求任何灾难档位都 RPO=0(本块【原理溯源】正是论证「丢一笔已确认转账=资金差错」),那异地也必须同步/半同步+第三仲裁点,代价是每笔写入多一次跨城 RTT(几十 ms)且跨城抖动会直接拖累交易,通常要靠「单元化+同单元内同步」把跨城写降到可接受;② 若允许城市级 RPO 分钟级,则异步复制即可,但必须书面确认该口径已获批准,并配「切换后按对账与差错处理补齐未同步交易」的流程(客户侧表现为「已扣款未到账」的待补偿状态,要有客服与监管报备口径)。答题先给口径归属(业务方/监管),再给架构;单元化 / 多活——把流量按用户维度切分成多个单元,单元内闭环,单元间不互相依赖,避免故障扩散;
关键技术点:流量调度(DNS / GSLB 健康检查 + 秒级切流,客户端多 IP 兜底);数据同步(强同步 + 异步分级);配置与发布(多机房配置一致性与灰度发布);依赖治理(避免跨机房同步调用,会放大延迟和故障面);
演练:定期做真实切流演练(不是纸上推演),验证 RTO / RPO 是否达标,暴露问题并整改。
容量估算: 两地三中心:同城双活常态各承担约 50% 流量(两侧相加不超过 100%),容量按任一侧可独扛 100% 预留。RPO/RTO 目标金融核心常 RPO≈0(同步复制)、同城秒级切流、异地灾备 RTO 数十分钟(分钟级异地要额外具备流量预热与自动切换能力,不是标配),两个指标不要混写。数据同步链路带宽≥峰值写入×冗余。演练频率按本题【关键数字】表「每季度至少 1 次」执行,年度另做一次全链路切换演练并留实测 RTO。
失败与降级: 机房级故障:自动/半自动切流;应用无状态+数据层同步是前提。切流期间限流防幸存机房被打爆。跨机房分布式事务要降级为单机房主,避免脑裂。
【原理溯源】
- 为什么核心账务要求 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,异地灾备防城市级灾难,演练验证达标” |
【关键数字】
| 参数 | 经验值 | 说明 |
|---|---|---|
| 核心账务 RPO | 0 | 强同步复制 |
| 核心账务 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 题——容灾演练发现问题后的整改
【自测】
- RTO 和 RPO 分别是什么?核心账务的目标值是多少? 参考答案:RTO=恢复时间目标,RPO=数据丢失量目标。核心账务:RPO=0(不能丢数据)、RTO≈0(秒级切流)。
- 为什么异地不做双活? 参考答案:跨城延迟高会拖慢写入;网络不稳定时频繁触发 CP 行为。异地做灾备,用 RTO 换同城性能。
- 为什么必须做真实切流演练? 参考答案:纸面 RTO/RPO 是假设值;真实切流才能发现 DNS 生效延迟、健康检查脑裂、数据同步延迟等问题。不演练的容灾是纸上谈兵。
223. 现场分析一段 GC 日志(日志分析实战)
【考察内容】JVM 日志解读与问题定位
【题目】给你一段线上 GC 日志(或:某城商行面试要求现场分析 GC 日志),请说出你从日志里能看出什么问题,以及下一步怎么排查。
【参考答案】
看日志先抓四个信息:GC 类型(Young GC / Full GC,用的哪种收集器);频率(单位时间 GC 次数,如 Full GC 每 2 分钟一次即异常;本库统一危险线为“≥每 5 分钟 1 次”);耗时(单次 STW 时长,如 Young GC 50ms 正常,Full GC 1s+ 会明显影响 RT);回收效果(GC 前后堆占用,如 Full GC 后老年代只降了 5% → 大概率内存泄漏);
典型异常模式与判断:Full GC 频繁 + 回收效果差 → 内存泄漏或老年代对象增长过快;Young GC 频繁且耗时短 → 新生代太小或对象分配速率过高;单次 GC 耗时突增 → 大对象 / 大数组、或堆太大导致标记耗时长;
promotion failed/concurrent mode failure→ 晋升失败 / CMS 并发失败,需调 Survivor 比例或换收集器;下一步排查:加
-XX:+HeapDumpOnOutOfMemoryError或手动jmap -dump拿堆快照,用 MAT / JProfiler 分析支配树找大对象;jstat -gcutil <pid> 1000持续观察;结合业务日志定位是哪个功能在大量创建对象;处置:先止血(扩容 / 重启 / 限流),再根治(修代码里的内存泄漏、调 JVM 参数、必要时换 G1 / ZGC)。
容量估算(日志分析实战): 看懂关键字段:
[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 少且可控。失败与降级: 日志分析同时业务不能停:先限流/扩容争取时间。若分析指向泄漏且无法快修:摘非核心、扩堆、安排发布窗口。把 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 问题在切流演练中可能暴露
【自测】
- GC 日志分析的四个维度是什么? 参考答案:类型(Young/Full)、频率(单位时间次数)、耗时(单次 STW)、回收效果(GC 前后堆占用变化)。
- Full GC 后老年代只降 5% 说明什么? 参考答案:大部分对象存活,典型内存泄漏。要拿堆快照找持有引用的对象。
- 换 G1/ZGC 能解决内存泄漏吗? 参考答案:不能。新收集器改善 STW 时长,不解决对象无法释放的问题。泄漏必须改代码。
224. 现场画出 Spring Bean 的生命周期(Spring 原理)
【考察内容】Spring IoC 容器核心原理
【题目】请画出 / 说出 Spring Bean 的完整生命周期,并说明各阶段的作用。(某国有银行面试原题:现场绘制 Spring Bean 生命周期流程图。)
【参考答案】
实例化前:BeanDefinition 加载(扫描 / 解析配置,注册 BeanDefinition)→ BeanFactoryPostProcessor(在 Bean 实例化之前修改 BeanDefinition,如
PropertySourcesPlaceholderConfigurer处理${}占位符);实例化与初始化:
- 实例化(
createBeanInstance):反射 / 工厂方法创建对象(此时对象还没注入属性); - 属性填充(
populateBean):依赖注入(@Autowired/@Value); - Aware 接口回调:
BeanNameAware→BeanFactoryAware→ApplicationContextAware(按顺序注入容器相关对象); - BeanPostProcessor 前置(
postProcessBeforeInitialization):如@PostConstruct就是在这里被CommonAnnotationBeanPostProcessor处理的; - 初始化:
InitializingBean.afterPropertiesSet()→ 自定义init-method; - BeanPostProcessor 后置(
postProcessAfterInitialization):AOP 代理就是在这一步生成的(AbstractAutoProxyCreator返回代理对象);
- 实例化(
使用与销毁:Bean 就绪,放入单例池(
singletonObjects)供使用;容器关闭时DisposableBean.destroy()→ 自定义destroy-method;补充要点:循环依赖——Spring 通过三级缓存解决单例的字段注入循环依赖(
singletonObjects一级、earlySingletonObjects二级、singletonFactories三级);构造器注入的循环依赖无法解决。AOP 代理时机——在 BeanPostProcessor 后置阶段生成,所以注入到其他 Bean 里的是代理对象。容量估算与要点: Spring Bean 生命周期作图必须包含:实例化 → 属性注入 → Aware → BeanPostProcessor#before → InitializingBean/init-method → after → 使用 → 销毁回调。循环依赖三级缓存只解决 setter 注入的单例,构造器循环仍会失败。启动慢时对应:扫描范围、条件装配、懒加载、Bean 数量。
失败与降级: 生产启动失败:保留完整启动日志与 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 题——框架层兼容性问题
【自测】
- Spring Bean 生命周期的主线是什么? 参考答案:BeanDefinition 加载→实例化→属性填充→Aware 回调→BPP 前置→初始化→BPP 后置→使用→销毁。
- AOP 代理在哪个阶段生成?为什么? 参考答案:BPP 后置(postProcessAfterInitialization)。因为需要在 Bean 完全初始化后才能创建代理,这里返回代理对象,后续使用者拿到的都是代理。
- 为什么构造器注入的循环依赖无法解决? 参考答案:构造器注入时 Bean 还没实例化完成,无法提前暴露引用。字段/Setter 注入可以在实例化后暴露早期引用。
225. 生产库 CPU 100%,客户无法转账(金融应急)
【考察内容】线上应急流程 + 数据库层排查
【题目】下午 3 点(业务高峰),监控告警核心数据库 CPU 持续 100%,转账接口大面积超时,客户无法转账。作为值班工程师,你怎么处理?
【参考答案】
先止损,后定位(金融场景第一原则:业务优先):立即拉应急群,同步业务 / 客服 / 运维,启动应急预案;若确认为异常 SQL 或异常流量,先 kill 掉问题 SQL / 限流问题来源(如封禁异常 IP / 关闭异常功能开关),先恢复业务;若有备用链路(只读库、备用机房),按预案切流;
定位(与止损并行):
top -Hp <pid>找到高 CPU 的线程 →printf "%x\n" <tid>转十六进制 →jstack <pid> | grep <hex>定位到具体代码;数据库侧SHOW PROCESSLIST看当前慢查询与会话,SHOW ENGINE INNODB STATUS看锁等待;慢查询日志 / APM 链路追踪定位是哪条 SQL、哪个上游服务;检查是否有全表扫描、缺索引、大事务、锁冲突、突发流量、定时任务撞车;常见根因与处置:慢 SQL / 缺索引 → 加索引(注意在线 DDL 的锁影响)或改写 SQL;大事务 / 批量任务撞上业务高峰 → 暂停任务,改到低峰执行;突发流量 / 爬虫 / 攻击 → 限流 + 封禁;锁冲突 / 死锁 → 找到持锁会话,必要时 kill 并回滚;连接池打满 → 扩容连接池 + 排查连接泄漏;
收尾:确认业务恢复 → 数据一致性校验(有没有少记 / 重复记账)→ 复盘 → 补监控与预案。
容量估算(应急): 生产库 CPU 100%:先看是 SQL、锁等待、连接打满还是备份/DDL。金融应急时限:对外公告时限、系统切换时限要有制度数字。限流将 DB QPS 压回安全水位(如峰值 60%)。杀会话权限与双人复核。
失败与降级: 立即保护核心转账:非核心查询/报表停掉;从库/只读接口降级;必要时切备库(数据新鲜度确认)。客户侧排队提示优于失败报错。全过程操作留痕,事后给监管可读报告。
【原理溯源】
- 为什么金融应急是“先止损,后定位”? 业务高峰期每分钟都有大量转账在排队,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 题——应急后数据校验的兜底
【自测】
- 金融应急的第一原则是什么? 参考答案:先止损后定位,业务优先。先恢复业务(kill SQL/限流/切流),再定位根因。
- 为什么 kill SQL 前要确认影响面? 参考答案:kill 会回滚事务。资金类事务可能已部分成功,盲目 kill 可能造成数据不一致。
- 为什么收尾要做数据一致性校验? 参考答案:应急过程中可能有事务被 kill、超时重试、降级返回,都可能造成资金差错。必须校验少记/重复记/金额错误。
226. 系统突然无法转账,客户投诉,你怎么办(情景题)
【考察内容】应急沟通 + 流程意识(国企综合面试高频)
【题目】系统突然无法转账,客户在网点闹起来了,领导让你去处理。你怎么办?
【参考答案】
第一时间:止损 + 上报(并行)——立刻联系技术团队确认故障范围与预估恢复时间;按故障分级上报,不隐瞒、不拖延(金融行业最忌“捂盖子”);
安抚客户 + 给出确定性信息——对客户诚恳说明情况,给出明确的时间预期(“预计 30 分钟内恢复”),提供替代方案(柜台手工处理、引导至其他渠道);避免说“不知道”“不关我事”,也避免过度承诺;
协同处置——与技术、运维、客服、业务部门拉通,明确谁对外、谁对内;记录客户诉求与联系方式,恢复后主动回访;
事后:复盘 + 改进——分析根因、评估影响面(涉及多少客户、多少笔、有无资金差错);修复问题、补监控与预案;对受影响的客户主动补偿或解释。
容量估算(情景应对): “无法转账”分诊:全渠道 vs 单渠道;全客户 vs 部分;有报错 vs 超时。影响面数字:失败笔数、涉及客户数、资金是否在途。内部升级路径时间盒:5 分钟技术定位、15 分钟业务通报、30 分钟对外口径。
失败与降级: 先保资金安全:在途交易状态优先澄清;暂停可疑自动重试。渠道故障则切备用通道或引导延后。客服话术与技术状态同步,避免口径不一。
【原理溯源】
- 为什么“止损与上报并行”而不是先修好再上报? 金融行业最忌“捂盖子”。故障瞒不住——客户在闹、网点在投诉,拖延上报只会让领导从其他渠道得知,被动挨打。主动上报体现责任心,也便于协调资源(备用方案、客户话术、监管沟通)。不隐瞒是金融从业者的底线。
- 为什么对客户要给“确定性信息”而不是说“正在处理”? “正在处理”是空话,客户不知道要等多久,焦虑会升级。“预计 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 题——故障后资金差错的兜底
【自测】
- 情景题的五步结构是什么? 参考答案:止损→上报→安抚→协同→复盘。
- 为什么不能说“不知道”? 参考答案:客户需要确定性信息。说“不知道”会让焦虑升级;给明确时间预期(即使保守)+替代方案,才能安抚。
- 故障是自己代码引起的,怎么办? 参考答案:第一时间如实上报,不隐瞒;先配合恢复业务;责任认定和复盘放事后。隐瞒的代价远大于承认。
227. 发现明文存储密码,但领导说“暂时没出事”(情景题)
【考察内容】合规意识 + 推动能力(国企综合面试高频)
【题目】你在代码审查中发现某个老系统把用户密码明文存在数据库里。你向领导反映,领导说“这个系统跑了十年了,暂时也没出事,先别动”。你怎么办?
【参考答案】
先把风险说清楚(用合规语言,不用技术语言):这是等保 2.0 与个保法的明确不合规项,不是“有没有出事”的问题,而是“检查到了就是问题”;一旦泄露,影响的是全部存量用户,且属于监管通报级别的事件;给出量化影响——涉及多少用户、可能的处罚与舆情后果;
给出可落地的低成本方案(不只提问题,要给方案):分层整改——新用户 / 新密码立即改为加盐哈希,存量用户走“下次登录时静默升级”(登录校验通过后用哈希覆盖原值),不需要停机、不需要强制改密——但静默升级只覆盖「还会登录」的账号:十年老系统里休眠/僵尸账号的明文会永久残留,不合规项并未闭合,而强制全员改密又会被业务否掉。所以要再加两条收口:① 收口期限(如连续 12 个月未登录→账号转冻结,激活时强制改密;或到期批量重置+首登强制改密,并按监管口径提前公告);② 可验证的清零指标(
SELECT COUNT(*) FROM user WHERE password NOT LIKE '$2%'必须为 0,即「库里已无明文」可举证),否则无法向检查方证明整改完成;若短期无法改造,先做数据库访问权限收敛 + 加密存储介质 + 加强审计,降低暴露面;留痕 + 推动:把风险说明与整改建议书面提交(邮件 / 工单),形成记录;推动排期,定期跟进;若长期无响应且风险等级高,按公司合规上报渠道升级(如安全部门 / 合规部门);
态度:对事不对人,目标是解决问题而不是追责;同时守住底线——不能因为“领导说先别动”就假装没看见。
容量估算与风险量化: 明文密码风险:撞库成功率、涉及账号数、监管处罚案例。改造成本:哈希加盐(bcrypt/argon2/国密 SM3+盐)迁移方案——登录时透明升级或强制重置。性能:慢哈希故意慢,登录接口 CPU 会涨,要压测并设并发上限。
失败与降级: 领导要求拖延时的底线:书面风险提示留痕;先做访问控制与审计降低泄露面;网关限流撞库。已泄露应对:强制改密、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 题——老系统改造的渐进式方法
【自测】
- 为什么“暂时没出事”不是不整改的理由? 参考答案:明文密码是等保/个保法的明确不合规项,监管检查到了就是问题。合规是底线不是加分项。
- 静默升级具体怎么做? 参考答案:登录时先用旧方式验证;通过后生成哈希覆盖明文。下次登录走哈希比对。不需停机、不需强制改密。
- 领导长期不同意怎么办? 参考答案:书面留痕后按公司合规/安全上报流程升级。这是履行合规义务,也是保护领导和自己。
228. 历史遗留系统有重大风险,没人敢动(情景题)
【考察内容】风险推动 + 渐进式改造思路
【题目】你接手了一个跑了十几年的核心老系统,代码没人看得懂、文档缺失、还有重大安全隐患。但它是核心业务,没人敢动。你怎么办?
【参考答案】
先评估、不冒进:先做风险清单——梳理安全隐患、性能瓶颈、单点、依赖关系,标注严重程度与影响面;建立可观测性——补日志、补监控、补告警,先把“看不见”变成“看得见”(这是所有改造的前提);补最小必要文档——核心链路、关键表、上下游依赖,不追求完整;
划边界:不改核心,先加外壳:在外部加防腐层 / 适配层,把老系统包起来,新功能走新架构,老逻辑保持不动;用绞杀者模式(Strangler Fig)——从外围功能(报表、查询、非核心接口)开始,逐个用新实现替换,逐步缩小老系统边界;
争取资源:用数据说话——故障次数、影响客户数、潜在合规风险、每次救火的工时,形成改造提案;提出分阶段方案(不是“推倒重来”),每阶段有明确收益,降低决策门槛;
守住底线:在改造完成前,对已知重大风险(如明文密码、越权接口)先做低成本缓解(权限收敛、访问审计、加网关拦截);关键操作留痕,出问题时能自证已尽到提示义务。
容量估算(改造排期): 风险打分=可能性×影响;按“每季度消除几个高风险项”定路线图。绞杀者模式新服务承接流量比例阶梯:1%→10%→50%→100%。可观测性投入通常 ROI 最高,优先做。预算:人月估算用接口数量与变更频率。
失败与降级: 改造中老系统仍是生产:任何外壳/适配层故障要能一键切回老入口。新系统 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 题——遗留系统出问题时的应急
【自测】
- 为什么改造前要先补可观测性? 参考答案:没有日志/监控/告警的老系统是黑盒,任何改造都是盲改。补可观测性是把黑盒变灰盒的第一步。
- 绞杀者模式和推倒重写的核心区别是什么? 参考答案:绞杀者模式渐进替换、可回退、业务不中断;推倒重写风险极高且往往失败(第二系统效应)。
- 怎么说服领导投入资源改造? 参考答案:用数据说话(故障次数/客户数/工时/罚款),翻译成业务语言;给分阶段、低风险、有阶段性收益的方案。
说明: 以下为 AI 算法场景专题(AI-01 ~ AI-54),独立于后端 1–228 题编号体系。