28 届两次面试记录:Java 后端项目拷打与一场全栈面试
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 悦享本地生活服务平台用到限流、秒杀、布隆过滤器,你们的流量、并发大概有多大?
- 布隆过滤器是什么作用,原理是什么?
- 用户量多大,日活有多少?
- SQL 优化这块,是怎么排查数据库问题的?
- 索引是什么?
- 本地事务和分布式事务分别是什么?
- 项目里 Redis 分布式锁解决了什么业务问题?
- JWT 权限认证是什么情况?
- 拦截器和过滤器的区别?
- Redis 里面常用的数据结构都有哪些?
- 接口和抽象类,二者有什么区别?
- List 和 Set 什么情况下用 List?什么情况下用 Set?
《参考解析》
被追问「流量多大、日活多少」时:答量级和来源,别编精确数字。这类问题面试官真正想验证的是你有没有真的跑过这个系统、有没有量化的概念。可用的答法是把口径说清楚:峰值 QPS 与平均 QPS 分别是多少、用户量是注册还是活跃、数据从哪来(监控面板、压测报告、还是日志统计),然后给出一个区间而不是一个虚假的精确值。如果手上确实没有数据,就明确说「当时没有做完整监控,我只能按压测结果和订单量估算大概在 X 量级」,再补一句「如果重做,我会在入口处埋点统计 QPS 与耗时分布」。进一步的追问通常会落到容量与瓶颈:限流阈值怎么定的、秒杀用了什么手段(前置校验、库存预热到 Redis、异步下单、令牌桶或漏桶)、系统在什么量级会先撑不住(数据库连接池、Redis 单线程、还是网络带宽)。回答里带上「怎么测出来的」和「瓶颈在哪」,比背一串漂亮数字更让人信服。
布隆过滤器:位数组加多个哈希函数,用误判率换空间。原理是把元素经 k 个独立哈希映射到位数组的 k 个位置并置 1;查询时如果有一位是 0,则元素一定不存在;如果全为 1,则可能存在(存在误判)。它的空间效率极高(每个元素约 10 bit 就能把误判率压到 1% 左右),代价是不能删除元素、不支持枚举,且误判率随插入量增长而上升。工程用法是放在缓存前面挡穿透:请求先过布隆过滤器,判定不存在就直接返回,避免无效查询打到数据库;需要删除的场景用计数布隆或定期重建(把新数据写到新过滤器,双写一段时间再切换)。答的时候建议给出参数关系——位数组长度 m、元素个数 n、哈希个数 k 满足 k ≈ (m/n)·ln2 时误判率最低,并指出它和布谷鸟过滤器的区别(后者支持删除),这会把答案从「知道名词」拉到「会调参」。
SQL 优化排查:要按固定顺序走,别一上来就说加索引。完整的排查链路是:先确认慢在哪条语句(慢查询日志、performance_schema、APM 里的 SQL 耗时排行),再看执行计划(EXPLAIN 关注 type 是否全表扫描、key 命中了哪个索引、rows 与 filtered 估算、Extra 里有没有 Using filesort 或 Using temporary),然后判断原因属于哪一类:索引缺失或失效(字段上做函数运算、隐式类型转换、前导模糊匹配、违反最左前缀)、索引选错(区分度太低导致优化器放弃)、回表过多(考虑覆盖索引)、数据量太大(分页深翻页用游标或延迟关联)、还是锁等待与连接池耗尽(这类不是语句问题)。索引的本质是排好序的数据结构(InnoDB 是 B+ 树)加指向数据行的引用,它把随机 IO 变成有序查找,代价是占空间并拖慢写入,所以索引不是越多越好。补充一点高频考点:EXPLAIN 的 type 从好到坏大致是 system > const > eq_ref > ref > range > index > ALL,看到 ALL 基本就是全表扫描。
本地事务与分布式事务:先讲清边界,再讲补偿。本地事务是单个数据库连接内的一组操作,靠 undo/redo log 保证 ACID,Spring 的 @Transactional 在同一个数据源下就能覆盖。分布式事务横跨多个数据库或服务,2PC/XA 强一致但同步阻塞、协调者单点,性能差;TCC 把操作拆成 Try-Confirm-Cancel,需要业务自己写三个接口并且要处理空回滚、悬挂、幂等;本地消息表与事务消息(先写本地事务再发消息,靠定时补偿保证最终一致)是互联网场景最常用的方案;Saga 把长事务拆成一串本地事务并定义补偿动作,适合流程长、可容忍中间态的业务。选型判断就一句话:能不能接受最终一致——能,就优先本地消息表或 Saga,避免为了强一致把吞吐拉垮。Redis 分布式锁则要讲清为什么用它(跨进程互斥,比如防止同一订单被重复处理),以及它的坑:加锁要带唯一 value、解锁要校验 value 并做成原子操作(Lua)、必须有超时兜底、锁过期而业务没跑完时需要看门狗续期,强一致场景应该用 Redlock 之外的方案(如基于数据库或 ZooKeeper)。
Java 基础三连:JWT、拦截器与过滤器、接口与抽象类、List 与 Set。 JWT 是自包含的令牌,由头部、载荷、签名三部分组成,服务端用密钥验签即可解析身份,好处是无状态、跨服务方便,代价是无法主动失效(只能靠短过期时间加刷新令牌或黑名单)、载荷仅做 Base64 编码不能放敏感信息,且要用强密钥并校验算法字段防止算法混淆攻击。拦截器与过滤器分属两层:Filter 是 Servlet 规范的一部分,在请求进入 Servlet 之前生效,能拿到原始 HttpServletRequest,适合做编码、跨域、日志、鉴权粗筛;Interceptor 属于 Spring MVC,能拿到 HandlerMethod,适合做细粒度鉴权、参数校验与统一响应包装,两者的执行顺序是 Filter → Interceptor → Controller。接口与抽象类的区别在于:接口是行为契约,可多实现、只声明(Java 8 起有默认方法与静态方法)、字段隐式 public static final;抽象类是模板,单继承,可有构造器、成员变量与部分实现,适合复用公共逻辑。List 与 Set 的选择看是否需要顺序与重复:List 有序可重复、支持按下标访问(ArrayList 随机访问快,LinkedList 头尾增删快),Set 元素唯一(HashSet 靠哈希去重、无序,LinkedHashSet 保插入序,TreeSet 有序但 O(log n)),去重与判重优先 Set,需要保序与索引就用 List。
复盘建议:简历决定了提问范围,第二场面试要主动控场。第一场问题几乎全从简历上的项目出发,说明面试官是「按你写的挖」,所以简历里出现的每个技术名词都要能讲三层——为什么用、怎么实现的、遇到什么问题怎么处理;写了却讲不清的,反而会成为失分点,不如不写。第二场是线下全栈面,形式更像沟通:自我介绍加 HR 介绍业务后问你的想法,这种场景要提前准备一段一百字左右的自我介绍(专业背景、最有代表性的一段经历、为什么投这个方向)和两三个反问(团队在做什么、这个岗位的成长路径、技术栈与协作方式),否则很容易聊不到十分钟就结束。另外面试场地与形式(HR 办公室、临时安排)说明这可能是小团队或初创,正规性不是唯一判断标准,但可以在反问环节确认团队规模、汇报关系与业务阶段,用来判断这个机会值不值得去,同时避免「没有下文」时无从复盘。