vault backup: 2026-08-09 19:06:40

This commit is contained in:
2026-08-09 19:06:40 +08:00
parent e2975eb86b
commit 9d664545c9
46 changed files with 7287 additions and 0 deletions
@@ -0,0 +1,142 @@
---
tags: [test/review, architecture, arch/cicd]
create time: 2026-08-09 12:00
---
# K8s 发布与可观测性体系 — 测试题
## 概述
本测试覆盖 RollingUpdate 策略详解、蓝绿部署 vs Canary 发布、HPA/VPA 自动扩缩容、Prometheus 指标采集链路、Grafana Dashboard 数据源以及日志收集方案。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
K8s Deployment 的 RollingUpdate 策略中,`maxUnavailable=0` 和 `maxSurge=1` 的含义是:
A. 更新期间最多有 0 个新 Pod 同时运行
B. 逐台升级,保证零停机——每次只启动 1 个新 Pod,旧 Pod 终止后再启动下一个
C. 所有 Pod 同时替换,然后检查是否可用
D. 先删除全部旧 Pod 再创建新 Pod
### Q2(基础)→
Canary 发布相比蓝绿部署的主要优势是什么?
A. 回滚速度更快
B. 资源消耗更低
C. 风险最低——只有小部分用户先体验新版本
D. 实现复杂度更低
### Q3(进阶)— 核心原理
HPA(Horizontal Pod Autoscaler)扩容的基本计算公式是:
A. `targetReplicas = currentReplicas * desiredMetricValue / currentMetricValue`
B. `targetReplicas = ceil(currentReplicas * currentMetricValue / desiredMetricValue)`
C. `targetReplicas = currentReplicas + (currentMetricValue - desiredMetricValue)`
D. `targetReplicas = floor(currentReplicas * 2)`
### Q4(进阶)— 比较/辨析
以下关于 Prometheus Pull 模式的说法哪个是正确的?
A. Push 模式下失联的服务会立即被标记为 down
B. Pull 模式下失联的 service 会自动被忽略(不再收到数据即标记为 down)
C. Prometheus 不支持自定义业务指标
D. Prometheus 的采集间隔是实时的,没有延迟
### Q5(深入)— 场景推理
某秒杀系统需要在流量洪峰到来前自动扩容。以下方案最合理的是:
A. 完全依赖 HPA,等 CPU 使用率上升后触发扩容
B. 提前设置 minReplicas >= 预期峰值的 80%,配合 HPA 动态调整上限
C. 使用 VPA Auto 模式代替 HPA
D. 手动扩容并在活动结束后手动缩容
### Q6(深入)— 源码级/边界场景
关于 Prometheus 的四种核心指标类型,以下匹配哪个是错误的?
A. Counter — 单调递增计数器,适合画 Rate 曲线
B. Gauge — 可上可下的仪表值,如活跃连接数
C. Histogram — 分桶统计,自动生成 count + sum + bucket
D. Summary — 服务端计算分位数(P50/P99),客户端不做计算
---
## 二、填空题(3道)
### F1 — 填空1
K8s 中新 Pod 必须通过 _____ Probe 才会被加入 Service 的 Endpoint 列表。如果失败,即使新 Pod 已 Running 也不会接收流量。livenessProbe 用于检测进程存活并可能触发重启;而 _____ Probe 用于决定"这个 Pod 是否可以接受流量"。
> **提示**: 两个空填同一种类型的探针名称。
### F2 — 填空2
Fluentd/Filebeat DaemonSet 采集日志后的两种典型存储方案:**ELK 栈**建立_____索引(搜索能力强但存储成本高);**Loki**不建立全文索引,只索引_____(Labels),存储成本极低。
> **提示**: ELK 的核心搜索机制和 Loki 的区别。
### F3 — 填空3
VPA(Vertical Pod Autoscaler)的 Offline 模式行为是_____——只推荐建议值而不直接应用,人工审核后手动调整。这种模式适合_____阶段。
> **提示**: 原文 VPA 表格中的描述。
---
## 三、简答题(1道)
### S1
面试官问:"HPA 能基于自定义业务指标(如 Kafka 消费 lag、QPS)进行扩缩容吗?如何做到?"请给出完整回答,包括必要的组件链和技术路径。
> **答题框架提示**:
> 1. 明确回答能否
> 2. 解释 Custom Metrics API 的工作原理
> 3. 列出关键组件及其职责
> 4. 结合实际场景举例
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | B | maxSurge=1 表示更新过程中允许超出目标副本数 1 个,maxUnavailable=0 表示不允许任何不可用实例。逐台升级确保零停机,但速度慢。生产环境高可用场景推荐此配置。 |
| Q2 | C | Canary 只有少量流量进入新版本(如 10%),大部分用户还在稳定版。这样风险最低——有问题也只影响一小部分用户。蓝绿需要双倍资源,且一旦切到新版本就是全部流量都有问题。 |
| Q3 | B | `ceil(current * current_metric / desired_metric)`。例如当前 5 副本,CPU 91%,目标 70% → ceil(5 × 91 / 70) = ceil(6.5) = 7。注意分子是当前值、分母是目标值。 |
| Q4 | B | A 错:Push 模式下挂了停止发数据但采集器不知道不存在了;C 错:通过 Custom Metrics API + adapter 可以读任意业务指标;D 错:采集间隔 15~60 秒,有分钟级延迟。 |
| Q5 | B | HPA 不是实时的(依赖 metrics-server 15~60 秒采样),等 CPU 上升再扩容已经来不及。minReplicas 预热的做法可以应对已知高峰。VPA 不适合因为它是垂直扩缩(改资源配额需重建 Pod),不能快速应对流量变化。 |
| Q6 | D | D 错误——Summary 的分位数计算在**客户端**完成(SDK 内部算 P50/P99),服务器端不做计算但有额外开销。Histogram 是在服务器端做分桶统计。原文原话:Summary = 客户端计算分位数。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `readiness`;`readiness` | Readiness Probe 决定 Pod 是否能接收流量(加入 Endpoint)。livenessProbe 检测进程是否存活。二者职责不同:Ready = 可服务,Live = 没挂。 |
| F2 | `全文`;`Labels` | ELK 对每个字段建 inverted index 支持全文检索,但 JSON 结构化索引非常占空间。Loki 只对 Labels 建索引,查询时先用 label 过滤再检索内容,存储成本低几个数量级。 |
| F3 | `只推荐不应用`;`微服务刚上线` | 刚上线阶段运维难以精确预估资源需求,可以让 VPA 学习实际使用模式后给出最优建议。Offline 模式不会自动修改 Pod Spec,避免误配导致业务中断。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **明确回答**:可以。HPA 不仅支持 CPU/内存指标,还支持自定义业务指标。
2. **Custom Metrics API**:HPA 通过 Kubernetes Custom Metrics API 获取任意指标值,不限于 K8s 原生指标。
3. **关键组件链**:Prometheus adapter(或 custom-metrics-adapter)负责将 Prometheus 中的数据暴露给 Custom Metrics API。流程:App 暴露 /metrics → Prometheus scrape → adapter 查询 Prometheus → HPA 读取指标 → 计算目标副本数。
4. **实际例子**:根据 Kafka consumer lag 扩缩容——当 lag > 阈值时 HPA 增加 Pod 数加快消费;lag < 阈值时缩容节省资源。也可以根据 QPS、错误率等业务指标触发。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[负载均衡算法]]
- [[限流熔断降级]]
@@ -0,0 +1,142 @@
---
tags: [test/review, architecture, arch/distributed, redis-distributed-lock]
create time: 2026-08-09 12:00
---
# Redis 分布式锁 — 测试题
## 概述
本测试覆盖 Redis 分布式锁的核心原理,包括 SETNX 原子性陷阱、Redlock 多实例容错、Redisson 看门狗续期、可重入锁 hash key 设计以及常见死锁场景分析。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
在 Redis 中尝试获取分布式锁时,以下哪段代码存在**最严重**的缺陷?
A. `redis.set("lock", uuid, "NX")`
B. `redis.set("lock", uuid, "NX", "EX", 30)`
C. `redis.setnx("lock", uuid); redis.expire("lock", 30)`
D. Lua 脚本:`if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) end`
### Q2(基础)→
使用 SET NX EX 获取锁后,客户端在持有锁期间宕机了。当锁过期时间到达时,Redis 会自动删除该 key。但如果在业务执行完成之前锁就过期了,会出现什么问题?
A. Redis 会阻塞等待业务完成后再删除 key
B. 其他客户端可能获取到同一把锁,导致数据竞争
C. 自动触发 Redlock 选举新的持有者
D. Lua 脚本检测到异常,自动延长锁有效期
### Q3(进阶)— 核心原理
Redisson 的看门狗(Watch Dog)机制在什么条件下才会启动?
A. 每次调用 `lock.lock()` 时都会启动
B. 只在传入 leaseTime 参数时启动
C. 只有在加锁时**不指定** leaseTime 参数时才启动
D. 看门狗需要手动通过 `startWatchDog()` 命令启用
### Q4(进阶)— 比较/辨析
Redisson 实现可重入锁的数据结构是 Hash 类型,其 key 中存储的内容是什么?
A. client_id 和整数计数
B. threadID 和重入次数
C. UUID 和时间戳
D. hostname 和端口号
### Q5(深入)— 场景推理
在一个包含 5 个独立 Redis 实例的 Redlock 部署中,客户端依次向所有 5 个实例发送 SET lock uuid NX EX 30。其中实例 R1、R3、R5 返回 OK,R2 返回 nil,R4 返回 OK。总耗时 T = 12ms。请问以下判断正确的是:
A. 加锁失败,因为只拿到了 3/5,未达到多数派
B. 加锁成功,有效 TTL 为 30s
C. 加锁成功,有效 TTL 约为 19.988s
D. 加锁成功,有效 TTL 为 20ms
### Q6(深入)— 源码级/边界场景
关于解锁操作,为什么必须用 Lua 脚本保证"检查 value + 删除"的原子性?下面哪个场景最能说明不加原子性的危险?
A. 客户端 A 读取到 key 的 value 是自己的 clientId,但在执行 DEL 之前,锁已过期且客户端 B 重新获得了锁并设置了新的 value。此时 A 的 DEL 会把 B 的锁删掉。
B. Redis 主从切换时主节点未同步 DEL 命令导致从节点仍有锁
C. 客户端网络抖动导致 DEL 超时,锁永远不会被释放
D. SET NX 在高并发下存在多个客户端同时返回 OK 的情况
---
## 二、填空题(3道)
### F1 — 填空1
Redlock 算法要求获得至少 _____ 个节点的 OK 响应才能判定加锁成功(假设部署了 5 个实例)。有效 TTL 的计算公式是:_____ − T(T 为总耗时)。
> **提示**: 回忆 Redlock 的核心规则中关于 N/2+1 的部分。
### F2 — 填空2
Redisson 看门狗的后台任务每 _____ 秒检查一次锁是否仍持有,每次续期到默认 _____ 秒。
> **提示**: 原文中有一个表格列出了看门狗的行为细节。
### F3 — 填空3
解锁 Lua 脚本的核心逻辑:只有当 `redis.call("get", key)` 返回的值等于传入的 _____ 时,才执行删除操作。这是为了防止误删其他客户端持有的锁。
> **提示**: 考虑竞态场景中谁有资格删除这把锁。
---
## 三、简答题(1道)
### S1
某金融系统需要在用户扣款接口上做防重复提交。面试官问你:"为什么不依赖 Redis 分布式锁来保证幂等,而要在数据库层面再加一层唯一约束+CAS?"请结合 Redis 分布式锁的局限性,给出你的完整回答思路。
> **答题框架提示**:
> 1. 从锁本身的可靠性局限谈起(clock drift、主从切换)
> 2. 说明即使锁正确工作也无法替代的业务语义需求
> 3. 提出"双重保障"架构建议
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | A | A 选项只用了 SET NX 而没有设置过期时间(EX/PX),客户端宕机后锁永久不释放——死锁。B 是正确写法(原子 SET NX EX),C 虽然非原子但有 expire 兜底,D 是正确的解锁 Lua 脚本而非加锁。 |
| Q2 | B | 锁自动释放后,其他客户端可以获取到同一把锁,而此时原客户端仍在执行业务逻辑,两个客户端同时对同一资源做写操作,必然产生数据竞争。 |
| Q3 | C | 看门狗只在**不指定** leaseTime 时启动。如果明确传入了 leaseTime,Redisson 认为你已经知道业务执行时间上限,无需续期。 |
| Q4 | B | Redisson 使用 Hash 存储 `{threadID}: count`,threadID 标识是哪个线程获得了锁,count 记录重入次数。unlock 时递减计数,归零才真正删除 key。 |
| Q5 | C | 5 个实例中获得 4 个 OK,4 >= 5/2+1=3,满足多数派所以加锁成功。有效 TTL = 30s - 0.012s ≈ 29.988s。 |
| Q6 | A | 这是经典的"误删他人锁"场景:没有 value 校验就直接 DEL,任何读到旧 value 的客户端都可以删除当前持有者的锁。Lua 脚本将 get + del 打包成原子操作是唯一解。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `3`;`30s`(或"设定值") | Redlock 要求 ≥ N/2+1 = 3 个实例 OK。有效 TTL = 设定过期时间 − 实际耗时,确保即使部分节点因网络延迟稍晚收到 DEL 也不会误判。 |
| F2 | `10`;`30` | 每 10 秒检查一次,续期到默认 30 秒。这意味着只要业务不超过 30 秒且不连续错过 3 次续期,锁就不会意外释放。 |
| F3 | `clientId`(或"客户端标识值") | 只有 value 匹配证明当前客户端确实是锁的持有者,才允许删除。否则可能是锁过期后被新客户端重新获取的场景。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **时钟漂移风险**:NTP 同步异常可能导致系统时钟回拨,使得一个实例已释放锁而客户端仍持旧锁,Redlock 也不能完全规避此问题。
2. **主从切换丢锁**:Redis 单实例在主从切换时,主节点上的锁可能还未复制到从节点就宕机了,从节点成为新主后锁丢失。
3. **业务语义不足**:分布式锁只能保证互斥访问,不能保证"之前是否已经成功执行过"——如果第一次请求成功但网络超时导致客户端重试,锁无法区分这两次请求。
4. **数据库兜底的不可替代性**:唯一索引 + CAS 是最终防线,即使锁层面全部失效,数据库层面仍然能保证不会重复扣款。
5. **最佳实践**:应采用"锁 + 数据库二次校验"的双重保障策略,锁提升性能减少冲突,数据库保证最终一致性。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[ZooKeeper 分布式锁]]
- [[限流熔断降级]]
@@ -0,0 +1,146 @@
---
tags: [test/review, architecture, arch/distributed, zookeeper-distributed-lock]
create time: 2026-08-09 12:00
---
# ZooKeeper 分布式锁 — 测试题
## 概述
本测试覆盖 ZooKeeper 分布式锁的核心机制,包括临时顺序节点创建、Watch 一次性触发、公平锁实现原理、ZAB 协议 CP 保证以及与 Redis 锁的系统级对比。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
ZK 分布式锁中创建节点的类型是什么,使得客户端断开连接后能自动清理锁?
A. PERSISTENT — 持久节点,需手动删除
B. EPHEMERAL_SEQUENTIAL — 临时顺序节点
C. PERSISTENT_SEQUENTIAL — 持久顺序节点
D. EPHEMERAL — 临时节点但无序号
### Q2(基础)→
以下关于 ZK Watch 机制的说法中,哪一个是正确的?
A. Watch 被触发后会保持注册,持续监听后续变化
B. Watch 是一次性的(One-shot),触发后需要重新注册
C. Watch 只在 `getData` 调用时才会注册
D. Watch 事件通过数据读取通道推送,确保顺序性
### Q3(进阶)— 核心原理
ZK 分布式锁天然实现了公平性,其根本原因是什么?
A. Leader 节点按 FIFO 队列分配锁
B. 使用 SEQUENTIAL 序号决定锁的持有权,按序号大小排序
C. Watch 事件按时间戳排序后分发给等待者
D. ZAB 协议保证了写操作的原子性和有序性
### Q4(进阶)— 比较/辨析
Redis 锁 vs ZK 锁在一致性模型上的主要区别是:
A. Redis 和 ZK 都是 AP 系统
B. Redis 是 CP,ZK 是 AP
C. Redis 单实例是 AP(Redlock 不确定),ZK 是 CP(ZAB 强一致)
D. Redis 是 CP,ZK 是不确定的
### Q5(深入)— 场景推理
N = 3 的 ZK 集群遭遇网络分区,左右各有一个节点。以下描述正确的是:
A. 两边都能正常工作,各自选出新 Leader
B. 左边可以继续写,右边拒绝服务
C. 都无法达成 Quorum,全部停止工作
D. 自动合并为 N=2 集群继续服务
### Q6(深入)— 源码级/边界场景
ZK 会话超时默认 40 秒太长了。根据原文建议,会话超时应该设为多少?同时心跳间隔与会话超时的关系是什么?
A. 建议 1~5 秒;heartbeat = timeout / 5
B. 建议 3~10 秒;heartbeat = timeout / 3
C. 建议 5~15 秒;heartbeat = timeout / 2
D. 建议 10~30 秒;heartbeat = timeout / 4
---
## 二、填空题(3道)
### F1 — 填空1
ZK 分布式锁使用的事件类型是 _____,当子节点列表发生变化时,所有相关监听者都会收到通知。
> **提示**: 这个事件的英文命名直接表达了"节点子列表变化"的含义。
### F2 — 填空2
ZAB 协议的第一个核心阶段是 _____,通过比较 ZXID(事务 ID)选出拥有最大 ZXID 的节点作为 Leader。第二个阶段是 Atomic Broadcast。
> **提示**: 回想 ZAB 的两个核心阶段名称。
### F3 — 填空3
Curator 是 ZK 最流行的 Java 客户端,加锁成功后需要在 finally 块中调用 _____() 方法。该方法会递归释放所有重入计数,而不仅仅是一次 unlock。
> **提示**: Curator 的方法名不是简单的 unlock,而是表达"释放锁"的动作。
---
## 三、简答题(1道)
### S1
某团队正在选型分布式锁方案,有人主张:"ZK 锁比 Redis 锁高级,我们应该用 ZK。"请结合原文内容,从以下几个维度给出你的分析并做出选型建议:
- 一致性要求
- 性能需求
- 运维复杂度
- 业务场景匹配度
> **答题框架提示**:
> 1. 先反驳"更高级就更好"的思维误区
> 2. 从三个维度客观对比
> 3. 给出具体场景下的推荐方案
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | B | EPHEMERAL_SEQUENTIAL = 临时 + 顺序。EPHEMERAL 语义保证 session 断开时自动清理,SEQUENTIAL 提供全局有序性。D 选项 EPHEMERAL 虽然也会自动清理,但没有序号就无法实现公平锁。 |
| Q2 | B | Watch 是一次性的,触发后自动注销。客户端必须在接收到事件后立刻重新注册,否则可能永远不再收到下一次通知。 |
| Q3 | B | 因为节点是 SEQUENTIAL 的,按序号大小决定锁的持有权——最小序号获得锁,其他节点按从小到大依次监听前一个节点。这是天然 FIFO 公平性。 |
| Q4 | C | Redis 单实例是 AP(追求高可用),Redlock 的一致性甚至不确定;ZK 基于 ZAB 协议是 CP(追求强一致性),脑裂时宁可停服也不会出现两把锁同时存在。 |
| Q5 | C | N=3 时 Quorum = 2。每个分区只有 1 个节点,无法达到半数(≥2),所以两个分区都无法工作。这是 CP 系统的必然结果——安全性优先于可用性。 |
| Q6 | B | 建议设为 3~10 秒以更快感知宕机。但 heartbeat interval = timeout / 3,太短的 timeout 会导致心跳过于频繁增加网络开销。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `NodeChildrenChanged` | ZK 锁场景下关注的是子节点列表的变化。当上一个持有者删除节点后,下一个等待者的 watch 会收到 NODE_DELETED 事件进而 getChildren 重新竞争。 |
| F2 | `Leader Election` | ZAB 的两阶段:① Leader Election 选举 Leader;② Atomic Broadcast Leader 广播 Proposal,Follower 回复 ACK 达到半数后提交。 |
| F3 | `release` | Curator 的 InterProcessMutex.acquire() 支持重入,release() 会递归递减重入计数直到归零才真正发送删除请求。直接用 delete 会导致重入计数未释放。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **"更高级"思维误区**:ZK 不是为"高级"设计的,而是为"强一致性协调"设计的。不要因为技术栈偏好而引入不必要的复杂度。
2. **一致性维度**:如果业务只需要简单互斥(如防止用户重复点击),Redis SET NX 足够好,CP 过度设计。如果需要 Leader 选举等强一致性保证,ZK 更适合。
3. **性能维度**:Redis 百万级 QPS(内存操作),ZK 需写事务日志同步复制,QPS 低一个数量级。高频短锁场景 Redis 明显更优。
4. **运维维度**:Redis 集群工具链成熟,ZK 需要维护奇数节点集群,运维成本高。
5. **结论**:简单互斥 → Redis + SET NX EX;强一致性少量并发控制(Leader 选举、Job 唯一绑定)→ ZK;不要为了"更高级"而上 ZK。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[Redis 分布式锁]]
- [[幂等设计方案]]
@@ -0,0 +1,145 @@
---
tags: [test/review, architecture, arch/idempotency]
create time: 2026-08-09 12:00
---
# 幂等设计方案 — 测试题
## 概述
本测试覆盖六种主流幂等方案(唯一索引防重、Token 预获取、乐观锁版本号校验、状态机校验、网关 Request ID 去重)以及三层防御最佳实践。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
以下哪个描述最准确地表达了"幂等"的概念?
A. 相同的请求只在系统中出现一次
B. 多次执行同一操作与执行一次的效果相同
C. 使用 Redis SETNX 来防止重复执行
D. 数据库的 UNIQUE INDEX 约束
### Q2(基础)→
以下哪种幂等方案**不适合**短延迟批处理场景(如批量导入数据)?
A. 数据库唯一索引防重
B. Token 预获取模式
C. 乐观锁版本号校验
D. 网关层 Request ID 去重
### Q3(进阶)— 核心原理
Lua 脚本 `if redis.call("GET", key) == expected then redis.call("SET", key, "USED") end` 在 Token 幂等模式中的核心作用是什么?
A. 设置 Token 的过期时间
B. 原子性地检查 Token 是否有效并标记为已使用
C. 生成一个新的 Token
D. 删除已经过期的所有 Token
### Q4(进阶)— 比较/辨析
以下关于各幂等方案的对比中,哪一个是错误的?
A. 唯一索引防重的实现复杂度低但会额外占用存储
B. Token 预获取可以防止 CSRF
C. 状态机校验不需要额外的数据结构
D. 网关 Request ID 方案可以保证跨重试窗口外的重复请求也被拦截
### Q5(深入)— 场景推理
某支付系统收到同一笔交易的重复扣款请求(同一个 biz_no)。以下哪种组合方案能提供最可靠的防护?
A. 仅用数据库唯一索引
B. 仅用网关 Request ID
C. 三层防御:网关 Request ID → Token 模式 → 数据库唯一索引兜底
D. 仅用乐观锁版本号
### Q6(深入)— 源码级/边界场景
使用唯一索引做幂等时,以下哪种做法可以正确避免 ToCToU 竞态条件?
A. SELECT count(1) WHERE biz_no='xxx',如果为 0 则 INSERT
B. 直接 INSERT,利用 Duplicate entry 错误判断已被处理过
C. SELECT FOR UPDATE 后手动插入
D. 先在内存 Map 中记录已处理的 biz_no
---
## 二、填空题(3道)
### F1 — 填空1
去重是_____,幂等是_____。去重是手段,幂等是目标——用唯一索引去重是为了达到幂等效果。
> **提示**: 原文中有明确的区分:"XX是强调语义...YY是强调数据..."
### F2 — 填空2
Token 预获取模式中,客户端先调用 _____ 接口获取一次性 Token,服务端存入 Redis 并设置过期时间(如 5 分钟),然后客户端携带 Token 发起实际业务请求。
> **提示**: 回想原文中描述的完整流程步骤。
### F3 — 填空3
Redis SETNX **不适合**单独做业务幂等的原因是:Redis 非持久化宕机可能丢数据;而且 SETNX 只能保证互斥,不能保证"之前是否已经_____过"。
> **提示**: 考虑 SETNX 的能力边界。
---
## 三、简答题(1道)
### S1
某电商下单接口面临用户重复点击导致重复创建订单的问题。请设计一个完整的幂等方案,要求:
1. 从流量入口到数据存储的全链路设计
2. 说明每层的作用和依赖关系
3. 讨论失败降级策略
> **答题框架提示**:
> 1. 第一道防线:什么位置做什么事
> 2. 第二道防线:什么机制保证什么
> 3. 第三道防线:最终兜底
> 4. 异常场景分析
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | B | 幂等的定义是"多次执行与执行一次效果相同"。A 是去重的定义,C 和 D 是实现幂等的手段而非定义本身。 |
| Q2 | B | Token 模式需要多一次 API 调用(先领 token 再提交),对于批量导入这种高频操作会严重拖慢用户体验。此时唯一索引方案更合适。 |
| Q3 | B | Lua 脚本将 GET 和 SET 打包成原子操作——不存在 ToCToU 竞态。如果分开执行两个步骤,其他线程可能在中间时刻拿到同一个 Token。 |
| Q4 | D | D 是错误的!网关 Request ID 只保护单次请求窗口内的重复(通常设定 TTL 如 300 秒),超出窗口的重复请求无法覆盖。这是其固有限制。 |
| Q5 | C | 三层防御互为补充:网关层拦截大部分重复流量降低后端压力,Token 模式控制高风险操作的不可重入性,数据库唯一索引作为最后防线保证最终一致性。任何一层被突破都有下一层兜住。 |
| Q6 | B | 直接 INSERT 利用 Duplicate entry 错误是最原子性的做法。A 是典型的 ToCToU——检查和插入之间有竞态窗口。C 的 SELECT FOR UPDATE 也可以但不如 D 简洁高效。D 的内存 Map 不解决分布式问题。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `数据`;`语义` | 去重强调数据层面——相同的请求只出现一次;幂等强调语义层面——多次执行结果相同。去重是手段,幂等是目标。 |
| F2 | `/token/generate` | Token 预获取流程:① 客户端调用 /token/generate 获取一次性 Token;② 服务端存入 Redis,UNUSABLE 状态,5 分钟过期;③ 客户端携带 Token 发起业务请求;④ 服务端 Lua 原子消费 Token。 |
| F3 | `成功执行` | SETNX 只能保证"此刻没人持有这个 key",但不能回答"之前是否已经成功处理过这个请求"。除非你在 Redis 里也存一份状态——那本质上就是把数据库该做的事搬到了 Redis。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **第一道防线(网关层)**:客户端在 HTTP 头中携带 X-Request-ID(UUID),网关层用 Redis SETNX reqid:id 1 EX 300s 做去重。重复请求直接从缓存返回之前的响应。
2. **第二道防线(业务层)**:对支付等高风险接口采用 Token 模式——用户必须先领取一次性 Token 才能提交订单,Token 原子消费确保不可重入。
3. **第三道防线(存储层)**:order_idempotent 表以 biz_no 为唯一索引。INSERT 时 Duplicate entry → 查询已有结果返回。
4. **异常降级**:网关层 Redis 挂了时放行(靠后续两层兜底);Token 服务挂了时切换到 Request ID 模式(用户体验下降但不会中断);数据库层永远生效因为它是物理约束。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[Redis 分布式锁]]
- [[ZooKeeper 分布式锁]]
@@ -0,0 +1,146 @@
---
tags: [test/review, architecture, arch/microservice, service-discovery]
create time: 2026-08-09 12:00
---
# 服务注册与发现 — 测试题
## 概述
本测试覆盖服务注册/注销/续约流程、Eureka/AP 取向、Nacos CP/AP 可切换、Consul 特性以及 CAP 理论在注册中心中的体现。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
服务注册的标准三步走流程是:
A. 注册 → 查询 → 注销
B. 注册 → 续约(心跳)→ 注销
C. 发现 → 健康检查 → 更新
D. 心跳 → 续约 → 下线
### Q2(基础)→
Eureka 的自我保护机制在什么条件下会被触发?
A. 15 分钟内超过 50% 实例未发送心跳
B. 15 分钟内超过 85% 实例未发送心跳
C. 所有实例同时宕机
D. 注册中心 CPU 使用率超过 90%
### Q3(进阶)— 核心原理
Nacos 在同一套代码中为什么能既支持 AP 又支持 CP 模式?
A. 通过动态切换一致性协议实现,运行时修改配置即可
B. 两种模式使用不同的数据存储路径和服务类型
C. Nacos 有两个独立的二进制进程分别处理 AP 和 CP
D. 基于 K8s Namespace 做逻辑隔离
### Q4(进阶)— 比较/辨析
Consul 的三个独特优势不包括以下哪一项?
A. Serf Gossip 协议的成员管理
B. 丰富的健康检查方式(TCP/HTTP/script/Docker/TTL)
C. 内嵌 Raft 一致性的 KV 存储
D. 原生支持多级缓存(本地 + 远程)
### Q5(深入)— 场景推理
某金融系统对数据一致性要求极高,在选型服务注册中心时最应该考虑哪个因素?
A. 需要高可用容忍短暂不一致 → 选 Eureka
B. 需要强一致性 → 选 Nacos CP 模式或 Consul TCP 接口
C. DNS 接口最快 → 选 Consul DNS
D. 客户端缓存最可靠 → 选 Eureka 并关闭自我保护
### Q6(深入)— 源码级/边界场景
PACELC 理论对 CAP 做了哪些补充?
A. PACELC 指出无分区时也需权衡延迟与一致性
B. PACELC 指出分区恢复后需先进行数据同步再服务
C. PACELC 引入了第三维度——性能,CAP 只有两个维度
D. PACELC 证明 CAP 定理在分布式系统中是错误的
---
## 二、填空题(3道)
### F1 — 填空1
Eureka 的消费者会**缓存**服务列表,默认每 _____ 秒刷新一次。这样即使注册中心完全不可用,消费方依然能根据本地缓存继续通信。
> **提示**: 回顾原文 Eureka 小节中关于客户端缓存的描述。
### F2 — 填空2
Consul 的 DNS 接口因为是 _____ 模式的——直接指向随机节点读取本地内存缓存,不经过 Raft 日志——所以速度极快但可能读到旧数据。
> **提示**: 回想 CAP/PACELC 表格中 Consul DNS 的行。
### F3 — 填空3
Nacos 通过 _____ 实现环境隔离(dev/test/prod),每个命名空间有独立的服务和配置视图。底层基于 PostgreSQL 存储元数据。
> **提示**: Nacos 的环境隔离术语来自 Kubernetes。
---
## 三、简答题(1道)
### S1
面试官问你:"Eureka 的自我保护机制在生产环境中什么时候该关?"请给出你的完整回答,包括:
- 自我保护机制的作用是什么
- 关了会有什么风险
- 什么场景下可以关
- 如果不关应该如何监控
> **答题框架提示**:
> 1. 解释机制的原理和风险
> 2. 分场景讨论
> 3. 给出具体的监控建议
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | B | 标准三步:① 注册服务(POST /register);② 心跳续约(维持 lastDirtyTimestamp);③ 主动注销(DELETE /deregister)。故障场景下感知延迟通常为续约超时周期(30~90 秒)。 |
| Q2 | B | 15 分钟内超过 85% 实例未发心跳触发保护窗口锁定,不再剔除任何实例。宁可多调几次失败也不主动剔。 |
| Q3 | B | 不同模式使用不同的存储路径和服务类型:CP 用 `nacos.v1.auth.user`(Raft),AP 用 `nacos.v1.instance`(Distro)。不是运行时切换而是物理隔离的路径。 |
| Q4 | D | Consul 的优势是 Serf Gossip、丰富健康检查、KV 存储。多级缓存不是 Consul 的功能,那是 Redis/Caffeine 层的职责。 |
| Q5 | B | 金融系统需要强一致性,应选 Nacos CP 模式(Raft)或 Consul TCP 接口(Raft Leader)。Eureka 最终一致不适合。DNS 可能 stale。关闭自我保护会增加雪崩风险。 |
| Q6 | A | PACELC = PA(Partition tolerant, choose Availability)+ EC(Else, choose Between Consistency and Latency)。CAP 只讨论分区场景,PACELC 补充了无分区时的 L/C 权衡。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `30` | 消费者每 30 秒刷新一次本地缓存。结合 Eureka 的续约超时周期(通常 30~90 秒),故障检测延迟约在一个续约周期左右。 |
| F2 | `AP` | Consul DNS API 直接读取随机节点的本地内存缓存,不走 Raft 日志,因此速度快但读到的可能是 stale data。如果需要强一致则走 TCP 端口。 |
| F3 | `namespace` | Nacos 的 namespace 相当于 K8s 的 Namespace,实现 dev/test/prod 的物理隔离。每个 namespace 独立存储服务列表和配置数据。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **机制作用**:自我保护防止因网络抖动大量实例被误判为宕机而批量剔除,避免雪崩式下线。
2. **关了的风险**:一旦关闭,心跳稍微延迟就会被剔除,一批实例被认为故障全部移除,调用方拿不到任何健康实例。
3. **适用场景**:金融类对一致性要求高的场景可以考虑关闭;普通互联网业务不建议关,误判的危害大于不调用的危害。
4. **监控建议**:生产环境必须监控 `eureka.server.selfPreservationThreshold` 指标,当该阈值被触发时告警通知运维介入检查。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[负载均衡算法]]
- [[限流熔断降级]]
- [[配置中心设计]]
@@ -0,0 +1,142 @@
---
tags: [test/review, architecture, arch/microservice, load-balancing]
create time: 2026-08-09 12:00
---
# 负载均衡算法 — 测试题
## 概述
本测试覆盖客户端 vs 服务端负载均衡架构、轮询/随机/一致性哈希/最少连接等核心算法、Spring Cloud LoadBalancer 实现原理以及加权轮询的工程实现。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
以下关于客户端负载均衡与服务端负载均衡的说法中,正确的是:
A. 客户端负载均衡延迟更高,因为多了一次网络跳
B. 服务端负载均衡的故障隔离更好——LB 单点故障不影响其他调用
C. 客户端负载均衡需要为每种语言实现 SDK,服务端 LB 协议无关
D. Nginx 是客户端负载均衡的典型代表
### Q2(基础)→
以下哪种负载均衡算法最适合 WebSocket 长连接场景?
A. 简单轮询(Round Robin)
B. 随机法
C. 最少连接数(Least Connections)
D. 一致性哈希
### Q3(进阶)— 核心原理
传统哈希 `hash(instance) % n` 在实例增减时为什么会导致大量请求重新路由?
A. 因为 hash 函数的不均匀性
B. 因为 n 变化后所有 hash 结果对新的 n 取模都变了
C. 因为虚拟节点数量不足
D. 因为 MurmurHash 本身不适合负载均衡
### Q4(进阶)— 比较/辨析
一致性哈希中虚拟节点的主要作用是什么?
A. 提高 hash 值的随机性
B. 解决数据倾斜问题,使物理实例在环上分布更均匀
C. 增加系统容错能力,某节点挂了可以立即接替
D. 减少 hash 冲突的概率
### Q5(深入)— 场景推理
一个微服务有 5 个实例,权重分别为 A=5、B=3、C=2、D=1、E=1(总权重 12)。使用平滑加权轮询算法,第一个被选中的实例一定是:
A. B(权重 3)
B. C(权重 2)
C. A(权重 5)
D. 无法确定,取决于初始 current_weight
### Q6(深入)— 源码级/边界场景
关于 Spring Cloud LoadBalancer,以下说法哪个是正确的?
A. 它内置了重试和熔断能力
B. 基于 Reactor 响应式编程,返回 Flux<ServiceInstance>
C. 默认使用一致性哈希算法
D. 只支持 HTTP 协议的实例选择
---
## 二、填空题(3道)
### F1 — 填空1
一致性哈希将 hash 值空间映射到环上(0 ~ _____),服务和请求都 hash 到环上的同一点,请求顺时针找到最近的实例。移除一个实例只影响其相邻的两个虚拟节点范围,而非全部数据。
> **提示**: 回忆原文中提到的一致性哈希环的范围上限。
### F2 — 填空2
一致性哈希中,每个物理实例对应的虚拟节点数 k 通常取 _____~_____。如果实例频繁增删(每几分钟变一次),k 要调得更大(500+)才能维持稳定性,但会增加内存开销。
> **提示**: 原文中有一个具体的数值范围。
### F3 — 填空3
Nginx 的 smooth weighted round robin 算法中,每次选出 current_weight 最大的实例后,执行 `selected.CurWeight -= _____`,保证长期均衡。
> **提示**: 减去的应该是总权重,这样每个实例的 CurWeight 会在一个周期内回到初始状态。
---
## 三、简答题(1道)
### S1
某电商大促场景中,你有 10 个商品推荐服务实例,其中 3 台是高性能机器(容量大),7 台是普通机器(容量小)。流量高峰时要求充分利用高性能机器的资源。请说明你会选用哪种负载均衡算法,如何配置参数,并解释为什么不用简单轮询或随机法。
> **答题框架提示**:
> 1. 分析场景的核心矛盾(规格差异)
> 2. 推荐算法并说明理由
> 3. 给出具体配置思路
> 4. 讨论边界情况
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | C | A 错:客户端 LB 少一次网络跳所以延迟低;B 错:LB 单点故障影响全部请求,故障隔离差;D 错:Nginx 是服务端 LB。只有 C 正确——客户端 LB 需要各语言的 SDK(如 Spring Cloud LoadBalancer for Java)。 |
| Q2 | C | WebSocket 长连接场景下不同连接的持续时间差异大,最少连接数能保证新请求发给当前活跃连接最少的实例,避免某个实例堆积大量长连接而其他实例闲置。 |
| Q3 | B | 当实例数从 n 变为 n±1 时,几乎所有 key 的 hash(key) % new_n 都会不同于原来的结果,导致约 (n-1)/n 的数据需要迁移。这就是一致性哈希要解决的问题。 |
| Q4 | B | 如果不使用虚拟节点,少数几个物理实例在环上的分布会很不均匀,造成严重的数据倾斜。K=100~200 个虚拟节点让分布趋近均匀。 |
| Q5 | C | 平滑加权轮询第一轮时所有实例的 CurWeight = 0,加上各自 Weight 后 A 的 CurWeight = 5 最大,所以第一轮一定选 A。之后 A 减 12 变为 -7,其他依次加完再选。 |
| Q6 | B | Spring Cloud LoadBalancer 基于 Reactor,返回 Flux<ServiceInstance>。它**不提供**重试和熔断(那是 Resilience4j 的职责),默认策略是 RoundRobinLocator(轮询),不是哈希。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `2^32`(或"4294967296") | 一致性哈希将 32 位 hash 空间映射为环形地址空间,首尾相接。顺时针寻找最近实例的逻辑确保了实例增减时的最小影响范围。 |
| F2 | `100`;`200` | 这是业界经验值。太少了分布不均,太多了内存占用大且维护代价高。频繁增删场景需要 500+ 的虚拟节点数。 |
| F3 | `totalW`(或"总权重 total_weight") | Nginx 的平滑加权轮询核心公式:cur += weight(累积),选 max 后 selected -= total。这样经过一个完整周期,每个实例被选中的次数恰好等于它的权重占比。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **核心矛盾**:性能差异大的实例不能用简单轮询——每台都会被分到相同数量的请求,导致弱机过载而强机资源浪费。
2. **推荐算法**:加权轮询(Weighted Round Robin)。将 3 台高性能机的权重设为普通机的若干倍(如 3:1 或根据实测 QPS 计算比例),使得长期来看请求按容量比例分配。
3. **不选简单的理由**:简单轮询无视容量差异;随机法在小样本下可能极端不均(连续命中同一个弱机),大促场景不能接受这种不确定性。
4. **边界处理**:需要考虑实例下线时的权重动态调整(Hot Restart 机制)、健康检查剔除故障实例后的自动重新加权。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[服务注册与发现]]
- [[限流熔断降级]]
@@ -0,0 +1,144 @@
---
tags: [test/review, architecture, arch/microservice, config-center]
create time: 2026-08-09 12:00
---
# 配置中心设计 — 测试题
## 概述
本测试覆盖 Apollo 三级 Namespace 模型、Nacos Config 长轮询推送机制、配置热更新实现原理、版本管理和回滚策略。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
Apollo 的配置模型中,以下哪一层不是三级结构的一部分?
A. Environment(部署环境:dev/test/prod)
B. Application(业务应用)
C. Namespace(配置类型)
D. Tenant(租户)
### Q2(基础)→
Nacos Config 的秒级推送底层使用什么机制?
A. WebSocket 长连接
B. HTTP 长轮询(Long Polling)
C. MQTT 发布/订阅
D. Redis Pub/Sub
### Q3(进阶)— 核心原理
Nacos Config 长轮询的工作原理是什么?
A. 客户端每 5 秒定时发送请求,服务端每次都立即返回
B. 客户端发起请求后服务端将其挂起在 waitList 中,配置变化时写入 notificationId 后返回;如果 30 秒无变更则超时返回
C. 服务端主动通过 WebSocket 向客户端推送变更通知
D. 客户端通过 Redis Pub/Sub 订阅配置变更事件
### Q4(进阶)— 比较/辨析
以下关于 Apollo 和 Nacos Config 的区别描述中,哪个是正确的?
A. Apollo 用长轮询,Nacos 用短轮询
B. Apollo 的 namespace 支持更细粒度的权限控制和审批流,ConfigMap 只支持键值对映射
C. Nacos 不支持灰度发布,只有全量发布
D. Apollo 不支持多环境隔离,需要手动管理
### Q5(深入)— 场景推理
某团队在生产环境中修改了数据库连接串配置,服务重启后出现大量连接失败。从配置中心的角度看,最根本的原因是什么?
A. 使用了长轮询而非 WebSocket
B. 配置变更没有经过审核+灰度流程,直接全量推送到生产环境
C. Nacos 的 namespace 粒度不够细
D. Apollo 的三级结构过于复杂
### Q6(深入)— 源码级/边界场景
Apollo 的回滚操作本质上是怎样的?
A. 将版本号倒退回上一个版本,删除中间版本的所有记录
B. 用当前最新状态 + 差异计算生成一个新版本,保证发布记录单调递增
C. 复制上一个版本的快照作为新版本,不产生新的变更记录
D. 在数据库中将对应行的 version 字段减 1
---
## 二、填空题(3道)
### F1 — 填空1
Apollo 客户端发现配置新版本的默认拉取周期是 _____ 秒。当服务端生成了新的 releaseKey 后,客户端在下一次拉取时发现版本变化即触发热加载。
> **提示**: 回想原文中 Apollo 灰度发布流程的描述。
### F2 — 填空2
Spring Cloud 中使用 `@RefreshScope` 注解的 Bean 在配置变更后会自动生成_____,使得下次调用 getter 时获取的是最新的配置值。
> **提示**: 这个代理技术是 Spring 框架的核心特性之一,基于 AOP 实现。
### F3 — 填空3
配置热更新最大的风险是配置变更导致服务行为突变。Apollo 的解决方案是"_____+灰度",先让少量实例生效观察指标,再逐步全量。
> **提示**: 两个字的动词,表示一个审核的动作。
---
## 三、简答题(1道)
### S1
面试官问:"为什么 Nacos Config 用长轮询而不是 WebSocket?"请给出你的完整回答,并扩展到以下讨论:
- 长轮询 vs WebSocket 各自的优缺点
- 微服务架构中的中间件链路限制
- 在什么场景下可能考虑 WebSocket
> **答题框架提示**:
> 1. 长轮询的核心优势
> 2. Websocket 的主要劣势(在微服务语境下)
> 3. 混合方案的思考
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | D | Apollo 的三级结构是 Environment → Application → Cluster → Namespace。Tenant(租户)不是 Apollo 的标准层级——那是多租户 SaaS 平台的概念。 |
| Q2 | B | Nacos Config 使用 HTTP 长轮询实现秒级推送。不是 WebSocket(因为要兼容所有 HTTP 中间件),也不是 MQTT 或 Redis Pub/Sub。 |
| Q3 | B | 长轮询核心:客户端请求挂起到 waitList,配置变化时写 notificationId 后立即返回;30 秒超时防止连接无限期挂起。客户端收到通知后再拉取最新配置。 |
| Q4 | B | A 错:两者都用长轮询;C 错:Nacos 也支持灰度发布和回滚;D 错:Apollo 天然支持多环境隔离(namespace 就是为这个设计的)。 |
| Q5 | B | 直接全量推送错误配置是最危险的——所有实例同时失效。正确做法是先审核进入待发布状态,灰度到少数 IP 验证无误后再全量。 |
| Q6 | B | 回滚的本质不是"倒退版本"而是用当前状态 + 差异生成新版本。这样保证了发布记录永远单调递增(版本号一直增长),不会产生环形依赖。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `5` | Apollo Client 每 5 秒轮询一次服务端检查是否有新 releaseKey。这是配置热更新的延迟上限(理想情况下一个拉取周期即可感知变更)。 |
| F2 | `代理 Bean` | @RefreshScope 会动态创建代理对象,每次 getter 调用时检查缓存是否过期,若已过期则从配置中心拉取最新值。 |
| F3 | `审核` | "审核+灰度"流程:编辑配置进入审核状态→审核通过发布→灰度规则指定特定 IP 先接收→验证后全量发布。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **长轮询的核心优势**:兼容所有 HTTP 中间件(网关、CDN、负载均衡器)。微服务架构中请求路径上通常有 Spring Cloud Gateway 等 HTTP-only 代理,这些代理不会做 WebSocket 升级,导致连接断开。
2. **WebSocket 的劣势**:全链路需要升级支持,跨 NAT/防火墙困难;运维复杂度显著增加。
3. **各自的缺点**:长轮询的连接保持期间占用服务端内存;WebSocket 需要维护连接池和心跳保活。
4. **WS 的适用场景**:需要毫秒级推送且能控制全链路的内部系统(如实时协作编辑器、游戏服务器)。对外暴露的微服务配置同步场景不适合。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[服务注册与发现]]
- [[限流熔断降级]]
@@ -0,0 +1,143 @@
---
tags: [test/review, architecture, arch/microservice, rate-limiting]
create time: 2026-08-09 12:00
---
# 限流熔断降级 — 测试题
## 概述
本测试覆盖三种限流算法(滑动窗口、令牌桶、漏桶)、熔断三态转换机制、Sentinel 与 Resilience4j 核心特性以及降级兜底策略。共 10 道题目(6 选择 + 3 填空 + 1 简答)。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
以下哪种限流算法**不允许突发流量**,强制输出匀速?
A. 计数器限流
B. 令牌桶算法
C. 漏桶算法
D. 以上都不对
### Q2(基础)→
熔断器从 Closed 状态转换到 Open 状态的典型触发条件是什么?
A. 单个请求失败
B. 最近 N 秒内成功率为零
C. 失败率超过阈值(如 >50%)
D. HPA 检测到 CPU 使用率过高
### Q3(进阶)— 核心原理
熔断半开(HalfOpen)状态的主要作用是什么?
A. 降低服务器负载,减少请求量
B. 用少量探测请求验证下游是否已恢复,避免直接进入 Closed 后流量暴增导致二次雪崩
C. 为客户端提供缓冲时间,等待前端超时
D. 在 Open 和 Closed 之间做数据同步
### Q4(进阶)— 比较/辨析
Resilience4j 与 Hystrix 的核心区别不包括以下哪项?
A. Resilience4j 基于信号量隔离(轻),Hystrix 基于线程池隔离(重)
B. Resilience4j 采用函数式设计,Hystrix 需要继承 Thread
C. Resilience4j 不依赖 Spring Cloud,可以独立使用
D. Resilience4j 不支持熔断功能
### Q5(深入)— 场景推理
某 API 网关需要对用户接口做限流保护。业务要求允许合理的突发流量(如用户刷新页面同时发多个请求),但限制长期平均速率。以下选型最合理的是:
A. 漏桶——因为保护消费者不被打爆
B. 令牌桶——因为允许突发消费存量令牌
C. 固定窗口计数器——因为实现最简单
D. 并发线程数限流——因为实现最轻量
### Q6(深入)— 源码级/边界场景
Sentinel 的滑动窗口与传统固定窗口的核心区别是什么?
A. Sentinel 使用 Redis 做分布式计数,传统方式用本地内存
B. Sentinel 将窗口细分为更小的 tick,在每个 tick 内独立计数再聚合;固定窗口在边界处会漏算(上一个窗口的尾巴 + 下一个窗口的头同时超限)
C. Sentinel 支持更多算法(令牌桶+漏桶+计数器),传统方式只支持计数器
D. Sentinel 不需要配置阈值,通过自适应学习自动设定
---
## 二、填空题(3道)
### F1 — 填空1
HPA(Horizontal Pod Autoscaler)的计算公式是:`targetReplicas = ceil(currentReplicas * (currentMetricValue / _____))`。例如当前 5 个副本,CPU 目标 70%,当前平均 CPU 使用率 91%,则扩容到 `ceil(5 * 91 / 70) = _____` 个副本。
> **提示**: 第一个空填公式中的占位符名,第二个空填计算结果。
### F2 — 填空2
Prometheus 采集指标使用 Pull 模式而非 Push 模式的原因是:Pull 模式下失联的服务会自动被忽略(不再收到数据即标记为 down),而 Push 模式下挂了的服务停止发送数据但采集器不知道它们已经不存在了。请写出 Prometheus 中四种核心指标类型中的两种:_____、_____。
> **提示**: 任选两种即可——Counter/Gauge/Histogram/Summary。
### F3 — 填空3
Token Bucket 和 Leaky Bucket 的选型建议:**对外暴露 API 时用_____**(允许客户端合理突发);**内部服务间调用时用_____**(保护消费方不被打爆)。
> **提示**: 每个空填一种算法名称。
---
## 三、简答题(1道)
### S1
面试官问:"为什么熔断要从 Open 到 HalfOpen 而不是直接从 Open 回到 Closed?"请详细解释原因,并结合以下场景说明后果:某个下游微服务的数据库连接池被打满,故障正在恢复中。
> **答题框架提示**:
> 1. HalfOpen 的安全阀作用
> 2. 直接回 Closed 的后果分析
> 3. HalfOpen 探测的具体流程
> 4. 补充:如果 HalfOpen 也失败的策略
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | C | 漏桶的核心就是无论输入多猛,输出永远匀速——请求进入桶中排队处理,满了就溢出拒绝。令牌桶允许突发(桶满时可以一次性消耗多个令牌),计数器有窗口边界问题。 |
| Q2 | C | 典型触发条件是失败率超过阈值(如最近 N 秒内失败率 > 50%)。单个请求失败不够成熔断,全为零太极端。 |
| Q3 | B | HalfOpen 是一个安全阀:下游还在恢复时,直接进入 Closed 会让全部流量瞬间灌入,可能导致二次雪崩。有限的探测请求(通常 1~3 个)先验证下游是否真恢复了。 |
| Q4 | D | D 是错误的——Resilience4j **完全支持**熔断功能。它的优势在于函数式 API 和装饰器模式。其他三项都是正确的区别点。 |
| Q5 | B | 令牌桶适合保护生产者:允许突发流量(桶满时可突发消费存量令牌),但长期受限于平均速率。这正是对外 API 网关的需求特征。 |
| Q6 | B | 固定窗口的问题在于边界效应:上一个窗口末尾 0.9 秒的请求和下一个窗口开头 0.9 秒的请求各占各自窗口但不超出阈值,合在一起可能翻倍。Sentinel 将窗口细分为更小的 tick 来消除这个问题。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | `desiredMetricValue`;`7` | ceil(5 × 91 / 70) = ceil(6.5) = 7。HPA 不是实时的——依赖 metrics-server 每 15~60 秒采样,扩容有分钟级延迟。 |
| F2 | `Counter`、`Gauge`(或 Histogram、Summary 任意两种) | Counter = 单调递增(如总请求数);Gauge = 可上可下(如活跃连接数);Histogram = 分桶统计(延迟分布);Summary = 客户端计算分位数(P50/P99)。 |
| F3 | `令牌桶`;`漏桶` | 对外 API 允许合理突发 → 令牌桶;内部服务间保护消费方 → 漏桶匀速处理。 |
### 简答题参考答案
S1:**参考答案要点**:
1. **安全阀作用**:HalfOpen 是 Open 和 Closed 之间的缓冲层,用有限的探针先测试下游恢复情况。
2. **直接回 Closed 的后果**:假设下游 DB 连接池被打满(比如只剩 5 个可用),如果直接从 Open 回 Closed,大量积压请求瞬间涌入会立即再次打满连接池,引发二次雪崩。
3. **HalfOpen 流程**:仅发出 1~3 个探测请求给下游,只有全成功才转入 Closed。任一失败立刻重新进入 Open 并重置倒计时。探测期间原有业务请求仍被拦截。
4. **补充**:如果连续多次 HalfOpen 都失败,可以引入渐进式加大探测流量的策略,或者人工介入告警。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。
## 关联笔记
- [[服务注册与发现]]
- [[负载均衡算法]]
- [[配置中心设计]]