
电商场景Java面试从JVM到Kafka谢飞机与严肃面试官的3轮交锋“谢飞机这是你的面试官王总。王总在大厂带了八年后端出了名的严肃。”HR小姐姐说完就关上了门。谢飞机搓了搓手咧嘴一笑“王总好我是谢飞机写Java写了三年主要搞电商。”王总扶了扶眼镜没有寒暄直接翻开简历“那我们开始吧。先聊点基础的。”第一轮项目热身与Java核心王总“你说你做了三年电商具体负责哪些模块技术栈怎么选型”谢飞机“就商品、订单、库存那套。Spring Boot MySQL Redis然后……写接口嘛CRUD一把梭。”王总眼角抽了一下“你们订单表数据量大了怎么处理”谢飞机“分库分表……吧我们没用过听说ShardingSphere挺火的。”王总没追问转向下一个问题“JVM内存模型了解吗垃圾回收算法有哪些”谢飞机“JVM内存分堆和栈堆里有新生代老年代方法区……垃圾回收就是GC回收垃圾对象算法有复制、标记清除、标记整理……好像是这样的吧。。”王总“具体讲讲GC Roots”谢飞机“GC Root……嗯……就像树的根从根上遍历够不到的就是垃圾。大概是这样吧。”王总沉默两秒换了个问题“那HashMap底层数据结构说一下。”谢飞机眼睛一亮“这个熟JDK 8之后数组链表红黑树。默认容量16负载因子0.75。当链表长度超过8并且数组长度超过64就转红黑树。put的时候先算hash找桶冲突了链尾插入查询复杂度O(1)最佳最差O(logn)。”王总微微点头“不错基础还可以。再聊聊Spring Boot自动配置原理。”谢飞机“自动配置……就是EnableAutoConfiguration注解从META-INF/spring.factories加载一堆AutoConfiguration类根据条件注解如ConditionalOnMissingBean生效。我平时用的时候确实没怎么配RedisTemplate。”王总“好第一轮差不多。下面问点实际的业务场景。”第二轮电商业务与缓存、并发王总“你们做商品列表页QPS上来了怎么防缓存穿透、击穿、雪崩”谢飞机“这个我熟缓存空值防穿透热点key加互斥锁防击穿过期时间加随机数防雪崩。我们当时就是Redis缓存然后设置过期时间随机查不到就查DB。”王总“那你怎么保证Redis和数据库的数据一致性比如更新库存时。”谢飞机“呃……我们的做法是先更新数据库然后删除缓存然后过一会再做延迟双删好像是。但有时候还是会不一致后来我们也没管了反正数据最终一致。”王总“最终一致那你倒是说说怎么个最终法”谢飞机“就……过段时间它就一致了。用消息队列补偿不过我们没做那么细。”王总没有继续计较抛出一个经典问题“那在下单扣减库存时如何防止超卖”谢飞机“哦我们用了synchronized把方法锁了就不会超卖了。”王总“如果多台机器呢多个Tomcat实例同时执行呢”谢飞机“啊多台机器啊……那synchronized只能锁一个JVM啊……那……那用分布式锁用Redis的setnx嗯……好像有这么个东西。”王总“再往下问你项目里遇到性能问题怎么排查”谢飞机“先看日志搜Exception再看Redis慢查询MySQL慢SQL。然后……然后我就交给运维了。通常重启一下就好了。”王总深吸一口气“好。我们进入第三轮。”第三轮消息、安全与云原生王总“你们订单系统用Kafka怎么保证消息不丢失”谢飞机“Kafka有acksall生产者等所有副本都确认然后消费者关闭自动提交手动提交offset。但是……如果处理完业务提交offset之前挂了会导致重复消费。”王总“重复消费怎么解决”谢飞机“消费端幂等呗。用Redis setnx或者数据库唯一约束。不过我们当时好像没做所以偶尔订单会重复。”王总微微皱眉“好那微服务之间调用怎么做链路追踪”谢飞机“链路追踪……听说过Sleuth和Zipkin。就是每个请求生成一个traceId然后传到下游服务在日志里串起来。但我们项目还没上我是看博客说的大概。”王总“如果Redis集群突然全部宕机你们的电商系统会怎么样”谢飞机“全部宕机那……那我们就直接挂了啊用户打开页面白屏下单接口全报错。”王总“有没有想过降级方案本地缓存兜底”谢飞机“本地缓存……好像可以用Caffeine。但没实际配过应该能撑一会儿吧。”王总“说说JWT无状态登录的原理。”谢飞机“这个我知道用户登录成功后服务端生成一个JWT里面有header、payload、signature三部分。之后前端每次请求把JWT放在Authorization头里服务端只验签不存session天然适合分布式。”王总“JWT密钥怎么管理遇到秘钥泄露怎么办”谢飞机“啊密钥……写在配置文件里。泄露了……就换一个但那用户全部要重新登录。。”王总无奈地摇摇头“最后一个问题你们的服务怎么部署的Docker和Kubernetes用过吗”谢飞机“我们用Docker写个Dockerfilejenkins构建镜像然后docker run。Kubernetes……我只看了点视频知道有Pod和ServiceDeployment可以滚动更新。但真没在集群上操作过。”王总合上笔记本站起身面无表情地说“好谢飞机面试到这里。我们了解了你的基本情况你先回去等通知吧。”谢飞机挠挠头走到门口又转身“王总三个工作日以内会给通知吗”王总嘴角勉强抽动了一下“会的。等通知吧。”答案解析详细讲解每一个问题的业务场景与技术点1. 电商项目模块与技术栈选型业务场景电商平台一般分为用户、商品、订单、购物车、库存、支付、营销等多个服务。Java后端常见技术选型为核心语言Java 8/11/17重点关注Stream、Optional、var等特性。Web框架Spring Boot、Spring MVC快速搭建REST API。数据库MySQL主从复制、分库分表应对大数据量。ORMMyBatis或Spring Data JPA。缓存Redis用于热点数据、会话、分布式锁。消息队列Kafka或RabbitMQ用于异步解耦订单、支付、库存。构建工具Maven或Gradle。技术点面试官问项目选型实际是想了解候选人的技术广度与系统设计能力。回答时建议简述每个组件的职责例如“MySQL存储业务数据Redis做热点缓存RabbitMQ异步发送订单通知”。2. JVM内存模型与垃圾回收算法业务场景电商大促时高并发会创建大量对象导致频繁GC影响响应时间。理解JVM有助于调优堆大小、选择合适的垃圾回收器。JVM内存模型运行时数据区堆存放对象实例分新生代、老年代。虚拟栈每个线程私有存局部变量、方法调用。本地方法栈为native方法服务。方法区/元空间存类信息、常量、静态变量。程序计数器当前线程执行的字节码行号。垃圾回收算法标记-清除先标记垃圾再清除。产生内存碎片。复制将内存分两块活对象复制到另一块清理原块。适合新生代。标记-整理让活对象向一端移动再清理边界外内存。适合老年代。GC Roots包括栈中本地变量、静态变量、JNI引用等。从这些根向下搜索未被引用的对象即为可回收对象。3. HashMap底层原理业务场景电商中用HashMap缓存小规格配置项同时面试高频。JDK 8数组 链表 红黑树。数组默认大小16负载因子0.75。当链表长度 8 且数组长度 64 时链表转为红黑树降低查找复杂度到O(log n)。put流程计算hash - 定位桶 - 若为空直接放否则遍历链表/红黑树key相同则覆盖否则插入尾部。扩容超过阈值 capacity * loadFactor 时扩容为原来的2倍重新分布元素。4. Spring Boot自动配置原理业务场景开发时引入redis-start、web-start等依赖后无需手动配置BeanSpring Boot自动完成。核心SpringBootApplication包含EnableAutoConfiguration。自动配置类在META-INF/spring.factories或AutoConfiguration.imports中注册。通过ConditionalOnClass、ConditionalOnMissingBean等条件注解判断类路径是否存在对应依赖、用户是否已自定义Bean从而自动生成默认配置。例如RedisAutoConfiguration提供了RedisTemplate、StringRedisTemplate的默认Bean。注意如需覆盖自定义Bean即可自动配置会失效。5. 缓存穿透、击穿、雪崩业务场景商品列表页每天百万QPS大量请求打向缓存。| 问题 | 现象 | 解决方案 | |------|------|----------| |穿透| 查询一个不存在的数据缓存没有每次打到数据库 | 缓存空值设置短过期时间布隆过滤器 | |击穿| 热点key过期瞬间大量请求同时打到数据库 | 互斥锁setnx重建缓存热点key逻辑过期 | |雪崩| 大量key在同一时间过期导致数据库压力骤增 | 过期时间加随机值多级缓存服务降级 |6. 缓存与数据库一致性业务场景更新商品价格后缓存中价格仍是旧值。常用策略Cache Aside旁路缓存读时先读缓存未命中再读数据库并写回缓存写时先更新数据库再删除缓存。删除缓存而不是更新缓存避免计算复杂度。延迟双删先删缓存再更新数据库再延迟几百毫秒删一次降低并发下的不一致窗口。最终一致方案通过订阅MySQL binlog同步缓存如Canal或使用消息队列异步删除缓存。注意强一致很难保证通常接受最终一致。7. 防止库存超卖业务场景秒杀场景下100个库存10000人同时下单。方案一数据库乐观锁。UPDATE t_stock SET versionversion1 WHERE id? AND version?或UPDATE t_stock SET stockstock-1 WHERE id? AND stock0。方案二Redis预扣减。秒杀前将库存加载到Redis用Lua脚本原子扣减再异步同步到数据库。方案三分布式锁。使用RedisSET lockKey value NX EX获取锁释放锁时用Lua保证原子性。注意synchronized只能锁单机进程多实例无效。8. 性能问题排查业务场景线上接口偶发超时如何排查步骤看监控告警Prometheus GrafanaCPU、内存、GC频率、P99延迟。查日志错误日志、慢日志尤其看有无OOM、Timeout。排查慢SQL开启MySQL慢查询日志用explain分析索引。排查Redis慢日志、大key、热key。排查线程栈jstack查看是否有死锁、线程阻塞。在线定位Arthas查看方法耗时、动态替换类。9. Kafka消息不丢失与重复消费业务场景订单支付成功后发送消息给积分服务如果消息丢失用户积分会少。消息丢失防范生产者设置acksall同步等待发送结果。Broker设置replication.factor3且min.insync.replicas2。消费者关闭自动提交enable.auto.commitfalse业务处理成功后再手动提交offset。重复消费消费者处理完消息后、提交offset前宕机重启后会从上次offset重新消费。解决方案消费端幂等RedisSETNX数据库唯一键状态机。使用消息去重表每条记录唯一消息ID插入前检查是否已存在。10. 微服务链路追踪业务场景一次查询商品请求会经过网关、商品服务、库存服务、优惠券服务。定位一次超时需要串联整个调用链。技术方案Spring Cloud Sleuth已退役现在使用Micrometer TracingZipkin/Jaeger。核心概念traceId全局唯一、spanId一次调用单元。每个服务从HTTP Header中提取traceId写入日志上报到Zipkin UI展示调用链和耗时。Micrometer支持多类监控后端与Prometheus、Grafana整合。11. Redis集群宕机如何应对业务场景大促时Redis挂了所有读请求打到MySQL系统雪崩。多级缓存本地缓存Caffeine Redis MySQL。Redis挂了本地缓存可以支撑几分钟。服务降级关闭非核心功能比如推荐流、个性化优惠券仅保留下单能力。限流熔断Resilience4j或Sentinel对下游依赖做熔断防止线程阻塞耗尽。高可用Redis Cluster / 哨兵模式自动故障转移但全局宕机概率仍存在必须有兜底。12. JWT无状态登录与安全业务场景电商各大服务之间需要认证用户身份不用每个服务都读session。JWT结构Header算法 Payload用户信息、过期时间 Signature签名Base64编码用点分隔。流程用户登录 - 服务端验证密码 - 生成JWT返回 - 前端存储HttpOnly Cookie或LocalStorage- 后续请求携带Authorization: Bearer - 服务端验签并解析用户信息。密钥管理JWT签名密钥必须保密通常放在配置中心Nacos / Apollo且定期轮换。泄露后需要立即吊销所有token让用户重新登录。注意JWT无状态无法主动退出可结合黑名单/短过期时间实现。13. Docker和Kubernetes部署业务场景电商有几十个微服务如何快速发布和扩容。Docker将应用打成镜像Dockerfile包含JDK环境、依赖、应用代码运行在容器中。Kubernetes负责容器编排管理Pod一组容器、Service负载均衡、Deployment滚动更新、ConfigMap配置。常见流程Jenkins/GitLab CI构建镜像推送到镜像仓库。更新Deployment镜像版本K8s自动滚动升级。使用Prometheus监控Pod指标HPA根据CPU/内存自动扩缩容。命名空间、IngressIngress作为入口按域名路由到不同Service取代Nginx的配置。14. 其余高频技术点补充为了方便小白扩展这里再补充几个本文中出现的名词Flyway / Liquibase数据库版本管理工具将SQL脚本纳入版本库。Resilience4j轻量级熔断、限流、重试库用于提高分布式系统容错。OpenFeign声明式HTTP客户端微服务间调用更优雅。Apache Shiro / Spring Security认证授权框架Spring Security配合OAuth2/JWT使用更主流。Micrometer监控门面将JVM指标暴露给Prometheus。Elasticsearch电商商品搜索倒排索引复杂查询。Thymeleaf / FreeMarker服务端渲染模板传统电商管理后台仍在用。MapStructJava Bean映射性能高于BeanUtils用于PO/DTO/VO转换。LombokData、Builder等注解减少样板代码。面试结束谢飞机离开房间。王总在面试评价上写下“基础功不扎实高并发经验不足但HashMap回答尚可人有点意思可考虑外包岗。”欢迎继续关注下一期我们讲谢飞机接到二面电话后如何用一周时间突击背题却在“Kafka重复消费”上再次翻车。