简历 preview
简历上 : 支持用户使用微信支付进行文章的打赏功能 以及 用户对账流程
流程设计
需求分析 :
-
用户能够选择一篇文章 通过 微信支付 进行打赏
-
支付成功后 用户能够在自己的余额里面看到扣款 以及 被打赏的金额,同时可以看到对应的流水
模块设计 :
考虑支付是一个通用的模块, 并且支付可以额外对接审计,账号,反洗钱等模块 所以把支付模块单独拆分出来
设计 支付、用户资产、打赏 三个模块
功能分析 :
用户模块支持 :
- 查看业务流水
- 更新用户资产
打赏模块支持 :
- 查看文章打赏记录
- 发起支付请求
支付模块支持 :
- 向第三方发起支付请求
- 接受微信支付的calback
- 查询发起的支付信息

难点 & 亮点
问题 :
微信支付回调后如果成功那么不会在此推送消息, 我们使用 MQ进行通知下游,如果MQ发送失败那么将丢失该信息
方案 :
-
引入 本地消息表
-
使用 本地事务 开启 支付表 和 本地消息表的写入 。 并且设置 消息表 init
-
只有当MQ发送成功之后才会设置 本地表 success 。
-
定时任务 定时轮询 init 的任务进行补偿
问题 :
由于本地消息表的引入, 可能带来重复消费的问题
方案 :
-
在下游账户处理模块, 设置了
biz_id + biz + account + account_type的联合唯一索引 -
并且引入 redis 进行查询优化, 预先判断 redis 的状态
问题 :
可能存在 微信回调消息发送失败, 微信回调只会默认会在 30分钟之后不再回调 不管成功或是失败
方案 :
- 定时任务 定期扫描 超过约30分钟的未完结订单 主动查询微信状态 并写回
问题 :
获取打赏信息的时候 ,我们会先去查询 打赏表的数据,如果打赏表数据还未完成 。会通过慢路径查询支付表的信息进行更新 用于加快状态的轮询。
方案 :
-
考虑限流时候降级, 对于限流的时候不走慢路径
-
在 账户资产更新 MQ 的时候 会一并更新对应的 状态
亮点 :
模块拆分 与 边界 + gRPC
-
支付只关心第三方与支付单状态
-
打赏只关心 业务单和分账意图
-
账户只关心余额与流水
缺点
-
缺少定时自动对账的机制。 涉及
打赏-支付-记帐三个流程 -
在 MQ 更新 账户资产 和 打赏表的时候 。 并不是强一致的, 我们优先更新 打赏表, 如果之后调用 rpc 处理 账户资产失败了 。 那么会发送告警 由人工手动修复
其他细节
支付消息必然发送成功
支付的一个核心步骤是由 微信来回调的 . 我们原先的处理是
-
微信回调
-
更新支付表状态
-
发送消息给 MQ 通知账户变更
如果这里 MQ 发送失败,那么将会丢失这笔消息 。但是支付消息可以认为是一个非常关键的功能 。
所以考虑优化引入了 本地消息表
表结构设计
-
主要字段
content和status -
我们通过 content 记录原有的
MQ信息 使用status维护 MQ 的状态 分为init,success,failed
|
|

流程优化设计 :
-
使用 事务控制 更新 支付表状态 和 写入本地事务表 并且初始化 init
-
只有当我们成功发送 MQ 之后才把 本地事务表设置 success
- 这里可能会造成重复发送
-
开启一个定时任务,批次获取 init 的状态, 然后发送 MQ 消息 。 如果半小时内都发送失败 设置 failed . 发送成功之后设置 success
接口幂等性分析
由于改造了本地事务之后,可能会产生重复消费数据 . 我们在下游 账户更新的时候
通过 redis+ 本地索引来处理 。
我们设置 账户流水表的 唯一索引 biz,biz_id,account,account_type 进行过滤
biz_id 就是 微信回调里面带的 tradeNoId
使用 redis 进行初步过滤 使用 唯一索引进行兜底
打赏详情降级处理
-
我们打赏的时候 会先查询我们打赏表 如果打赏已经是支付状态 会直接返回
-
否则会去查询一遍支付表
对于限速的状态,我们会抛弃这个慢路径。 这条慢路径,由 MQ 进行处理, MQ 会较慢一点时间 更新到支付表的状态 。
|
|
总分:72 / 100
对应 2 年经验中级偏上:系统设计与可靠性意识不错,能讲清主链路和几个关键问题;但深度、闭环和对面试追问的准备还不够稳。
评分拆解
| 维度 | 分数 | 说明 |
|---|---|---|
| 需求与业务理解 | 14/20 | 主流程清楚,但对账、分账、退款几乎空缺 |
| 模块拆分与边界 | 16/20 | 支付 / 打赏 / 账户划分合理,亮点明确 |
| 可靠性设计(消息必达、补偿) | 18/20 | 本地消息表 + 定时补偿是加分项 |
| 幂等与一致性 | 12/20 | 有唯一索引思路,但一致性模型讲得偏浅 |
| 降级与工程细节 | 8/10 | 慢路径 + 限流降级有工程味道 |
| 表达与面试可讲性 | 4/10 | 结构散、术语错误多,容易被追问打穿 |
优点
-
边界意识好
「支付只关心第三方与支付单」「打赏关心业务单」「账户关心余额流水」——这是面试里很吃香的表述,说明做过拆分,不是堆接口。 -
抓住了支付域真难点
微信回调只推一次成功、MQ 可能丢、回调有时效——都点到了,再配本地消息表 + 定时扫 init 补偿,对 2 年经验来说已经超过很多只会 CRUD 的候选人。 -
幂等有兜底思路
biz + biz_id + account + account_type唯一索引 + Redis 前置过滤,主路径对、兜底也对。 -
会主动说缺点
缺自动对账、账户与打赏非强一致靠告警人工修——面试官通常加分,显得务实。 -
有可落地的代码片段
GetReward快慢路径 +limited降级,能证明不是纯理论。
缺点(面试里容易被打穿的点)
-
「对账」名不副实
简历写「对账流程」,正文却写「缺少定时自动对账」。2 年经验可以不做完整对账,但简历与口述必须对齐,否则会被认定夸大。 -
一致性模型说不清
「优先更新打赏表,RPC 失败靠人工」——面试官会问:为何不先账后业务 / 同事务 / Outbox 统一出口?最终一致还是人工一致?超时重试与幂等如何配合?这里准备不足。 -
本地消息表细节偏薄
failed后怎么办?(死信、告警、人工重放)- 发送成功但改 status 失败 → 重复投递,下游如何保证?
- 定时任务并发扫同一批 init 如何防重?
- content 序列化格式、版本兼容?
这些是「本地消息表」题的标配追问。
-
Redis 幂等设计不严谨
「预先判断 Redis 状态」太模糊:key 是什么?TTL?先 Redis 还是先 DB?Redis 挂了怎么办?正确叙事应是:DB 唯一约束是真相,Redis 只是加速,不能单独当幂等源。 -
Golang / 工程深度弱
全文几乎没有:gRPC 超时与重试、context 传递、回调验签、并发安全、事务边界、错误码。2 年 Golang 岗会被追问这些。 -
表达与硬伤
calback、stauts、ctx.Value("limited")(类型不安全、难测)、JSON 伪结构不规范——细节会拉印象分。 -
退款 / 部分失败 / 重复打赏 几乎未覆盖
支付面试常问:重复回调、金额篡改校验、订单超时关单、退款与冲正。
建议(按优先级)
1. 先改简历表述(立刻做)
- 改为:「实现微信支付打赏;用本地消息表保证支付结果可靠投递;账户侧幂等入账」
- 不要写「完整对账」,除非补一版:按日对
支付成功单 vs 账户流水 vs 打赏状态的差异报表 + 告警。
2. 准备一张 2 分钟口述主链路
发起打赏 → 建业务单/支付单 → 微信下单 → 回调验签 → 本地事务写支付状态+Outbox → 发 MQ → 账户幂等入账 → 更新打赏状态;失败靠定时补偿 + 主动查单。
3. 把三个「追问答案」写死
- 为何本地消息表而不是直接依赖微信重试?
- 重复消息如何保证只加一次钱?
- 打赏已成功、账户失败如何发现与修复?(最好从「人工」升级到「对账任务 + 可重放」)
4. 补齐技术细节清单(半页纸即可)
- 回调验签、金额与
out_trade_no校验 - Outbox 状态机:
init → sending → success / failed - 定时任务:分页、
FOR UPDATE SKIP LOCKED或租约,避免多实例抢同一批 - 幂等:先插流水(唯一索引)再改余额;冲突当成功返回
- 主动查单:状态机只允许 Init→Success/Failed,禁止回退
5. 代码展示再打磨
- 限流标记不要用
ctx.Value("limited"),改成明确参数或中间件注入的Limiter/Degrade标志 - 慢路径更新打赏状态时说明:是否只更新、是否再触发入账(避免查询接口变成写副作用)
6. 面试话术升级一句
不要只说「模块拆了」;说:「支付可复用到会员/订单,打赏是支付的一种业务形态,账户是账本,三者用 MQ 最终一致,用唯一键兜底。」
面试官结论
这份材料说明候选人做过真实支付链路,懂拆分和消息可靠性,对 2 年经验够用;但若现场只能复述文档、答不上一致性与对账追问,分数会掉到 60 左右。把「对账诚实化 + Outbox/幂等细节 + 2 分钟口述」补上,冲击 80+ 更稳。