后端开发工程师面经合集
完整信息
本篇目录
面试官开口不是自我介绍,是「你这个 92.3% 是怎么算的」。我愣了两秒,就知道今天不好过。
时间:11.03 一面 60min,11.05 二面 85min 结果:二面完进池子
京东这两面给我最大的感受是,他们不聊"Agent 是什么",只聊"你这一个数是怎么来的"。一个数讲不清楚,后面二十分钟全在拆它。
一面:从图片和规则开始
- 自我介绍,说重点。
- 你这个审核系统,输入是什么?纯文本还是带图?
- 一张商品图里同时有文字、logo、水印、二维码,你怎么分别处理?
- OCR 识别错了,比如把"0"认成"O",后面链路会怎么样?
- 你会不会把 OCR 结果直接喂给模型?
- 不喂的话,中间那一层做了什么?
- 图和文冲突:图片写"纯棉",详情写"聚酯纤维",你信谁?
- 这个冲突你自己判过吗?还是靠规则?
- 规则引擎有多少条规则?谁维护?
- 规则之间打架了怎么办?优先级怎么定?
- 新增一条规则,怎么验证不会误伤历史商品?
- 你有没有跑过全量回归?跑一次多久?
- 模型和规则,谁先谁后?为什么这么排?
- 模型判"不确定"的时候,走人工还是走规则?
- 人工审核队列一天多少单?人均处理多少?
- 审核人疲劳之后准确率会掉,你怎么发现?
- 你怎么衡量一个审核人靠不靠谱?
- 误杀一个正常商品,商家损失是什么?你怎么算这个数?
- 漏放一个违规商品,平台损失是什么?
- 这两个损失不对等,你的阈值往哪边偏?
- 阈值 0.8 是谁定的?业务签字了吗?
- 调到 0.9 通过率掉多少?测过吗?
- 92.3% 是准确率还是召回率?分母是什么?
- 测试集多少条?谁标的?标注一致性多少?
- 这个数里有没有把"模型没判、规则兜住了"的算进去?
- 如果把规则那部分剔掉,模型单独多少?
- 你怎么证明提升是你的改动,不是换了模型?
- 商家申诉了,链路怎么走?申诉成功之后数据怎么回流?
- 回流的数据要不要重新标?谁标?
- 反问。
(第 26 题我答不上来。我们线上从来没单独测过模型,一直是整套一起算的。)
二面:往系统底下压
- 一面问了什么,你复盘一下。
- 这个系统的峰值 QPS 多少?什么时候?
- 大促期间量翻三倍,第一个撑不住的是哪?
- 图片上传和审核结果,中间是同步还是异步?
- 异步的话,商家页面显示什么?
- 商家刷新页面,你怎么保证不重复提交一次审核?
- 幂等键怎么设计的?业务单号还是内容哈希?
- 同一张图换了个文件名重传,内容哈希一样吗?
- 幂等记录存多久?存 MySQL 还是 Redis?
- 表数据量到千万级你怎么分?按什么分片?
- 分片键选商家 id 还是时间?各有什么问题?
- 按商家分片,一个大商家把某个分片打爆了怎么办?
- 商品检索你用 ES 吗?索引怎么建的?
- ES 和数据库的一致性怎么保证?
- 双写失败了一半,怎么修?
- 你用 MQ 了吗?哪一步用?
- 消费失败返回什么?返回成功会怎么样?
- 一条消息重复消费,审核结果会不会写两遍?
- 消息积压了先看什么?
- 审核服务线程池参数怎么定的?
- 图片 OCR 是 IO 密集还是 CPU 密集?线程数该往哪边调?
- 你用虚拟线程了吗?为什么没用?
- ThreadLocal 在虚拟线程里有什么问题?
- 线上接口 P99 突然从 200ms 涨到 2s,你怎么排查?
- 怎么区分是下游慢还是自己 GC 了?
- Full GC 频繁你会看哪些指标?
- 缓存命中率多少?怎么算的?
- 命中率掉了但 QPS 没变,可能是什么原因?
- 你给模型加了缓存吗?什么粒度?
- prompt 差一个字缓存就失效,你怎么设计 key?
- 反问。
手撕:按 key 串行、跨 key 并行,还要能取消
题目原话:实现一个执行器 submit(key, task)。相同 key 的任务按提交顺序串行,不同 key 可以并行。加两个条件:任务能被取消,服务关闭时正在排队和正在跑的任务要能优雅收尾,不许丢任务也不许卡死。
这题毒在"优雅收尾"。大多数人写到"每个 key 一个队列 + 一个 worker"就停了,取消和停机一加进来,前面的结构就得重来。
思路:
- 每个 key 一条队列,队列上挂一个"是否已有 worker"的标志,没 worker 才起,避免一个 key 起一堆线程。
- 取消要分两种:还在排队的直接摘掉,正在跑的只能置标志,靠任务自己让出。
- 停机先关入口(不再收新任务),再等队列清空,最后才停线程池。顺序反了就会丢任务。
import threading, queue
from collections import defaultdict
class KeyedExecutor:
def __init__(self, n_workers=8):
self.pool = []
self.lock = threading.Lock()
self.queues = defaultdict(queue.Queue) # key -> 任务队列
self.active = set() # 已有 worker 的 key
self.closed = False
self.running = {} # task_id -> cancel flag
def submit(self, key, task):
with self.lock:
if self.closed:
raise RuntimeError("executor closed")
t = {"id": task.id, "fn": task.run, "cancel": threading.Event()}
self.running[t["id"]] = t["cancel"]
self.queues[key].put(t)
if key not in self.active:
self.active.add(key)
th = threading.Thread(target=self._drain, args=(key,), daemon=True)
self.pool.append(th)
th.start()
return t["id"]
def cancel(self, task_id):
flag = self.running.get(task_id)
if flag:
flag.set() # 正在跑的靠协作式取消
return True
return False
def _drain(self, key):
q = self.queues[key]
while True:
t = q.get()
if t is None: # 停机哨兵
q.task_done()
break
if not t["cancel"].is_set():
try:
t["fn"](cancel_flag=t["cancel"])
except Exception:
pass
self.running.pop(t["id"], None)
q.task_done()
with self.lock:
self.active.discard(key)
def shutdown(self, wait=True):
with self.lock:
self.closed = True # 1. 先关入口
keys = list(self.queues.keys())
for k in keys:
self.queues[k].join() # 2. 等每个 key 排空
for k in keys:
self.queues[k].put(None) # 3. 再放哨兵收 worker
if wait:
for th in self.pool:
th.join(timeout=5)
追问四个:
- 一个 key 堆积了一万条任务,其他 key 会不会被饿死?
- 你用了一个 key 一个线程,key 有几万个的时候怎么办?
cancel只置标志,任务里跑的是一个不带取消语义的第三方库,怎么停?shutdown的时候有任务正好在submit和put之间,会不会漏?
第三个我说"那就停不了,只能等超时"。他说"所以取消这件事得在任务协议层就定好,不是执行器能补的"。
这句我记下来了。
出来之后
京东这两面,我最大的问题不是不会,是没拆过自己的数。
92.3% 写了半年,从来没人问过我分母是什么。真被问到的时候,我才发现自己也不确定。
面完在楼下买了杯咖啡,把项目里所有指标翻出来重新算了一遍。算完出了一身汗。
各位写简历的时候,是不是也有一两个数字自己没拆过?评论区聊聊,我看看是不是只有我这样。
#秋招面试记录# #面试AI岗经常会被问到哪些问题?#
岗位、轮次与题面基于牛客近一周公开面经整理重排,细节有改写与合并,不指向任何具体个人。
本篇目录
当前问题0165
- 01
自我介绍,说重点。
- 02
你这个审核系统,输入是什么?纯文本还是带图?
- 03
一张商品图里同时有文字、logo、水印、二维码,你怎么分别处理?
- 04
OCR 识别错了,比如把"0"认成"O",后面链路会怎么样?
- 05
你会不会把 OCR 结果直接喂给模型?
- 06
不喂的话,中间那一层做了什么?
- 07
图和文冲突:图片写"纯棉",详情写"聚酯纤维",你信谁?
- 08
这个冲突你自己判过吗?还是靠规则?
- 09
规则引擎有多少条规则?谁维护?
- 10
规则之间打架了怎么办?优先级怎么定?
- 11
新增一条规则,怎么验证不会误伤历史商品?
- 12
你有没有跑过全量回归?跑一次多久?
- 13
模型和规则,谁先谁后?为什么这么排?
- 14
模型判"不确定"的时候,走人工还是走规则?
- 15
人工审核队列一天多少单?人均处理多少?
- 16
审核人疲劳之后准确率会掉,你怎么发现?
- 17
你怎么衡量一个审核人靠不靠谱?
- 18
误杀一个正常商品,商家损失是什么?你怎么算这个数?
- 19
漏放一个违规商品,平台损失是什么?
- 20
这两个损失不对等,你的阈值往哪边偏?
- 21
阈值 0.8 是谁定的?业务签字了吗?
- 22
调到 0.9 通过率掉多少?测过吗?
- 23
92.3% 是准确率还是召回率?分母是什么?
- 24
测试集多少条?谁标的?标注一致性多少?
- 25
这个数里有没有把"模型没判、规则兜住了"的算进去?
- 26
如果把规则那部分剔掉,模型单独多少?
- 27
你怎么证明提升是你的改动,不是换了模型?
- 28
商家申诉了,链路怎么走?申诉成功之后数据怎么回流?
- 29
回流的数据要不要重新标?谁标?
- 30
一面问了什么,你复盘一下。
- 31
这个系统的峰值 QPS 多少?什么时候?
- 32
大促期间量翻三倍,第一个撑不住的是哪?
- 33
图片上传和审核结果,中间是同步还是异步?
- 34
异步的话,商家页面显示什么?
- 35
商家刷新页面,你怎么保证不重复提交一次审核?
- 36
幂等键怎么设计的?业务单号还是内容哈希?
- 37
同一张图换了个文件名重传,内容哈希一样吗?
- 38
幂等记录存多久?存 MySQL 还是 Redis?
- 39
表数据量到千万级你怎么分?按什么分片?
- 40
分片键选商家 id 还是时间?各有什么问题?
- 41
按商家分片,一个大商家把某个分片打爆了怎么办?
- 42
商品检索你用 ES 吗?索引怎么建的?
- 43
ES 和数据库的一致性怎么保证?
- 44
双写失败了一半,怎么修?
- 45
你用 MQ 了吗?哪一步用?
- 46
消费失败返回什么?返回成功会怎么样?
- 47
一条消息重复消费,审核结果会不会写两遍?
- 48
消息积压了先看什么?
- 49
审核服务线程池参数怎么定的?
- 50
图片 OCR 是 IO 密集还是 CPU 密集?线程数该往哪边调?
- 51
图片 OCR 是 IO 密集还是 CPU 密集?线程数该往哪边调?
- 52
你用虚拟线程了吗?为什么没用?
- 53
ThreadLocal 在虚拟线程里有什么问题?
- 54
线上接口 P99 突然从 200ms 涨到 2s,你怎么排查?
- 55
怎么区分是下游慢还是自己 GC 了?
- 56
Full GC 频繁你会看哪些指标?
- 57
缓存命中率多少?怎么算的?
- 58
命中率掉了但 QPS 没变,可能是什么原因?
- 59
你给模型加了缓存吗?什么粒度?
- 60
prompt 差一个字缓存就失效,你怎么设计 key?
- 61
实现一个执行器 `submit(key, task)`。相同 key 的任务按提交顺序串行,不同 key 可以并行。加两个条件:任务能被取消,服务关闭时正在排队和正在跑的任务要能优雅收尾,不许丢任务也不许卡死。
- 62
一个 key 堆积了一万条任务,其他 key 会不会被饿死?
- 63
你用了一个 key 一个线程,key 有几万个的时候怎么办?
- 64
`cancel` 只置标志,任务里跑的是一个不带取消语义的第三方库,怎么停?
- 65
`shutdown` 的时候有任务正好在 `submit` 和 `put` 之间,会不会漏?
