---
name: backend
description: 后端架构与方法论出题（栈无关）：缓存、数据库扩展、消息队列、可靠性与容错、接口设计、可观测性、限流与容量。岗位或简历涉及后端开发、服务端、Backend Engineer、微服务、分布式系统时加载。
keywords: [后端, 服务端, 后端开发, backend, backend engineer, 微服务, 分布式, 缓存, redis, 消息队列, kafka, 高并发, 限流, 可观测性, api设计]
layer: domain
---

## 岗位职责与考察重点

后端工程师（服务端开发、Backend Engineer）的日常是把业务需求变成稳定、可扩展、可排查的线上服务：设计接口与数据模型、处理并发与一致性、接缓存与队列、盯监控与告警、扛流量高峰、处理线上故障。真实面试里，不论候选人写 Java、Go 还是 Python，被反复追问的都是同一批东西：数据怎么存、怎么读快、怎么写不丢、挂了怎么办、怎么知道它挂了、流量翻十倍先崩哪里。面试官最在意三件事：一是候选人能否说清自己系统里每个组件"为什么在那里"，而不是"大家都这么搭"；二是有没有真实的线上排查经历——从告警到根因的完整链路；三是对一致性、可用性、成本、复杂度之间的取舍有没有自己的判断，而不是背 CAP。

校招侧重基础：HTTP 与 RPC 的差别、缓存的基本用法、事务与锁、能否把一个简单业务拆成合理的表和接口，重点看思路是否清晰、能否被追问推着往下想。社招侧重工程判断：给一个具体故障或容量问题，看排查顺序、看有没有量化（QPS、P99、连接数、命中率）、看方案里有没有回滚与降级。一线大厂与外企近年更倾向于"场景推演"：给一个业务描述，让候选人现场设计并解释每个决定，纯名词题（"说说 Redis 的数据结构"）占比越来越低。

## 主题

### 缓存设计与一致性
- 阶梯：为什么加缓存、放哪一层 → Cache Aside / Read Through / Write Behind 各自的适用场景，为什么"先删缓存再写库"会出问题 → 缓存击穿、穿透、雪崩在线上各自长什么样、怎么区分、怎么修 → 强一致与最终一致的边界：哪些数据可以容忍几秒不一致，哪些必须走数据库
- 好题：商品详情页缓存命中率突然从 98% 掉到 60%，数据库 CPU 飙高，你按什么顺序排查？如果发现是大促前运营批量改价触发了集中失效，短期与长期各怎么处理？
- 危险信号：只会说"用 Redis 加缓存"；把延迟双删当标准答案却说不出它解决的是什么竞态；不知道自己系统缓存的命中率与 key 数量级
- 期望信号：能画出读写路径并指出竞态窗口；区分热 key、大 key 的处理（本地缓存、拆分、异步加载）；知道过期时间加随机抖动、互斥重建、布隆过滤器各解决什么问题；能说出哪些业务用了缓存但接受了什么程度的不一致

### 数据库扩展与分库分表
- 阶梯：单库能撑多大、什么信号说明该拆了 → 读写分离的主从延迟怎么处理，垂直拆与水平拆的区别 → 分片键选错之后（热点、跨片查询、扩容重分布）怎么办 → 分库分表 vs 分布式数据库（TiDB 等）vs 换存储（宽表、ES）的取舍
- 好题：订单表到 20 亿行，按用户 ID 分了 64 片，现在客服要按商家维度查订单，你有哪些方案？各自对写入路径、一致性和运维的代价是什么？
- 危险信号：一上来就分库分表而没试过索引优化、归档、读写分离；说不出分片键的选择依据；不知道跨片事务和跨片分页的代价
- 期望信号：先做过冷热分离/归档；分片键按主要查询维度选并接受次要维度走异构索引（ES/宽表/映射表）；扩容方案有一致性哈希或成倍扩容的思路；主从延迟场景下有"写后读走主库"之类的处理

### 消息队列与异步解耦
- 阶梯：什么场景该异步 → 至少一次、至多一次、恰好一次各在哪一层保证，消费端幂等怎么做 → 消息堆积、消费者慢、重复消费、顺序错乱的排查与处理 → 削峰填谷带来的最终一致，业务上怎么向用户交代，什么场景不该用队列
- 好题：支付成功后发货的链路走 MQ，某天堆积了 200 万条，用户投诉收不到发货通知，你先看什么、怎么快速恢复、事后怎么防止？扩消费者会不会打垮下游？
- 危险信号：认为 MQ 能保证恰好一次；消费端没有幂等设计；不知道自己 topic 的分区数、消费组、消费延迟指标
- 期望信号：幂等靠业务主键或去重表；堆积时有限流下游与动态扩容并存的方案；顺序需求用同一分区键保证并知道会牺牲并行度；死信队列与告警；能说出事务消息或本地消息表怎么保证"写库与发消息"一致

### 分布式事务与一致性
- 阶梯：为什么跨服务不能用数据库事务 → 2PC、TCC、Saga、本地消息表各自的模型与代价 → 补偿失败、悬挂、空回滚这些边界情况怎么处理 → 业务上能不能通过重新定义流程避开分布式事务
- 好题：下单扣库存与扣优惠券在两个服务，产品要求"要么都成功要么都失败"，你会怎么设计？如果扣券成功但库存不足，补偿失败了怎么办？有没有办法让这个流程根本不需要分布式事务？
- 危险信号：只会说"用 Seata"；把最终一致当成不一致；不知道补偿也会失败
- 期望信号：优先考虑通过预占、状态机、异步核对避开强一致；TCC 有 try 阶段资源预留的具体设计；有对账与人工兜底；能量化一致性窗口

### 接口设计与 API 演进
- 阶梯：RESTful 与 RPC 怎么选 → 幂等键、分页游标、错误码体系、版本管理各自的设计 → 接口被上游重试打爆、老版本客户端无法下线怎么处理 → 内部接口用 gRPC/Thrift 还是 HTTP JSON，字段兼容规则怎么定
- 好题：一个创建订单接口，客户端网络抖动重试三次，如何保证只创建一单？幂等键放哪里、存多久、并发下两个请求带同一个键同时到达怎么办？
- 危险信号：认为接口设计就是命名规范；幂等靠"数据库唯一索引报错"却没考虑用户体验与并发；分页用 offset 到几百万页
- 期望信号：幂等键客户端生成、服务端先占位再处理；游标分页；错误码区分可重试与不可重试；字段只加不删不改语义；有接口文档与契约测试

### 可靠性：超时、重试、熔断、降级
- 阶梯：为什么每个远程调用都必须有超时 → 重试放大（retry storm）怎么发生，退避与抖动、重试预算 → 依赖服务变慢导致线程池耗尽、级联雪崩的排查 → 降级什么、保什么，怎么定义核心链路，预案怎么演练
- 好题：一个下游服务 P99 从 50ms 涨到 2s 但没有挂，你的服务却整体不可用了，为什么？怎么设计能让下游变慢时你只损失那一个功能？
- 危险信号：所有调用共用一个线程池/连接池；重试没有上限没有退避；熔断阈值是拍脑袋的
- 期望信号：按依赖隔离资源（线程池/信号量/连接池）；超时按链路预算逐级分配；熔断半开探测；降级有开关有兜底数据；能说出一次真实的雪崩与修复

### 可观测性与线上排查
- 阶梯：日志、指标、链路追踪各自回答什么问题 → RED/USE 指标怎么选，采样率与成本 → 告警了但日志里什么都没有、慢请求只在特定用户复现怎么查 → 告警噪音治理与 SLO 驱动的告警
- 好题：凌晨告警接口错误率 3%，你打开监控后按什么顺序看？如果发现只有一台机器错误率高，怀疑哪些原因？如果全部机器都高但下游都正常呢？
- 危险信号：排查全靠 grep 日志；不知道自己服务的 P99 是多少；告警多到没人看
- 期望信号：先看变更（发布、配置、流量），再看依赖，再看资源；有 trace ID 贯穿；区分错误率、延迟、饱和度；提到告警要有 runbook；能讲出一次从告警到根因的完整过程

### 限流、容量规划与压测
- 阶梯：为什么要限流、限在哪一层 → 令牌桶、漏桶、滑动窗口的差别，单机限流与分布式限流 → 压测数据怎么造、怎么隔离、压测发现瓶颈在哪一层 → 容量按峰值备还是弹性扩，成本与 SLA 的取舍
- 好题：活动前要求系统能扛 10 倍日常流量，你怎么评估当前容量、怎么压测、压出瓶颈后优先扩什么？活动当天流量超过预期 3 倍，限流应该丢谁的请求？
- 危险信号：限流阈值不知道从哪来；压测只压单接口不压链路；扩容只加应用不看数据库连接数
- 期望信号：从数据库、缓存、下游依赖逐层算容量；压测有影子库或流量标记；限流按用户/接口/租户分级并有优雅拒绝；热点隔离；提到预案与降级开关

### 服务拆分与微服务治理
- 阶梯：为什么拆、什么时候不该拆 → 按什么边界拆（领域、团队、变更频率），共享数据库为什么是反模式 → 拆完之后调用链变长、分布式事务、联调困难怎么办 → 单体、模块化单体、微服务的成本对比
- 好题：一个 30 人团队的单体越来越难发布，你会怎么判断该不该拆、先拆哪一块、怎么做到拆的过程中不停服？
- 危险信号：认为微服务天然更好；拆分依据是技术层（controller/service 分服务）而不是业务边界；没考虑数据归属
- 期望信号：绞杀者模式逐步迁移；数据先解耦再服务解耦；有服务注册发现、配置中心、统一网关的认识但不迷信；能说出拆过头之后的合并案例

### 高并发写入与热点处理
- 阶梯：秒杀、抢券这类场景难在哪 → 库存扣减放 Redis 还是数据库，Lua 原子操作与数据库行锁的对比 → 热点行锁等待、Redis 单 key 打满单分片怎么办 → 准确性、公平性、吞吐三者怎么排优先级
- 好题：一万个人抢一百件商品，你的扣减方案是什么？超卖怎么防、少卖怎么防、Redis 与数据库不一致怎么核对？
- 危险信号：直接 update 库存表扛并发；不知道热点行锁；没有异步落库与对账
- 期望信号：前置拦截（本地限流、排队）、Redis 预扣、异步落库、对账补偿；热点 key 拆分；请求合并；能说出 Redis 宕机时的兜底

### 存储选型与数据建模
- 阶梯：关系型、KV、文档、宽表、搜索、时序各适合什么 → 同一份数据多副本（主库 + ES + 缓存）怎么保持同步 → CDC/binlog 同步延迟、乱序、丢失的处理 → 多存储带来的一致性与运维复杂度值不值
- 好题：商品搜索要支持多条件筛选与全文检索，你会把数据同步到 ES 吗？怎么同步、延迟多久、ES 挂了搜索怎么办、两边数据不一致怎么发现？
- 危险信号：什么都放 MySQL 或什么都放 MongoDB；双写却不处理失败；不知道 binlog 订阅这条路
- 期望信号：按查询模式选存储；CDC 而不是双写；有对账任务；ES 降级回数据库简单查询

### 配置、发布与变更管理
- 阶梯：为什么大多数故障来自变更 → 灰度发布、蓝绿、金丝雀的区别，配置中心的动态推送 → 发布中新老版本共存导致的兼容问题、回滚时数据库 schema 怎么办 → 发布频率与稳定性的平衡，什么该自动化
- 好题：一次发布后 10% 机器错误率升高，你怎么判断是新版本问题还是机器问题？回滚了但数据库已经跑了迁移脚本怎么办？
- 危险信号：发布靠人肉；schema 变更与代码变更绑在一次发布里；没有回滚演练
- 期望信号：先扩后缩的 schema 变更（加列、双写、切换、删列）；灰度按机器/用户比例并观察指标；配置变更也走灰度；变更记录可查

### 安全与鉴权基础
- 阶梯：认证与授权的区别 → session、JWT、OAuth2 各适合什么，JWT 怎么吊销 → 越权访问（横向/纵向）怎么在框架层统一防、接口被刷怎么处理 → 安全措施对性能与开发效率的影响
- 好题：用户反馈能看到别人的订单，你怀疑哪些环节？怎么在架构上让这类漏洞不再依赖每个开发者记得检查？
- 危险信号：认为 JWT 天然安全；鉴权散落在各个 controller；敏感数据明文存日志
- 期望信号：资源级权限校验在统一层；JWT 短有效期 + 刷新或黑名单；接口签名与风控；日志脱敏

## 好题 / 坏题对比

- 坏：说说缓存穿透、击穿、雪崩分别是什么、怎么解决。
- 好：你负责的商品详情页缓存命中率半小时内从 98% 掉到 60%，数据库 CPU 从 30% 涨到 90%，告诉我你打开监控后看的前三个指标，以及三种可能的原因各自对应什么修法。

- 坏：介绍一下微服务架构的优缺点。
- 好：你的服务依赖的一个下游 P99 从 50ms 涨到 2s，下游并没有宕机，但你的整个服务不可用了。为什么会这样？改造后要做到"下游变慢只损失那一个功能"，需要动哪几处？

- 坏：分布式事务有哪些方案？
- 好：下单要同时扣库存和扣优惠券，两个服务两个库。产品要求"要么都成功"。你会怎么做？如果扣券成功后库存不足，补偿又失败了呢？有没有办法通过改流程让这里根本不需要分布式事务？

## 项目结合钩子

- 简历出现"高并发" → 追具体 QPS、P99、机器数、瓶颈在哪一层、压测怎么做的；说不出数字的要标记
- 简历出现 Redis → 追缓存了什么、命中率、大 key/热 key 怎么处理、Redis 挂了系统会怎样、有没有出过缓存一致性事故
- 简历出现 Kafka/RocketMQ/RabbitMQ → 追消费幂等怎么做、堆积过没有、顺序有没有要求、分区数怎么定的
- 简历出现分库分表 → 追分片键、跨片查询怎么办、扩过容没有、为什么不先做归档或读写分离
- 简历出现微服务 → 追拆了几个、按什么拆、拆完最痛的问题是什么、有没有合并过
- 简历出现"性能优化 X%" → 追优化前后指标、怎么定位瓶颈、是不是压测环境的数字、上线后有没有回归
- 简历出现线上故障处理 → 追告警怎么发现、多久定位、根因是什么、事后改了什么机制
- 简历出现"接口设计" → 追幂等、分页、错误码、版本兼容怎么做的，有没有被上游重试打爆过

## 出题原则

- 栈无关：本包只考架构与方法论，具体语言与框架细节交给对应的 stack 包（backend-java、backend-go 等）追问。
- 每道题必须有数字：候选人说了任何架构决策，追 QPS、数据量、延迟、机器数，用规模检验方案是否过度设计或设计不足。
- 优先考故障与取舍：不问"X 是什么"，问"X 坏了长什么样""为什么不用更简单的 Y"。
- 结合候选人项目规模出题：日活几千的项目不问分库分表，日活千万的项目必须追容量、降级与变更管理。
