京东日常实习后端一面记录

没有自我介绍环节,全程项目拷打

拼团项目

1. 介绍一下拼团项目

邻家鲜团是一个以社区拼团为基础的自营型电商平台。具体来说:
平台聚焦于线下社区,以生鲜和日用品这些高频、刚需品切入。在社区关系链的基础上,我们引入了社交拼团功能。用户可以作为团长发起拼单,邀请好友参与,也可以作为团员加入其他人的拼团。通过拼团购买,用户可以获得更优惠的价格。
这不仅仅通过价格激励提供了商品的销量和转换率,更重要的是,它利用熟人之间的信任关系,实现了低成本的社交裂变与用户增长。将一次性的交易行为转变为了基于社交互动的持续性消费。

2. 为什么要用拼团,和普通购买有什么区别

见1

3. 比如购买手机,很难拼团成功,你是怎么考虑的

见1

4. 拼团怎么邀请好友

  1. 生成链接:当用户发起拼团(开团)成功后,前端会根据返回的 teamId(队伍ID)和 activityId(活动ID)生成一个唯一的分享链接。
  2. 分享渠道:用户通过微信、朋友圈等社交渠道将链接发送给好友。
  3. 后端支持:后端提供了用于查询当前拼团的进度的接口,实时返回当前拼团的已拼人数和剩余名额。

5. 好友打开拼团链接能看到什么

好友点击链接后,前端会调用后端的查询接口,展示以下信息:

  • 商品信息:商品图片、拼团优惠价、原价。
  • 拼团状态:
    • 进度条:当前人数/目标人数
    • 倒计时:显示拼团的剩余时间
  • 操作按钮:
    • 如果未满员且未过期:显示“立即加入拼团”。
    • 如果已满员:显示“该团已满,我来开个团”。

6. 假如好友点拼团链接,但是只是浏览没组队,会发生什么

  • 无状态浏览:在后端层面,单纯的浏览请求是无状态的查询,不会对数据库中的订单表产生任何写操作,也不会占用库存。
  • 但是为了后续分析转化率,目前项目采用redis的hyperLogLog来记录每一个队伍有多少人浏览,以及每个活动有多少人浏览,这些数据可以用作分析活动的转换率和团长的传播能力。

7. 讲一下项目中用到的Redis原子预占与数据库乐观锁的多级防超卖机制

首先,在缓存层面,我们利用 Redis 的原子自增命令实现了一个“全局叫号机”。每个尝试参与拼团的用户都会先去取一个号。由于 Redis 单线程执行命令的特性,我们不需要加锁就能保证每个用户拿到的号码是唯一且递增的。

其次,为了处理拿到号但后续业务失败的情况,我们引入了错误恢复量机制。每当有请求在后续流程失败,我们不是去回滚叫号机,而是将错误恢复量加 1。
判断逻辑是:只有当用户号码 <= 拼团目标 + 错误恢复量 时,才允许进入数据库层。这相当于动态扩大了准入窗口,补上了之前失败留下的空缺。

此外,当高并发流量瞬间涌入时,Redis 的叫号机可能会瞬间冲得很高。此时,虽然多余的请求被拦截了,但叫号机的值已经远超目标值。我们会选择通过CAS回滚叫号机的号码为target,这样剩余的组队人数就是错误恢复量,来避免有无法利用的空位。

最后,在数据库层面,对于通过了 Redis 校验的请求,我们利用 MySQL 的乐观锁(UPDATE … WHERE lock_count < target)进行最终的库存扣减。数据库的行锁机制会强制串行化并发的更新操作,确保绝对不会发生超卖。

这种Redis 挡住绝大部分流量 + 数据库兜底最终一致性的多级防护架构,既保证了高性能,又确保了数据安全。

8. 假如多个用户同时点击拼团按钮会发生什么

  • 并发请求:假设目标是 5 人团,当前有 3 人,瞬间来了 10 个请求。
  • Redis 层:10 个请求同时执行 INCR,Redis 会依次返回 4, 5, 6, … 13。
  • 拿到 4, 5 的请求:通过校验,进入下一步。
  • 拿到 6-13 的请求:occupy > target 判断为 true,直接返回失败(提示“手慢了”),不会访问数据库,并且将叫号重置为5。
  • DB 层:拿到 4, 5 的两个请求并发执行 UPDATE SQL。数据库会串行化这两个更新操作,确保 lock_count 正确增加。

9. 数据库兜底怎么做的

  1. 如果 Redis 放行了多余请求(例如 Redis 数据丢失),数据库更新条件 lock_count < target_count 会导致更新失败,从而拦截超卖。
  2. 唯一索引约束:
    group_buy_order_list 表中,order_id 是唯一索引,且 biz_id(由 activityId_userId_count 组成)也是用于幂等控制的。如果同一个用户重复提交,数据库会报 DuplicateKeyException,程序捕获后抛出异常。

10. 数据库的行锁怎么用的

当执行 UPDATE group_buy_order ... WHERE team_id = ? 时,MySQL 的 InnoDB 引擎会自动给 team_id 对应的这行记录加上 排他锁(X锁)。

11. 数据库给行上独占锁后可以读吗

可以读,但取决于怎么读:

  • 快照读(Snapshot Read):普通的 SELECT * FROM ... 可以读。InnoDB 利用 MVCC(多版本并发控制)机制,会读取该行记录在加锁之前的历史版本(快照),不会被阻塞。
  • 当前读(Current Read)SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE 不可以读(会被阻塞),必须等待锁释放。

12. 有考虑过Bean的启动顺序吗?假如业务的Bean先起来,但是Redis连接Bean没起来怎么办

  1. 可以使用@DependsOn注解明确业务Bean依赖于redis连接的Bean
  2. 实际上由于业务Bean显式持有了RedisTemplate有显示的依赖关系,所以Spring会自动处理依赖关系。

RAG项目

1. 介绍一下RAG

2. 讲一下怎么做文本切分的

3. 用的什么向量模型

4. 向量检索和你这里使用的混合检索的优劣,你有测试过吗?

5. 你说你的WebSocket是全双工通信,讲一下全双工是什么意思

6. 除了WebSocket你还知道别的全双工通信的方法吗

7. WebSocket你在项目里怎么用的?代码

8. 讲一下为什么你这里需要使用Redis的Bitmap

9. 分片在前端做的还是服务端做的

10. 为什么要用消息队列

11. 服务端怎么判断有没有上传完毕

12. 用户能知道他上传的文档进数据库了吗