京东后端实习一二面面经:Lua 脚本与订单超时关闭
- 轮次
- 一二面
- 结果
- OC
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
一面(技术面)
- 自我介绍。
- 实习中最有挑战的地方是什么?(会顺着你的回答深入追问)
- 你使用过哪些 AI 工具?
- Codex 和 Cursor 有什么区别?
- 使用 AI 工具的时候,你的开发流程是怎样的?
- 你会自己写开发流程吗?Agent 为什么会按照这个流程去做事情?
- 项目中印象最深的点是什么?
- 订单对账怎么做的?
- 订单 id 什么时候生成?
- 为什么使用 Lua 脚本?它有什么特点?
- 场景题:用户下了订单,超过十分钟没有支付,系统要自动关闭这个订单。让你来实现的话,你会用什么技术方案?
- Java 这块你是怎么学习的?什么时候开始学的?
- 反问环节:业务方向与团队里的 AI 实践。
二面(HR 面)
- 实习中最有挑战的地方是什么?你是如何去解决的?解决之后达到了什么样的效果?
- 项目中还有什么比较有挑战、或者让你有成就感的事情?
- 实习生如何培养?多久出结果?(反问)
《参考解析》
订单超时自动关闭:主流方案与取舍。这道题的关键是先说清楚”精度要求有多高”,再选方案:
- 定时任务扫表:用一个调度每分钟扫一次
status=待支付 AND create_time < now-10min的订单。实现最简单、天然幂等(重复扫到也不会重复关),缺点是精度只有分钟级、订单量大时全表扫描压力大(要靠状态加索引并分片)。中小规模业务首选。 - 延迟消息:下单时往 RocketMQ 发一条延迟 10 分钟的消息,消费端收到后查一次订单状态,仍未支付就关闭。精度好、没有轮询,代价是依赖 MQ 的延迟消息能力,且消息可能丢失(要做补偿)。
- Redis 过期 + 延迟队列:把订单号写进 ZSet,score 设为到期时间戳,另一个线程轮询
ZRANGEBYSCORE捞到期订单。也可以用 key 过期事件,但 Redis 的过期通知不保证可靠投递(键被淘汰或实例重启就丢了),生产上一般只作辅助。 - 时间轮:Netty 的
HashedWheelTimer或 Kafka 的时间轮,适合单机内高精度定时,多实例下要配合分片,重启会丢任务。
无论哪种方案,消费时要再查一次订单状态(用户可能刚好在这一刻付款了),关闭动作本身要对状态做 CAS(UPDATE ... WHERE status=待支付),保证幂等。
为什么用 Lua 脚本:Redis 执行 Lua 是单线程原子执行的,脚本内的多条命令不会被其他客户端插队。典型场景是”判断 + 扣减”这类需要原子的复合操作,比如秒杀库存扣减、分布式锁的释放(先比对 value 再删除)、限流计数。如果拆成多条命令从客户端发,中间就会有竞态窗口。它的限制也要知道:脚本不能太长(会阻塞整个实例)、不能在脚本里做耗时操作、集群模式下所有 key 必须在同一个 slot。
订单 id 什么时候生成:常见做法是在下单时就生成,且要保证全局唯一、趋势递增(便于 B+ 树索引写入)。方案有数据库自增段号(号段模式,一次取一批缓存在内存)、雪花算法(时间戳 + 机器号 + 序列号)、Redis INCR。不要用 UUID 做订单主键——无序会导致页分裂、插入性能差。另外要区分”订单号”和”支付流水号”:前者面向业务与用户,后者面向支付渠道,两者不该混用。
订单对账:核心是”三方对平”——本地订单/账务流水、支付渠道的对账文件、以及渠道实时回调三者对齐。工程上做 T+1 批量拉渠道对账文件,按渠道流水号匹配本地记录,把差异分成三类:本地有渠道无(可能是渠道未成功,需冲正)、渠道有本地无(回调丢失,需补单)、金额不一致(要人工介入)。差异结果落表并出报表,重试与告警都要有。
Codex 与 Cursor 的区别:Cursor 是 IDE 形态,强在编辑器内的补全、多文件重构和交互式改代码,人始终在环路里;Codex 一类是任务型 Agent,你给它一个目标,它自己读文件、跑命令、改多处代码直到完成,人在事后 review。面试里更好的答法是落到”我什么场景用哪个”:小步修改、需要看上下文时用 IDE 助手,批量机械改动、跨仓库重构时交任务型 Agent,并且明确说清你会怎么验收它改的东西。