Skip to main content

后端场景面试题集

总题数: 120道 | 重点领域: 线上问题排查、性能优化、业务场景 | 难度分布: 中高级

本文档整理了后端场景的完整120道面试题目,涵盖线上问题排查、系统设计、性能优化、架构设计等各个方面。


� 面试题目列表

1. 针对支付宝最近出现的八折优惠事故,说说如何才能避免类似事件的发生?

核心措施

  1. 配置管理:多级审批、配置校验、灰度发布
  2. 金额校验:最大折扣限制、单笔金额上限
  3. 实时监控:异常折扣告警、资金损失监控
  4. 熔断机制:异常流量自动熔断
  5. 快速回滚:一键回滚配置

2. 有一张表里面有三个字段,分别是(id,开始时间,结束时间),表中数据量为 5000W,如何统计流量最大的时候有多少条数据?

扫描线算法

sql
1WITH events AS (
2 SELECT start_time AS time, 1 AS type FROM traffic_table
3 UNION ALL
4 SELECT end_time AS time, -1 AS type FROM traffic_table
5)
6SELECT MAX(concurrent) AS max_traffic
7FROM (
8 SELECT SUM(type) OVER (ORDER BY time) AS concurrent
9 FROM events
10) t;

优化:建立时间索引、MapReduce分治处理

3. 让你设计一个 RPC 框架,怎么设计?

核心组件

  1. 代理层:动态代理生成客户端
  2. 序列化:Protobuf/Hessian/JSON
  3. 网络通信:Netty
  4. 服务注册:Zookeeper/Nacos
  5. 负载均衡:随机/轮询/一致性Hash
  6. 容错:重试、熔断、降级

4. 如何设计一个秒杀功能?

核心方案

  1. 前端:按钮防重、倒计时
  2. 网关:限流(令牌桶)
  3. Redis:预减库存
  4. MQ:削峰填谷
  5. 数据库:乐观锁防超卖
java
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. 让你设计一个消息队列,怎么设计?

核心设计

  1. 存储:CommitLog顺序写 + ConsumeQueue索引
  2. 生产者:同步/异步发送
  3. 消费者:Push/Pull模式、消费者组
  4. 可靠性:消息确认、重试机制
  5. 高可用:主从复制、故障转移

6. 消息队列设计成推消息还是拉消息?推拉模式的优缺点?

推模式:Broker主动推送,实时性好但流量控制难 拉模式:Consumer主动拉取,可控速度但实时性差 长轮询(推荐):兼顾实时性和流量控制

7. 让你设计一个短链系统,怎么设计?

核心方案

  1. 生成算法:自增ID转62进制 / Hash / 雪花算法
  2. 存储:MySQL存储映射 + Redis缓存
  3. 跳转:302重定向
  4. 统计:MQ异步统计点击数
java
1// 生成短码
2String shortCode = Long.toString(id, 62);
3redis.setex("short:" + shortCode, 86400, longUrl);

8. 让你实现一个分布式单例对象,如何实现?

方案1:Redis SETNX

java
1Boolean success = redis.setnx("singleton:instance", "1", 3600);
2if (success) {
3 return new SingletonObject();
4}

方案2:Zookeeper临时节点

java
1zkClient.create("/singleton", data, CreateMode.EPHEMERAL);

9. 分布式锁一般都怎样实现?

Redis实现

java
1// 加锁
2redis.set(lockKey, requestId, "NX", "PX", 30000);
3// 解锁(Lua脚本保证原子性)
4if redis.call('get', KEYS[1]) == ARGV[1] then
5 return redis.call('del', KEYS[1])
6end

Zookeeper实现:创建临时顺序节点,最小节点获得锁

Redisson:自动续期、可重入

10. 如果让你统计每个接口每分钟调用次数怎么统计?

方案1:Redis INCR

java
1String key = "api:" + apiName + ":" + (timestamp / 60);
2redis.incr(key);
3redis.expire(key, 120);

方案2:滑动窗口(ZSET)

java
1redis.zadd(key, timestamp, uuid);
2redis.zremrangeByScore(key, 0, timestamp - 60000);
3long count = redis.zcard(key);

11. 让你设计一个文件上传系统,怎么设计?

核心功能

  1. 分片上传:大文件切分成小块
  2. 断点续传:记录已上传的分片
  3. 秒传:MD5校验文件是否已存在
  4. 存储:OSS/MinIO对象存储
java
1// 分片上传
2String chunkKey = fileId + "_" + chunkIndex;
3redis.setex(chunkKey, 3600, "uploaded");
4// 所有分片上传完成后合并

12. 让你设计一个分布式 ID 发号器,怎么设计?

方案对比

  1. 雪花算法:1位符号 + 41位时间戳 + 10位机器ID + 12位序列号
  2. 数据库号段:批量获取ID段,本地分配
  3. Redis INCR:简单但依赖Redis
  4. 美团Leaf:号段模式 + 双buffer
java
1// 雪花算法
2long id = (timestamp << 22) | (workerId << 12) | sequence;

13. 什么是限流?限流算法有哪些?怎么实现的?

限流算法

  1. 固定窗口:计数器,简单但有临界问题
  2. 滑动窗口:精确但内存占用大
  3. 漏桶:平滑流量,无法应对突发
  4. 令牌桶:允许突发,推荐使用
java
1// 令牌桶(Guava)
2RateLimiter limiter = RateLimiter.create(100); // 100 QPS
3if (limiter.tryAcquire()) {
4 // 处理请求
5}

14. 即时通讯项目中怎么实现历史消息的下拉分页加载?

方案

java
1// 使用消息ID作为游标
2List<Message> messages = messageMapper.selectByUserId(
3 userId, lastMessageId, 20
4);
5// WHERE user_id = ? AND id < ? ORDER BY id DESC LIMIT 20

优化:Redis缓存最近消息、分表存储历史消息

15. HashMap 是不是线程安全的?如果让你来实现一个线程安全的 HashMap 你要怎么设计?如果不用加锁你要怎么设计?

HashMap不是线程安全的

线程安全实现

  1. ConcurrentHashMap:分段锁(JDK7)/ CAS+Synchronized(JDK8)
  2. Collections.synchronizedMap:全局锁
  3. 无锁实现:CopyOnWriteMap(写时复制)

16. 接口变慢了应该如何排查?导致接口变慢的原因有哪些?

排查步骤

  1. 查看监控:QPS、RT、错误率
  2. 查看日志:慢SQL、异常日志
  3. 查看资源:CPU、内存、网络、磁盘IO
  4. 链路追踪:Skywalking/Zipkin

常见原因

  • 慢SQL、缺少索引
  • 网络延迟、第三方接口慢
  • GC频繁、内存泄漏
  • 锁竞争、线程池满
  • 缓存失效、数据库连接池满

17. 编写一段代码,使得这段代码必定会产生死锁,不能使用Thread.sleep()

java
1Object lock1 = new Object();
2Object lock2 = new Object();
3
4Thread 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});
12
13Thread 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});
21
22t1.start();
23t2.start();

18. 现在手头上有一个单体项目,系统的整体 QPS 到了 1 万了,要微服务化拆分吗?

不一定需要拆分。考虑因素:

  1. 性能瓶颈:单体能否通过优化(缓存、异步、数据库优化)解决
  2. 团队规模:小团队拆分反而增加复杂度
  3. 业务复杂度:业务简单不需要拆分
  4. 技术债务:拆分成本 vs 收益

建议:先优化单体,确实遇到瓶颈再拆分

19. 系统每天晚上都会有一小时左右的时间瘫痪,你觉得可能的原因是什么?有遇到过这样的情况吗?

可能原因

  1. 定时任务:大批量数据处理、全量同步
  2. 数据库备份:锁表、IO飙高
  3. 日志清理:磁盘IO占满
  4. 批量任务:报表生成、数据统计
  5. GC:Full GC导致STW

排查方法:查看定时任务、监控资源使用、分析GC日志

20. 现在有 40 亿个 QQ 号,给你 1G 的内存,如何实现去重?

方案1:Bitmap

java
1// 40亿个号码,每个号码1bit
2// 需要内存:40亿 / 8 / 1024 / 1024 ≈ 477MB
3BitSet bitSet = new BitSet(4000000000);
4for (long qq : qqList) {
5 if (bitSet.get(qq)) {
6 // 重复
7 } else {
8 bitSet.set(qq);
9 }
10}

方案2:布隆过滤器(允许小概率误判)

java
1BloomFilter<Long> bloomFilter = BloomFilter.create(
2 Funnels.longFunnel(),
3 4000000000L,
4 0.01 // 1%误判率
5);

方案3:分治:分成多个文件,每个文件单独去重

21. 在 Java 中,不使用锁如何实现一个线程安全的单例?

静态内部类(推荐):

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}

枚举

java
1public enum Singleton {
2 INSTANCE;
3}

22. 如果要实现一个抢红包的功能,红包金额是如何计算的?

二倍均值法

java
1public BigDecimal random(BigDecimal total, int remaining) {
2 if (remaining == 1) return total;
3
4 // 最大金额 = 剩余金额 / 剩余人数 * 2
5 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 ,怎么设计?

核心设计

  1. 数组+链表/红黑树:数组存储桶,链表/红黑树解决冲突
  2. Hash函数(h = key.hashCode()) ^ (h >>> 16)
  3. 扩容:负载因子0.75,容量翻倍
  4. 线程安全:CAS + Synchronized(JDK8)

24. 线上 CPU 飙高如何排查?

排查步骤

bash
1# 1. 找到CPU占用高的进程
2top
3
4# 2. 找到占用CPU高的线程
5top -Hp <pid>
6
7# 3. 线程ID转16进制
8printf "%x\n" <thread_id>
9
10# 4. 查看线程堆栈
11jstack <pid> | grep <thread_id_hex> -A 20
12
13# 5. 分析代码

常见原因:死循环、频繁GC、正则表达式、大量计算

25. 线上 CPU Load 飙高如何排查?

CPU Load vs CPU使用率

  • Load高、使用率低:IO等待、锁等待
  • Load高、使用率高:计算密集

排查

bash
1# 查看IO等待
2iostat -x 1
3
4# 查看锁等待
5jstack <pid> | grep BLOCKED

26. 系统上线后,发现某个接口响应很慢,你如何定位可能的原因,以及对应的解决思路?

定位方法:监控(QPS/RT)→ 日志(慢SQL)→ 链路追踪(Skywalking)→ 性能分析(Arthas) 解决思路:优化SQL、加缓存、异步处理、限流降级

27. 如果项目需要你实现敏感词过滤功能,如何实现?

DFA算法(确定有限状态自动机)+ 前缀树(Trie)

java
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)

  1. 将500G数据分成125个4G文件
  2. 每个文件单独排序后写回磁盘
  3. 使用归并排序合并125个有序文件

29. 项目上现在需要存储 IP 地址,数据库应该用什么类型来存储?

INT UNSIGNED(推荐):

java
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. 一笔订单,在取消的那一刻用户刚好付款了,怎么办?

方案

  1. 状态机:订单状态流转加锁
  2. 分布式锁:取消和支付互斥
  3. 补偿机制:支付成功后检查订单状态,如已取消则退款

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()、布隆过滤器


学习指南

核心要点:

  • 线上问题排查的方法论
  • 性能优化和故障排查
  • 分布式系统设计模式
  • 业务场景解决方案

学习路径建议:

  1. 掌握线上问题排查技能
  2. 熟悉性能优化方法
  3. 理解分布式系统设计
  4. 学习业务场景解决方案
forum

评论区 / Comments