后端场景面试题集
总题数: 120道 | 重点领域: 线上问题排查、性能优化、业务场景 | 难度分布: 中高级
本文档整理了后端场景的完整120道面试题目,涵盖线上问题排查、系统设计、性能优化、架构设计等各个方面。
� 面试题目列表
1. 针对支付宝最近出现的八折优惠事故,说说如何才能避免类似事件的发生?
核心措施:
- 配置管理:多级审批、配置校验、灰度发布
- 金额校验:最大折扣限制、单笔金额上限
- 实时监控:异常折扣告警、资金损失监控
- 熔断机制:异常流量自动熔断
- 快速回滚:一键回滚配置
2. 有一张表里面有三个字段,分别是(id,开始时间,结束时间),表中数据量为 5000W,如何统计流量最大的时候有多少条数据?
扫描线算法:
1WITH events AS (2 SELECT start_time AS time, 1 AS type FROM traffic_table3 UNION ALL4 SELECT end_time AS time, -1 AS type FROM traffic_table5)6SELECT MAX(concurrent) AS max_traffic7FROM (8 SELECT SUM(type) OVER (ORDER BY time) AS concurrent9 FROM events10) t;优化:建立时间索引、MapReduce分治处理
3. 让你设计一个 RPC 框架,怎么设计?
核心组件:
- 代理层:动态代理生成客户端
- 序列化:Protobuf/Hessian/JSON
- 网络通信:Netty
- 服务注册:Zookeeper/Nacos
- 负载均衡:随机/轮询/一致性Hash
- 容错:重试、熔断、降级
4. 如何设计一个秒杀功能?
核心方案:
- 前端:按钮防重、倒计时
- 网关:限流(令牌桶)
- Redis:预减库存
- MQ:削峰填谷
- 数据库:乐观锁防超卖
1// Redis预减库存2Long stock = redis.decr("stock:" + productId);3if (stock < 0) {4 redis.incr("stock:" + productId);5 return "库存不足";6}7// 发送MQ异步创建订单8mqProducer.send(new SeckillMessage(productId, userId));5. 让你设计一个消息队列,怎么设计?
核心设计:
- 存储:CommitLog顺序写 + ConsumeQueue索引
- 生产者:同步/异步发送
- 消费者:Push/Pull模式、消费者组
- 可靠性:消息确认、重试机制
- 高可用:主从复制、故障转移
6. 消息队列设计成推消息还是拉消息?推拉模式的优缺点?
推模式:Broker主动推送,实时性好但流量控制难 拉模式:Consumer主动拉取,可控速度但实时性差 长轮询(推荐):兼顾实时性和流量控制
7. 让你设计一个短链系统,怎么设计?
核心方案:
- 生成算法:自增ID转62进制 / Hash / 雪花算法
- 存储:MySQL存储映射 + Redis缓存
- 跳转:302重定向
- 统计:MQ异步统计点击数
1// 生成短码2String shortCode = Long.toString(id, 62);3redis.setex("short:" + shortCode, 86400, longUrl);8. 让你实现一个分布式单例对象,如何实现?
方案1:Redis SETNX
1Boolean success = redis.setnx("singleton:instance", "1", 3600);2if (success) {3 return new SingletonObject();4}方案2:Zookeeper临时节点
1zkClient.create("/singleton", data, CreateMode.EPHEMERAL);9. 分布式锁一般都怎样实现?
Redis实现:
1// 加锁2redis.set(lockKey, requestId, "NX", "PX", 30000);3// 解锁(Lua脚本保证原子性)4if redis.call('get', KEYS[1]) == ARGV[1] then5 return redis.call('del', KEYS[1])6endZookeeper实现:创建临时顺序节点,最小节点获得锁
Redisson:自动续期、可重入
10. 如果让你统计每个接口每分钟调用次数怎么统计?
方案1:Redis INCR
1String key = "api:" + apiName + ":" + (timestamp / 60);2redis.incr(key);3redis.expire(key, 120);方案2:滑动窗口(ZSET)
1redis.zadd(key, timestamp, uuid);2redis.zremrangeByScore(key, 0, timestamp - 60000);3long count = redis.zcard(key);11. 让你设计一个文件上传系统,怎么设计?
核心功能:
- 分片上传:大文件切分成小块
- 断点续传:记录已上传的分片
- 秒传:MD5校验文件是否已存在
- 存储:OSS/MinIO对象存储
1// 分片上传2String chunkKey = fileId + "_" + chunkIndex;3redis.setex(chunkKey, 3600, "uploaded");4// 所有分片上传完成后合并12. 让你设计一个分布式 ID 发号器,怎么设计?
方案对比:
- 雪花算法:1位符号 + 41位时间戳 + 10位机器ID + 12位序列号
- 数据库号段:批量获取ID段,本地分配
- Redis INCR:简单但依赖Redis
- 美团Leaf:号段模式 + 双buffer
1// 雪花算法2long id = (timestamp << 22) | (workerId << 12) | sequence;13. 什么是限流?限流算法有哪些?怎么实现的?
限流算法:
- 固定窗口:计数器,简单但有临界问题
- 滑动窗口:精确但内存占用大
- 漏桶:平滑流量,无法应对突发
- 令牌桶:允许突发,推荐使用
1// 令牌桶(Guava)2RateLimiter limiter = RateLimiter.create(100); // 100 QPS3if (limiter.tryAcquire()) {4 // 处理请求5}14. 即时通讯项目中怎么实现历史消息的下拉分页加载?
方案:
1// 使用消息ID作为游标2List<Message> messages = messageMapper.selectByUserId(3 userId, lastMessageId, 204);5// WHERE user_id = ? AND id < ? ORDER BY id DESC LIMIT 20优化:Redis缓存最近消息、分表存储历史消息
15. HashMap 是不是线程安全的?如果让你来实现一个线程安全的 HashMap 你要怎么设计?如果不用加锁你要怎么设计?
HashMap不是线程安全的
线程安全实现:
- ConcurrentHashMap:分段锁(JDK7)/ CAS+Synchronized(JDK8)
- Collections.synchronizedMap:全局锁
- 无锁实现:CopyOnWriteMap(写时复制)
16. 接口变慢了应该如何排查?导致接口变慢的原因有哪些?
排查步骤:
- 查看监控:QPS、RT、错误率
- 查看日志:慢SQL、异常日志
- 查看资源:CPU、内存、网络、磁盘IO
- 链路追踪:Skywalking/Zipkin
常见原因:
- 慢SQL、缺少索引
- 网络延迟、第三方接口慢
- GC频繁、内存泄漏
- 锁竞争、线程池满
- 缓存失效、数据库连接池满
17. 编写一段代码,使得这段代码必定会产生死锁,不能使用Thread.sleep()
1Object lock1 = new Object();2Object lock2 = new Object();34Thread t1 = new Thread(() -> {5 synchronized (lock1) {6 System.out.println("Thread 1: Holding lock 1");7 synchronized (lock2) {8 System.out.println("Thread 1: Holding lock 1 & 2");9 }10 }11});1213Thread t2 = new Thread(() -> {14 synchronized (lock2) {15 System.out.println("Thread 2: Holding lock 2");16 synchronized (lock1) {17 System.out.println("Thread 2: Holding lock 1 & 2");18 }19 }20});2122t1.start();23t2.start();18. 现在手头上有一个单体项目,系统的整体 QPS 到了 1 万了,要微服务化拆分吗?
不一定需要拆分。考虑因素:
- 性能瓶颈:单体能否通过优化(缓存、异步、数据库优化)解决
- 团队规模:小团队拆分反而增加复杂度
- 业务复杂度:业务简单不需要拆分
- 技术债务:拆分成本 vs 收益
建议:先优化单体,确实遇到瓶颈再拆分
19. 系统每天晚上都会有一小时左右的时间瘫痪,你觉得可能的原因是什么?有遇到过这样的情况吗?
可能原因:
- 定时任务:大批量数据处理、全量同步
- 数据库备份:锁表、IO飙高
- 日志清理:磁盘IO占满
- 批量任务:报表生成、数据统计
- GC:Full GC导致STW
排查方法:查看定时任务、监控资源使用、分析GC日志
20. 现在有 40 亿个 QQ 号,给你 1G 的内存,如何实现去重?
方案1:Bitmap
1// 40亿个号码,每个号码1bit2// 需要内存:40亿 / 8 / 1024 / 1024 ≈ 477MB3BitSet bitSet = new BitSet(4000000000);4for (long qq : qqList) {5 if (bitSet.get(qq)) {6 // 重复7 } else {8 bitSet.set(qq);9 }10}方案2:布隆过滤器(允许小概率误判)
1BloomFilter<Long> bloomFilter = BloomFilter.create(2 Funnels.longFunnel(),3 4000000000L,4 0.01 // 1%误判率5);方案3:分治:分成多个文件,每个文件单独去重
21. 在 Java 中,不使用锁如何实现一个线程安全的单例?
静态内部类(推荐):
1public class Singleton {2 private Singleton() {}3 4 private static class Holder {5 private static final Singleton INSTANCE = new Singleton();6 }7 8 public static Singleton getInstance() {9 return Holder.INSTANCE;10 }11}枚举:
1public enum Singleton {2 INSTANCE;3}22. 如果要实现一个抢红包的功能,红包金额是如何计算的?
二倍均值法:
1public BigDecimal random(BigDecimal total, int remaining) {2 if (remaining == 1) return total;3 4 // 最大金额 = 剩余金额 / 剩余人数 * 25 BigDecimal max = total.divide(new BigDecimal(remaining))6 .multiply(new BigDecimal(2));7 8 // 随机金额 = [0.01, max]9 BigDecimal amount = BigDecimal.valueOf(Math.random())10 .multiply(max)11 .setScale(2, RoundingMode.DOWN);12 13 return amount.max(new BigDecimal("0.01"));14}23. 让你设计一个 HashMap ,怎么设计?
核心设计:
- 数组+链表/红黑树:数组存储桶,链表/红黑树解决冲突
- Hash函数:
(h = key.hashCode()) ^ (h >>> 16) - 扩容:负载因子0.75,容量翻倍
- 线程安全:CAS + Synchronized(JDK8)
24. 线上 CPU 飙高如何排查?
排查步骤:
1# 1. 找到CPU占用高的进程2top34# 2. 找到占用CPU高的线程5top -Hp <pid>67# 3. 线程ID转16进制8printf "%x\n" <thread_id>910# 4. 查看线程堆栈11jstack <pid> | grep <thread_id_hex> -A 201213# 5. 分析代码常见原因:死循环、频繁GC、正则表达式、大量计算
25. 线上 CPU Load 飙高如何排查?
CPU Load vs CPU使用率:
- Load高、使用率低:IO等待、锁等待
- Load高、使用率高:计算密集
排查:
1# 查看IO等待2iostat -x 134# 查看锁等待5jstack <pid> | grep BLOCKED26. 系统上线后,发现某个接口响应很慢,你如何定位可能的原因,以及对应的解决思路?
定位方法:监控(QPS/RT)→ 日志(慢SQL)→ 链路追踪(Skywalking)→ 性能分析(Arthas) 解决思路:优化SQL、加缓存、异步处理、限流降级
27. 如果项目需要你实现敏感词过滤功能,如何实现?
DFA算法(确定有限状态自动机)+ 前缀树(Trie):
1// 构建敏感词树2Map<String, Object> tree = new HashMap<>();3for (String word : sensitiveWords) {4 Map<String, Object> node = tree;5 for (char c : word.toCharArray()) {6 node = (Map) node.computeIfAbsent(String.valueOf(c), k -> new HashMap<>());7 }8 node.put("isEnd", true);9}28. 如果现在有 500G 数据需要排序,但是你只有 4G 内存,如何实现?
外部排序(External Sort):
- 将500G数据分成125个4G文件
- 每个文件单独排序后写回磁盘
- 使用归并排序合并125个有序文件
29. 项目上现在需要存储 IP 地址,数据库应该用什么类型来存储?
INT UNSIGNED(推荐):
1// IP转整数2long ip2Long(String ip) {3 String[] parts = ip.split("\\.");4 return (Long.parseLong(parts[0]) << 24)5 + (Long.parseLong(parts[1]) << 16)6 + (Long.parseLong(parts[2]) << 8)7 + Long.parseLong(parts[3]);8}优点:占用4字节,索引效率高,支持范围查询
30. 一笔订单,在取消的那一刻用户刚好付款了,怎么办?
方案:
- 状态机:订单状态流转加锁
- 分布式锁:取消和支付互斥
- 补偿机制:支付成功后检查订单状态,如已取消则退款
31-102. 核心答案速览
31. 避免重复下单:Redis SETNX + 过期时间、订单状态机
32. Redis爆满优化:清理过期key、优化数据结构、增加内存、集群扩容
33. Excel导出优化:分页导出、异步处理、EasyExcel、压缩
34. Excel导入注意:分批插入、事务控制、异常处理、进度反馈
35. 同时支付:分布式锁、支付状态机、幂等性校验
36. HashMap扩容优化:渐进式rehash、分段锁、预估容量
37. RPC超时设置:根据P99响应时间设置,一般1-3秒
38. 超时时间链路:网关 > 服务A > 服务B,逐级递减
39. 线程池设计:核心线程数、最大线程数、队列、拒绝策略
40. 1000亿数据插入HashMap:分段并发、预估容量、批量操作
41. 连接池爆满:慢SQL、连接泄漏、连接数不足
42. 数据库不停服迁移:双写、数据同步、灰度切换
43. SQL调优:索引优化、避免全表扫描、分页优化
44. 深度分页:游标分页(WHERE id > last_id)、ES
45. 索引失效:EXPLAIN分析、索引覆盖、避免函数计算
46. 全量同步问题:增量同步、缓存、分页加载
47. JDK序列化:版本不兼容、使用JSON/Protobuf
48. Gateway 500:查看日志、超时配置、熔断降级
49. MQ故障兜底:本地队列、数据库队列、重试机制
50. 点赞系统:Redis ZSET、异步入库、防重复点赞
51. JVM内存分析:jmap -heap、MAT分析dump文件
52. Redis内存溢出:查看bigkey、设置淘汰策略、扩容
53. 200万生产者1消费者:批量消费、无锁队列、分区
54. 附近商户:GeoHash、Redis GEO、四叉树
55. 文件写入过程:用户态 → 内核态 → PageCache → 磁盘
56. 分布式锁并发度:锁粒度细化、分段锁、乐观锁
57. 购物车设计:Redis Hash、持久化到MySQL、合并计算
58. 会员过期提醒:定时任务扫描、延迟队列、Redis过期监听
59. Top50商品:Redis ZSET、定时统计、实时计算
60. SELECT * 1000万行:流式查询、分批处理、不会一次性加载
61. 线程池参数:核心线程1000、最大线程1000、队列0
62. 订单超时取消:延迟队列、定时任务、Redis过期
63. 调用第三方接口:超时设置、重试机制、熔断降级、幂等性
64. 朋友圈点赞:Redis SET、异步入库、推拉结合
65. Redis热点数据:LRU淘汰策略、定期更新热点数据
66. 慢请求排查:链路追踪(Skywalking)、日志分析
67. Redis挂了:本地缓存、限流降级、快速恢复
68. 服务发现:Nacos/Eureka注册中心、心跳机制
69. 单表优化:索引优化、分区表、冷热数据分离
70. 堆外内存增长:DirectByteBuffer、Netty、JNI
71. Bitmap大ID:RoaringBitmap压缩、分段存储
72. 本地远程事务一致性:TCC、SAGA、最终一致性
73. 多机共享登录:Redis Session、JWT Token
74. 负载均衡器:servers.get(request.hashCode() % servers.size())
75. 踢用户下线:删除Redis Session、WebSocket推送
76. 不用大小号比较:(a - b) >> 31 或异或
77. 1s优化到1ms:加缓存、异步处理、预计算、CDN
78. IM协议设计:心跳、消息确认、离线消息、加密
79. Linux命令执行:Shell解析 → Fork进程 → Exec加载 → 执行
80. 缓存预热:启动时加载、定时刷新、懒加载
81. 关联表vs冗余:关联表规范、冗余字段性能好
82. 避免重连洪峰:随机延迟、指数退避、限流
83. 异步处理:MQ解耦、线程池、CompletableFuture
84. 4C8G vs 8C16G:看业务特点,IO密集选4C8G
85. Agent死循环:限制执行次数、超时中断
86. LLM性能分析:批处理、流式输出、模型并行
87. JWT安全:HTTPS、短过期时间、Refresh Token
88. CDN流量异常:防盗链、访问控制、监控告警
89. 恶意刷流量:限流、验证码、IP黑名单、风控
90. 多数据库适配:MyBatis多数据源、JPA、抽象DAO
91. 性能优化:硬件、网络、架构、中间件、配置
92. 上线关注指标:QPS、RT、错误率、CPU、内存
93. OAuth2.0设计:授权码模式、Token存储Redis
94. 防验证码攻击:图形验证码、行为验证、频率限制
95. 在线加字段:Online DDL、pt-osc、先加后用
96. 重复登录:Redis ZSET记录登录时间、ZCOUNT统计
97. 海外延迟:CDN、海外节点、数据预同步
98. 最大在线人数:扫描线算法、事件排序
99. 收集并行结果:CountDownLatch、CompletableFuture.allOf()
100. 限流FIFO设计:分布式队列、令牌桶、Redis List
101. 亿级数据加索引:Online DDL、从库加索引后切换
102. ArrayList去重:HashSet、Stream.distinct()、布隆过滤器
学习指南
核心要点:
- 线上问题排查的方法论
- 性能优化和故障排查
- 分布式系统设计模式
- 业务场景解决方案
学习路径建议:
- 掌握线上问题排查技能
- 熟悉性能优化方法
- 理解分布式系统设计
- 学习业务场景解决方案
评论区 / Comments