请求到持久化与权衡

共 62 题
📑 题目列表 62 题
#
★★★

1. "写请求返回成功"前需要经过 cache 失效 → DB 写入 → binlog(MySQL)→ 主从同步 → 客户端确认,讨论 commit latency 的临界点。

"写请求返回成功"前需要经过哪些环节?讨论 commit latency 的临界点是什么?

  • 写请求的完整路径
  • 各环节的延迟贡献
  • commit latency 的临界点

一个写请求成功返回前要经过:cache 失效(删除/更新缓存)→ DB 写入(事务提交)→ 写 binlog(MySQL redo+binlog)→ 主从同步(如果要求半同步)→ 客户端确认。commit latency 的临界点在于"何时对客户端返回成功"——若要求同步刷盘(WAL fsync)与主从同步完成才返回,延迟最高但最安全;若返回成功即允许异步刷盘/同步,则延迟低但可能在崩溃时丢数据。工程上:多数场景用"cache 失效 + 本地事务提交(可选 fsync)后即返回",主从同步走异步,牺牲一致性换低延迟;对强一致场景(如金融)则在主从同步(半同步)后返回。临界点是"客户端确认前必须完成哪些持久化/同步"。

这是"延迟 vs 持久化/一致性"的核心权衡。commit latency 的取舍本质是决定"哪些环节必须同步完成"——同步环节越多延迟越高,但数据越安全。

#
★★★

2. "缓存击穿"(cache stampede)的处理,singleflight、分布式锁如何应用。

"缓存击穿"(cache stampede)如何处理?singleflight 与分布式锁各有什么作用?

  • cache stampede 的定义
  • singleflight 机制
  • 分布式锁方案

缓存击穿指缓存中某个热点 key 过期失效后,大量并发请求同时打到数据库,导致数据库压力骤增(甚至被击垮)。处理方案:singleflight(请求合并)——同一时刻多个相同 key 的请求只放行一个去查库,其余等待其结果并复用,避免重复查库;分布式锁——用 Redis 等加锁,保证只有一个请求回源重建缓存,其余等待或直接返回旧值。此外可加"过期续期"(stale-while-revalidate)与"缓存预热"(定时刷新)避免热点 key 过期。工程上常 singleflight + 热 key 预热 + 永不过期组合。

缓存击穿的本质是"热点失效 + 并发放大"。singleflight 合并请求,分布式锁保证单点回源,二者都是"让并发打 DB 变成单打"。

#
★★★

3. "缓存穿透"(cache penetration)的处理,空值缓存、布隆过滤器如何应用。

"缓存穿透"(cache penetration)如何处理?空值缓存与布隆过滤器各有什么作用?

  • cache penetration 的定义
  • 空值缓存
  • 布隆过滤器

缓存穿透指查询不存在的数据(key 既不在缓存也不在数据库),导致每次请求都穿透到数据库,可能被恶意攻击利用。处理方案:空值缓存——把"查无此数据"的结果也缓存(空值 + 短 TTL),避免重复查库;布隆过滤器——在缓存前加一个布隆过滤器,判断 key 是否可能存在,不存在则直接返回,把"不存在"的请求挡在数据库之外。布隆过滤器有误判(可能把不存在的判为可能存在)但无漏判,适合"大量不存在 key"场景。工程上常空值缓存 + 布隆过滤器(或 key 校验)组合。

穿透的本质是"无效 key 绕过缓存直打 DB"。空值缓存减小重复,布隆过滤器把不存在请求挡在前面,二者针对"不存在"场景。

#
★★★

4. "读己之写"(read-your-writes)一致性,在主从架构下的 session 路由策略。

"读己之写"(read-your-writes)一致性如何保证?在主从架构下的 session 路由策略是什么?

  • read-your-writes 一致性
  • 主从复制延迟的挑战
  • session 路由策略

read-your-writes(读己之写)一致性指用户写入后应能立即读到自己刚写的数据。在主从架构(写主读从)下,若复制有延迟,用户写主库后立刻读从库可能读到旧值。保证策略:session 粘性路由(sticky session)——同一用户/session 的写请求路由到主库,且其后一段时间的读请求也路由到主库(或读"已同步到最新"的从库),保证读到自己的写入;或写入后对特定 key 打"近期写过"标记,读该 key 时强制走主库;或用"复制延迟感知"的路由(读前检查复制进度)。工程上常用 session 粘性 + 短暂读主库窗口。

这是"一致性 vs 读扩展"的权衡。读己之写要求写入后读可见,用 session 粘性路由把"刚写用户"的读固定到主库(或已同步副本)即可在不牺牲整体读扩展的前提下保证。

#
★★★

5. "链路预算"(request budget),100ms 总预算的子调用拆分。

"链路预算"(request budget)如何设计?100ms 总预算如何拆分给各子调用?

  • 链路预算的概念
  • 子调用预算分配
  • 超时与兜底

链路预算(request budget)指为一个请求的总耗时设定预算(如 100ms),并拆分子调用来确保整体不超时。100ms 预算拆分:预留缓冲(如 20ms 给网络/调度/序列化),其余按子调用价值分配——核心数据读取(如 DB 主查询)给最多(如 50ms),次要调用(如日志、推荐)给少(如 10ms),并设置每跳超时(通常用"预算的剩余时间"而非固定值,避免叠加超预算)。工程上:按子调用优先级分配、超时用全局 budget 递减(如果只剩 20ms 就快速失败)、关键路径优先、非关键调用可降级/异步。

预算的价值是"总耗时有界"。关键是把"每跳超时"与"总预算"挂钩,避免子调用超时之和超过预算;非关键调用可降级以保核心路径。

#
★★★

6. MySQL 的两阶段提交(XA)vs 单库事务的延迟差异。

MySQL 的两阶段提交(XA)vs 单库事务在延迟上有何差异?

  • XA 两阶段提交
  • 单库事务
  • 延迟差异

单库事务在单个数据库节点的本地事务内完成,提交只需一次本地 commit(落 WAL + 返回),延迟低。XA 两阶段提交(跨库/跨资源分布式事务)需要 prepare 阶段(各参与者准备并锁定)+ commit 阶段(协调者通知各参与者提交),涉及多轮网络交互与协调者节点,延迟显著高于单库事务,且 prepare 阶段会持有锁与资源,增加锁等待与冲突。工程上:优先用单库事务(本地事务)+ 应用层补偿(SAGA/最终一致)避免 XA 的延迟与复杂度;只有强一致跨库场景才用 XA。

XA 的延迟来自"多轮网络 RTT + 协调者 + 资源锁持有"。多数业务用本地事务 + 最终一致替代 XA,以延迟换一致性强度。

#
★★★

7. 从浏览器到数据库的端到端链路,DNS → TCP → TLS → HTTP → 应用线程 → 缓存 → DB → 磁盘。

从浏览器到数据库的端到端链路包含哪些环节?各环节的延迟如何累积?

  • 端到端链路各环节
  • 延迟累积与分解
  • 优化方向

端到端链路:DNS(解析域名)→ TCP(建立连接)→ TLS(加密握手)→ HTTP(请求/响应)→ 应用线程(业务处理、队列等待)→ 缓存(Redis 查缓存)→ DB(SQL 执行)→ 磁盘(WAL/数据落盘)。延迟逐环节累积:DNS+TCP+TLS 是网络握手开销(可用复用/缓存降低),应用线程含排队与逻辑,缓存命中可省去 DB 访问,DB 与磁盘是持久化大头。优化方向:网络层用 keep-alive/HTTP2/缓存,应用层减少排队与串行调用,缓存层提高命中率,DB 层优化 SQL 与索引,磁盘层用 SSD/合理 fsync。定位需分环节打点(trace、各阶段耗时)。

端到端延迟是"网络 + 应用 + 缓存 + DB + 磁盘"的累积。分环节打点定位瓶颈,再逐层优化(复用、缓存、索引、落盘)。

#
★★★

8. 应用层缓存(Redis)vs 数据库缓存(innodb_buffer_pool)的边界。

应用层缓存(Redis)vs 数据库缓存(innodb_buffer_pool)的边界是什么?

  • 两类缓存的定位
  • 数据一致性与使用场景
  • 边界划分

Redis 是应用层缓存,位于应用与数据库之间,缓存"业务解析后的结果/热数据",可跨实例共享、可设 TTL、可做复杂数据结构,但需应用维护一致性(缓存失效/更新),且增加一次网络访问。innodb_buffer_pool 是数据库内部缓存,缓存磁盘数据页,对应用透明,减少磁盘 I/O,但只缓存"原始数据页",无法缓存业务计算结果。边界:Redis 缓存高价值、高命中率、可接受一致性的热数据(如配置、会话、热点结果),innodb_buffer_pool 缓存数据库磁盘页(对 SQL 透明减 I/O)。二者互补:Redis 在上层挡住重复查询,buffer_pool 在底层减少磁盘读。

边界是"业务结果 vs 数据页"。Redis 缓存业务层,buffer_pool 缓存存储层;Redis 需管理一致性,buffer_pool 透明但只缓存原始页。

#
★★★

9. 数据库 fsync(fdatasync)的延迟贡献,磁盘 WAL 写入的 fsync 在 HDD、SSD、NVMe 的差异(ms → μs)。

数据库 fsync(fdatasync)的延迟贡献如何?磁盘 WAL 写入的 fsync 在 HDD、SSD、NVMe 上有何差异?

  • fsync 的作用与延迟
  • 各类磁盘的 fsync 延迟
  • 持久化与延迟权衡

fsync(fdatasync)把数据强制刷到持久化存储并等待确认,是数据库保证持久化的关键,也是提交延迟的主要来源。不同介质差异:HDD 机械盘 fsync 需等待盘片旋转与寻道,延迟数毫秒(约 5-10ms);SSD 闪存需擦除写入,延迟约 0.1-1ms(受写放大与磨损均衡影响);NVMe 高性能闪存延迟可低至几十 μs 甚至更低。工程上:数据库把 fsync 压在 WAL 顺序写(顺序小写 + 组提交),减少每次事务的 fsync 次数;用 NVMe/SSD 显著降低提交延迟;用 group commit(批量提交)合并多次 fsync。fsync 是"持久化 vs 延迟"的权衡点。

fsync 是持久化延迟的核心。WAL + 组提交 + 顺序写把 fsync 开销降到最低,介质从 HDD 到 NVMe 的延迟差是数量级差异。

#
★★★

10. 数据库连接池(HikariCP)的 wait/active 配置与延迟。

数据库连接池(HikariCP)的 wait/active 配置如何影响延迟?

  • 连接池的 active/wait 概念
  • 配置与延迟
  • 调优

HikariCP 连接池维护 active(正在使用的连接数)与 idle(空闲连接数),当请求到来时若无空闲连接则进入等待(wait),直到有连接释放或超时。配置影响:maximumPoolSize 决定最大并发连接,过小则请求排队等待(wait 增大,延迟升高);过大则浪费资源且可能超过数据库连接上限。合理大小:约 (core_count * 2) + disk_spindle,对基于磁盘的数据库;对 SSD 可适当减少。wait 时间反映池饱和——若 wait 持续高说明连接不足,需加大池或优化查询时长。HikariCP 的 minimumIdle 与 maximumPoolSize 协调空闲连接池大小。

连接池的 wait 是"池饱和"信号。池太小导致等待(延迟),太大浪费资源;监控 wait 与 active 判断池大小是否合适。

#
★★★

11. "协程"(goroutine、virtual thread、coroutine)在百万并发的实现差异。

"协程"(goroutine、virtual thread、coroutine)在百万并发上的实现差异是什么?

  • 协程的调度模型
  • goroutine / virtual thread / coroutine 的实现
  • 与线程的对比

协程是用户态轻量级任务,由运行时调度器在少量线程上多路复用,相比 OS 线程可支持百万级并发(线程栈 MB 级,协程栈 KB 级)。实现差异:goroutine(Go)——由 Go 运行时 M:N 调度器(GMP 模型)管理,栈动态增长,可阻塞 I/O 但调度器把阻塞 I/O 交给系统线程;virtual thread(Java,Project Loom)——把 Java 线程映射到载体线程(carrier),阻塞操作自动脱出载体线程,避免阻塞 OS 线程,兼容现有线程 API;coroutine(C++/Kotlin 等)——由编译器/库实现,多为 stackful 或 stackless,需显式调度点。共同点:相比线程,协程创建/切换开销小,支持大规模并发;但需注意其调度器与 I/O 的配合。

百万并发的核心是"轻量任务 + 用户态调度"。协程用运行时调度避免 OS 线程的创建/切换与栈开销,但不同实现(M:N 调度、载体线程、编译器栈)各异。

#
★★★

12. "自适应限流"(adaptive concurrency limit)的 AIMD 算法(TCP 拥塞控制类比)。

"自适应限流"(adaptive concurrency limit)的 AIMD 算法如何工作?它如何类比 TCP 拥塞控制?

  • 自适应并发限制
  • AIMD 算法
  • 与 TCP 拥塞控制类比

自适应限流根据系统实时负载动态调整允许的并发请求数,避免固定限流在负载波动时过严或过松。AIMD(加性增、乘性减)算法类比 TCP 拥塞控制:正常时并发上限"加性增加"(如每个成功窗口 +1),检测到超时/错误/延迟上升时"乘性减少"(如 ×0.5),从而在保持吞吐的同时避免过载。与 TCP 拥塞控制类似,它用"延迟(RTT)或错误率"作为拥塞信号:延迟/错误上升说明系统过载,需降低并发;延迟平稳则逐步增加并发,逼近吞吐上限(knee point)。

AIMD 是"加性增、乘性减"——成功则试探性 +1,故障则减半,天然收敛于稳态并发。类比 TCP 拥塞控制,用延迟/错误率做拥塞信号,无需人工调固定值。

#
★★★

13. "舱壁隔离"(bulkhead),线程池隔离、信号量隔离、连接池隔离的工程实践。

"舱壁隔离"(bulkhead)如何实现?线程池隔离、信号量隔离、连接池隔离各有什么工程手段?

  • 舱壁隔离的概念
  • 线程池/信号量/连接池隔离
  • 故障传播控制

舱壁隔离(bulkhead)借鉴船舱分隔,把不同服务/调用用独立的资源池隔离,避免一个调用耗尽资源拖垮整个系统。实现:线程池隔离——为每个下游/调用分配独立线程池,一个池被打满不影响其他;信号量隔离——用信号量限制并发进入某调用,不占线程但限制并发(如 Hystrix 的 semaphore 模式);连接池隔离——为每个下游/DB 分配独立连接池,避免一个连接池耗尽。工程上:对关键/易故障调用用线程池隔离(隔离更彻底但开销大),对非关键快速调用用信号量隔离(开销小),连接池按资源独立。隔离的本质是"故障局部化"。

bulkhead 是"故障隔离"——资源池彼此独立,一个池耗尽不影响其他。线程池隔离最彻底但占资源,信号量隔离轻量,连接池隔离数据访问。

#
★★★

14. "连接数增加但吞吐不增"的工程诊断,可能瓶颈在 epoll 上限、CPU、内存、I/O、数据库。

"连接数增加但吞吐不增"的工程诊断思路是什么?可能瓶颈在 epoll 上限、CPU、内存、I/O、数据库?

  • 连接数增加但吞吐不增的成因
  • 各类瓶颈排查
  • 系统化诊断

连接数增加但吞吐不增,说明"连接数不是瓶颈,真正的瓶颈在别处"。排查方向:epoll 上限——fd 数/事件上限(ulimit -n、epoll 满)导致新连接无法处理;CPU——CPU 饱和导致加连接不加吞吐;内存——内存不足导致 OOM/交换;I/O——磁盘/网络 I/O 饱和;数据库——连接池满、SQL 慢、锁竞争导致堵塞。诊断:看 CPU/内存/磁盘/网络利用率与队列深度,看连接是否被 accept(epoll 队列),看数据库连接池与慢查询。连接数增加但吞吐不增,往往是"单连接处理能力不够"(每个连接都慢)或"资源已饱和"。

连接数增加不加吞吐,说明是"连接侧"之外的问题。需逐层排查 epoll 处理、CPU、内存、I/O、DB 是否饱和,结合延迟与队列定位真正瓶颈。

#
★★★

15. "连接预热"(warm-up)的工程,如何避免冷启动的延迟劣化。

"连接预热"(warm-up)的工程价值是什么?如何避免冷启动的延迟劣化?

  • 连接预热的目的
  • 冷启动延迟劣化
  • 预热手段

连接预热(warm-up)指在服务启动后、正式流量到来前,主动建立所需连接(数据库、Redis、下游服务、线程池就绪),避免首个请求触发冷启动的延迟劣化。冷启动问题:连接池为空导致首请求需新建连接(握手超时)、TLS 首次握手、JIT/缓存未就绪、配置加载慢。预热手段:启动后主动 ping/建连(连接池预热)、预加载配置与缓存、回放少量请求触发 JIT 编译、预加载类加载。工程上:健康检查通过后再接流量,配合预热减少冷启动延迟尖峰。

冷启动的延迟劣化来自"资源未就绪"。预热把连接、缓存、JIT 等提前就绪,让首请求即达到稳态性能,避免启动期大延迟。

#
★★★

16. "熔断"(circuit breaker)的滑动窗口,count-based vs time-based。

"熔断"(circuit breaker)的滑动窗口如何实现?count-based 与 time-based 有何区别?

  • 熔断器滑动窗口
  • count-based 与 time-based
  • 适用场景

熔断器用滑动窗口统计近期失败率,超过阈值则打开熔断。滑动窗口两种实现:count-based(计数窗口)——统计最近 N 次调用(如最近 100 次)的成功/失败,窗口长度用请求数界定,适合流量稳定场景;time-based(时间窗口)——统计最近 T 秒(如最近 10 秒)的调用,窗口长度用时间界定,适合流量波动场景。count-based 在流量低时窗口时间跨度长(可能过期数据仍算),time-based 在流量高时窗口内请求多(统计更准)。工程上:流量稳定用 count-based,流量波动用 time-based(如 Resilience4j 的 slidingWindow 配置)。

滑动窗口是"统计窗口内的失败率"。count-based 按请求数滑动,time-based 按时间滑动,二者在流量模式下的统计准确性不同。

#
★★★

17. "限流"(rate limit)的"溢出"(overflow)策略。

"限流"(rate limit)的"溢出"(overflow)策略有哪些?

  • 限流溢出处理
  • 丢弃/排队/降级
  • 工程取舍

限流在超过阈值后对"溢出"请求的处理策略:丢弃(drop/reject)——直接返回拒绝(如 429),保系统但用户体验差;排队(queue)——把溢出请求放入队列等待,利用突发容量但增延迟;降级(degrade)——返回降级结果(如缓存默认值)而非完全拒绝;也有的"允许溢出少量"(burst)。工程上:对写操作多用丢弃+重试提示,对读操作可降级(返回旧缓存),对可延迟的批处理可排队。溢出策略本质是"保系统 vs 保体验"的权衡,需结合业务重要性选择。

溢出策略决定"超限请求去哪"。丢弃保系统、排队用突发、降级保体验,按业务差异选择,避免"限流导致所有请求失败"的雪崩。

#
★★★

18. "mTLS"(mutual TLS)在服务间调用的性能开销。

"mTLS"(mutual TLS)在服务间调用有什么性能开销?

  • mTLS 握手开销
  • 加密开销
  • 优化

mTLS 在服务间调用增加两类开销:握手开销——连接建立时双向 TLS 握手(证书交换、双方验证、密钥协商),涉及多轮 RTT 与证书链传输/验证,比单边 TLS 更重;加密开销——后续数据加密/解密与 MAC 计算的 CPU 开销(现代 AES 有硬件加速,影响较小)。服务间短连接高频调用时,握手开销是主要成本(每连接一次握手)。优化:连接复用(keep-alive/连接池)减少握手次数、session resumption 复用会话、证书链瘦身、用更快的曲线(如 X25519);延迟敏感且内网可信任的场景可考虑只在边界做 mTLS。

mTLS 的握手开销(RTT + 证书验证)在短连接高频调用下显著,加密本身因硬件加速影响较小。核心优化是"减少握手次数"。

#
★★★

19. "加密传输"(TLS)vs"端到端加密"(E2EE)的边界与代价。

"加密传输"(TLS)vs"端到端加密"(E2EE)的边界与代价是什么?

  • TLS 与 E2EE 的区别
  • 信任边界
  • 代价

TLS(传输层加密)只保护"客户端到服务器"这一段传输,中间节点(如服务器、代理、CDN)可解密数据,信任边界在服务器;E2EE(端到端加密)加密在两端(发送方到接收方)进行,中间节点(甚至服务器)无法解密,信任边界在接收方。边界:TLS 保护传输链路,E2EE 保护内容本身。代价:E2EE 增加密钥管理复杂度(如何分发密钥、恢复数据)、无法做服务端数据处理(内容不可见)、性能开销(二次加密);TLS 更易部署但内容在服务端可见。工程上:HTTPS 用 TLS;隐私敏感(聊天、文件)用 E2EE。

核心是"信任边界在哪"。TLS 信任服务器,E2EE 信任两端;E2EE 更强隐私但牺牲服务端可用性与密钥管理便利。

#
★★★

20. "加密开销"(encryption overhead)在 HTTPS、TLS、磁盘加密的吞吐影响。

"加密开销"(encryption overhead)在 HTTPS、TLS、磁盘加密中的吞吐影响如何?

  • 各类加密的吞吐影响
  • 硬件加速
  • 优化

加密开销指加密/解密与 MAC 计算消耗的 CPU/资源。HTTPS/TLS 传输加密:AES-GCM 等现代算法有 AES-NI 硬件加速,吞吐影响小(加密不再是瓶颈),但握手(密钥协商)仍占 CPU 与 RTT;磁盘加密(如 LUKS/dm-crypt):全盘加密用 AES-XTS,同样受硬件加速,对顺序读写吞吐影响小,但随机小 I/O 可能受加密粒度影响;软件加密(无硬件加速)场景吞吐显著。整体上:现代硬件加速下,加密吞吐开销已大幅降低,主要开销转移到握手与密钥管理。工程上:用硬件加速、避免重复加密、合理缓存会话。

现代 CPU 的 AES 硬件加速使"加密吞吐"不再是主要瓶颈,成本集中在握手与密钥管理。优化重点是减少握手与复用。

#
★★★

21. "密钥管理服务"(KMS)的中心化与分布式。

"密钥管理服务"(KMS)的中心化与分布式有何取舍?

  • KMS 中心化 vs 分布式
  • 密钥管理的取舍
  • 工程应用

KMS(密钥管理服务)管理密钥的生命周期(生成、分发、轮换、撤销)。中心化 KMS:所有密钥集中在一个服务(如 AWS KMS/HashiCorp Vault),统一管理、审计、权限控制,但引入单点(KMS 故障影响所有加密)与集中瓶颈(高并发加解密请求);分布式 KMS:密钥分散在各节点/本地,各节点本地解密,减少对中心依赖与网络开销,但密钥分发/轮换/撤销更复杂,一致性难保证。工程上:中心化 KMS 用于集中管理和审计,分布式用"本地缓存密钥 + 中心 KMS 管理",密钥不易外泄且解密性能好,需权衡中心可用性与分发复杂度。

中心化优势是"统一管理",分布式优势是"本地高性能与可用性"。常见做法是中心化 KMS 管密钥,分布式缓存解密密钥。

#
★★★

22. "缓存键"(cache key)的设计,如何避免 PII 泄漏与租户越权。

"缓存键"(cache key)如何设计?如何避免 PII 泄漏与租户越权?

  • cache key 设计
  • 租户隔离
  • PII 保护

缓存键(cache key)设计要考虑隔离与安全:租户越权——多租户场景 cache key 必须包含租户标识(tenant_id),否则不同租户可能命中同一缓存键返回对方数据(越权);PII 泄漏——cache key 或缓存值不应包含明文敏感信息(如手机号、身份证),且日志/缓存中避免记录 PII。设计要点:cache key 用业务标识 + 租户标识 + 参数哈希,避免用明文敏感字段做 key;缓存值做脱敏/加密;缓存键加上命名空间(namespace)防止不同业务/版本冲突。工程上:cache key 结构如 tenant:business:object:version:hash,并做权限校验。

cache key 是缓存隔离的边界。不含租户标识会导致跨租户越权,含明文 PII 会泄漏敏感信息。key 设计要带租户、业务、版本与参数哈希。

#
★★★

23. "鉴权缓存"(auth cache)的租户边界,cache key 的设计如何避免越权。

"鉴权缓存"(auth cache)的租户边界如何保证?cache key 如何设计避免越权?

  • auth cache 的租户边界
  • cache key 设计
  • 越权防护

鉴权缓存(auth cache)缓存权限/令牌校验结果,若 cache key 不含租户边界,可能把租户 A 的鉴权结果返回给租户 B(越权)。cache key 必须包含租户/用户标识(tenant_id:user_id:resource),并区分权限维度;同时缓存值本身要绑定租户,避免跨租户共享。此外,权限变更(如用户被撤销权限)要能及时失效缓存,避免陈旧鉴权结果放行。工程上:cache key = 租户 + 用户 + 资源 + 权限版本,缓存 TTL 短且权限变更时主动失效,返回前再校验租户。

鉴权缓存是安全敏感缓存,key 必须含租户边界,且权限变更要能失效。缓存正确性 + 租户隔离 + 及时失效三者缺一不可。

#
★★★

24. "文件系统"(filesystem)的跨平台差异,ext4、xfs、btrfs、ntfs、FAT32 的工程取舍。

"文件系统"(filesystem)的跨平台差异:ext4、xfs、btrfs、ntfs、FAT32 各有什么工程取舍?

  • 各文件系统特性
  • 适用场景
  • 跨平台兼容

各文件系统取舍:ext4——Linux 默认,成熟稳定,支持大文件与日志,通用场景;xfs——高扩展性、适合大文件与高并发写(如大型文件服务器),但也有日志;btrfs——支持快照、压缩、校验和、子卷,功能丰富但性能与复杂度高,适合需要快照/检测的场景;ntfs——Windows 主流,支持权限、日志、大文件,跨平台需额外驱动;FAT32——最广泛兼容(USB、相机),但单文件大小限制 4GB、无权限/日志,适合移动存储。跨平台要点:ext4/xfs 是 Linux 原生,ntfs 是 Windows,FAT32 的兼容性最好但功能受限。工程上:服务器用 ext4/xfs,需快照用 btrfs,跨平台交换用 FAT32/exFAT。

文件系统取舍是"功能、性能、兼容性"的权衡。工程选型看场景:Linux 服务用 ext4/xfs,快照用 btrfs,跨平台便携用 FAT32/exFAT。

#
★★★

25. "时区"(timezone)的数据库存储与展示,UTC 优先策略。

"时区"(timezone)的数据库存储与展示如何设计?UTC 优先策略是什么?

  • 时区存储
  • UTC 优先策略
  • 展示转换

时区处理的最佳实践是"UTC 优先":数据库统一存储 UTC(或带时区的时间戳,如 timestamp with time zone),不存本地时间;展示时由客户端/应用层按用户时区转换。原因:避免服务器时区配置差异导致数据错乱、避免夏令时(DST)跳变歧义、便于跨时区比较与排序。实施要点:存储用 UTC 时间戳(含时区偏移),日志/追踪也用 UTC,只在展示层转换用户时区;时区变更(夏令时)不影响存储。工程上:统一 UTC 存储 + 展示层按用户偏好转换,避免"存本地时间"的常见坑。

时区问题本质是"存储干净、展示转换"。UTC 存储避免夏令时与配置差异,是跨时区系统的标准做法。

#
★★★

26. "特性探测"(feature detection)vs"特性协商"(feature negotiation)的客户端/服务器边界。

"特性探测"(feature detection)vs"特性协商"(feature negotiation)在客户端/服务器边界有何区别?

  • feature detection 与 negotiation
  • 客户端/服务器职责
  • 协议设计

feature detection(特性探测)指客户端或服务器主动检测对方是否支持某特性(如用测试请求/能力探测),不依赖显式协商;feature negotiation(特性协商)指双方在会话中显式协商能力(如 TLS 的 ALPN、HTTP 的 Accept 头、版本协商),明确双方都支持的特性。边界:detection 是"探测式",更主动但可能误判(如探测被防火墙拦截);negotiation 是"声明式",更可靠但需双方都支持协商机制。工程上:协议版本常用 negotiation(如 HTTP/2 ALPN、Protocol 版本),能力探测用于无法协商的兼容场景。客户端声明能力,服务器按能力选择响应。

detection 是"试探",negotiation 是"声明协商"。可靠协议用 negotiation,探测用于兼容性兜底。边界在"谁声明能力、谁决定响应"。

#
★★★

27. "编码"(encoding)的跨平台处理,UTF-8、UTF-16、GBK 的字节序。

"编码"(encoding)的跨平台处理:UTF-8、UTF-16、GBK 的字节序如何理解?

  • 各编码特性
  • 字节序(endianness)
  • 跨平台处理

编码处理:UTF-8——变长编码,ASCII 兼容,无字节序问题(按字节流),互联网/存储主流,跨平台最安全;UTF-16——变长(2/4 字节),有字节序问题(BOM 或指定大端/小端),Windows/Java 内部常用;GBK——中文编码(双字节),字节序固定,兼容 GB2312,但非 ASCII 兼容且中文外不通用。跨平台要点:用 UTF-8 作为内部与传输默认编码,避免字节序问题;处理 UTF-16 时注意 BOM/字节序;GBK 仅用于兼容旧中文数据。字节序指多字节整数在内存中的排列(大端/小端),网络传输常规定大端,存储需明确。

跨平台编码的核心是"统一 UTF-8 + 明确字节序"。UTF-8 规避字节序问题,UTF-16 需 BOM,GBK 是中文专用。网络协议常用大端字节序。

#
★★★

28. "网络协议"(network protocol)的版本协商,HTTP/1.1 vs HTTP/2 vs HTTP/3。

"网络协议"(network protocol)的版本协商:HTTP/1.1、HTTP/2、HTTP/3 有何区别?

  • 各 HTTP 版本特性
  • 版本协商机制
  • 性能差异

HTTP/1.1:串行/有限并发(默认每连接一请求,靠 Keep-Alive 复用连接、pipeline 有限),队头阻塞(head-of-line blocking),需域名分片/多连接提升并发。HTTP/2:二进制分帧、多路复用(多请求共享一连接)、头部压缩(HPACK)、服务端推送,解决队头阻塞(应用层),但 TCP 层仍可能队头阻塞(丢包时整个连接重传)。HTTP/3:基于 QUIC(UDP),独立流(独立丢包/重传)、0-RTT 建连、连接迁移,彻底消除队头阻塞。版本协商:HTTP/2 用 ALPN(TLS 扩展)协商,HTTP/3 用 Alt-Svc 或 HTTPS 记录。工程上:现代服务默认 HTTP/2,弱网/高丢包场景用 HTTP/3 收益更明显。

HTTP/1.1 队头阻塞、HTTP/2 应用层多路复用但 TCP 层队头阻塞、HTTP/3(QUIC)彻底消除。逐版本迭代解决"并发与队头阻塞"。

#
★★★

29. 前端 SSR vs CSR 的延迟权衡,TTFB 与首次渲染。

前端 SSR vs CSR 的延迟权衡:TTFB 与首次渲染如何取舍?

  • SSR 与 CSR 的区别
  • TTFB 与首次渲染
  • 延迟权衡

SSR(服务端渲染)在服务端生成 HTML 返回,首次渲染快(TTFB 后直接有内容),但 TTFB 可能更高(服务端渲染逻辑耗时),且每请求服务端渲染开销大;CSR(客户端渲染)返回空壳 + JS,客户端 JS 渲染内容,TTFB 低但首次渲染(FCP/LCP)慢(需下载并执行 JS、请求数据)。权衡:SSR 适合 SEO 敏感与首屏要求高的场景,但 TTFB 与服务端负载高;CSR 适合交互复杂应用,但首屏慢。混合方案(SSR + 客户端 hydrate)兼顾首屏与后续交互。工程上:首屏/SEO 用 SSR,交互复杂用 CSR,或混合方案(SSR 首屏 + CSR 交互)。

这是"TTFB vs 首屏内容"的权衡。SSR 首屏快但 TTFB/服务端开销高,CSR TTFB 低但首屏慢,混合方案折中。

#
★★

30. 持久化的"半同步"(semisync)与"最终同步"(async)取舍。

持久化的"半同步"(semisync)与"最终同步"(async)有何取舍?

  • 半同步与异步复制
  • 一致性 vs 延迟
  • 工程取舍

持久化复制取舍:半同步(semisync)——主库写入后需至少一个从库确认同步后才返回成功,保证主从数据不丢(至少一从),但增加提交延迟(需等从库落盘);异步(async)——主库写入即返回,从库异步复制,延迟低但主库故障时可能丢数据。取舍:强一致/金融场景用半同步(牺牲延迟保不丢),高吞吐/可容忍少量丢失场景用异步(牺牲一致性换延迟)。工程上:半同步需平衡"至少几个从库确认"与延迟,异步需监控复制延迟与主从差异。

这是"数据安全性 vs 延迟"的权衡。半同步保证至少一从同步,延迟高;异步延迟低但可能丢数据。按业务对数据丢失的容忍度选择。

#
★★

31. "队列"作为缓冲的工程价值,SQS、Kafka、RabbitMQ 在延迟与吞吐的取舍。

"队列"作为缓冲的工程价值是什么?SQS、Kafka、RabbitMQ 在延迟与吞吐上如何取舍?

  • 队列解耦与缓冲
  • 各消息队列的延迟/吞吐
  • 选型

队列作为缓冲的工程价值:解耦生成与消费、削峰填谷(缓冲突发流量)、异步化(非关键路径)、可靠投递(失败重试)。各队列取舍:Kafka——高吞吐、分区顺序、持久化,适合日志流/大数据,但延迟相对较高(批量、磁盘);RabbitMQ——低延迟、灵活路由(AMQP)、可靠投递,适合低延迟任务/复杂路由,但吞吐低于 Kafka;SQS(云)——托管、微服务解耦、按需扩展,延迟适中,吞吐受并发限制。选型:高吞吐流式用 Kafka,低延迟任务/路由用 RabbitMQ,云原生托管用 SQS。核心是"吞吐 vs 延迟 vs 可靠性"的权衡。

队列的价值是"缓冲与解耦"。选型看场景:Kafka 吞吐高(代价是延迟/复杂度),RabbitMQ 延迟低(吞吐有限),SQS 托管省心。

#
★★

32. "复制延迟"(replication lag)在主从架构的工程影响。

"复制延迟"(replication lag)在主从架构中有何工程影响?

  • replication lag 的定义
  • 影响
  • 监控与治理

复制延迟(replication lag)指主库写入到从库应用该写入的时间差。影响:读己之写问题(用户写主读从读到旧值)、统计/报表读到不一致数据、主从切换时丢数据(lag 内未同步的写入)、从库读到过期数据导致业务错误。治理:监控 lag(seconds_behind_master 等指标)、对 lag 敏感读走主库或读己之写路由、半同步复制减少 lag、分布式系统用单调读/绑定读保证。工程上:区分"允许 lag 的读"与"要求强一致"的读,按需路由。

replication lag 是"读扩展"的代价。它让只读副本数据滞后,需按场景路由(强一致读走主)并监控 lag 及时告警。

#
★★

33. "脑裂"(split-brain)的 quorum 与 fencing token 防御。

"脑裂"(split-brain)如何用 quorum 与 fencing token 防御?

  • split-brain 定义
  • quorum 机制
  • fencing token

脑裂(split-brain)指分布式系统中因网络分区,多个节点都认为自己"唯一主"同时对外服务,导致状态不一致。防御:quorum——要求多数派(如 3 节点需 2 票)才能确认领导,分区后只有多数派侧能当选主,避免两主;fencing token(栅栏令牌)——主节点每次当选获得递增的 token,写入时带上 token,旧 token 的写入被拒绝(STONITH/fencing 使旧主失效),防止旧主继续写造成覆盖。工程上:quorum 保证"多数派一致",fencing 保证"旧主不生效",二者结合防止脑裂导致的写冲突。

脑裂的根因是"分区后无法区分新旧主"。quorum 用多数派消除双主,fencing token 用令牌让旧主失效,防止旧主写覆盖。

#
★★

34. "超时"(timeout)的合理值,基于历史 P99 还是经验值。

"超时"(timeout)的合理值如何设定?基于历史 P99 还是经验值?

  • 超时设定方法
  • 基于 P99 的超时
  • 经验值

超时设定的合理值:基于历史 P99/P99.9——用服务历史延迟分布设定超时,如 P99 的 2-3 倍作为超时,能覆盖绝大多数正常请求又不至于过长(避免慢请求长期占用);经验值——用固定经验值(如 3s、30s)简单但可能过短(误杀大量正常请求)或过长(长时间占用资源)。工程上:用历史分位数动态设定超时,结合上下文(读/写、下游、重试预算)调整;超时不宜过长(否则慢请求占资源),也不宜过短(误杀)。配合"超时预算"(总超时)与"重试超时"(单次更短)设计。

超时是"覆盖率 vs 资源占用"的权衡。基于历史 P99 设定(如 2×P99)比固定经验值更合理,但需结合总预算与重试策略。

#
★★

35. "constant-time"(常量时间)在密码学运算的工程应用,如何避免侧信道。

"constant-time"(常量时间)在密码学运算的工程应用是什么?如何避免侧信道?

  • constant-time 概念
  • 侧信道攻击
  • 工程实现

constant-time(常量时间)指算法执行时间与密钥/输入值无关,避免通过执行时间推断秘密(时序侧信道)。侧信道攻击:攻击者观察运行时间、功耗、缓存访问等旁路信息推断密钥(如比较字符串时提前返回泄露内容)。工程实现:密码学比较用常量时间比较(如 memcmp 的常量时间版本、Crypto 库的 constant-time 比较),加解密避免基于密钥的分支/表查找(如基于秘密的数组索引会泄露缓存访问),用查表时用"无分支"处理。工程上:用可信密码学库(OpenSSL、libsodium 等)的常量时间实现,避免自己实现密码学。

constant-time 是防侧信道的核心。关键在"执行时间/内存访问不依赖秘密",用专用库而非手写,避免时序与缓存侧信道。

#
★★

36. "加密磁盘"(encryption at rest)的全盘加密与字段级加密。

"加密磁盘"(encryption at rest)的全盘加密与字段级加密有何取舍?

  • 全盘加密 vs 字段级加密
  • 性能与安全
  • 工程取舍

静止加密(encryption at rest)两种方案:全盘加密(如 LUKS/dm-crypt)——对整个磁盘/分区加密,对应用透明,部署简单,保护介质丢失(磁盘被盗/退役),但无法区分数据敏感度(全都加密),且性能开销(虽有硬件加速)与密钥管理粗粒度;字段级加密——只加密敏感字段(如手机号、身份证),粒度细、可做权限控制、密钥更细分,但需应用层改动(哪些字段加密、如何查询加密字段)、性能开销在应用层、查询/索引受限(无法直接 LIKE/排序)。工程上:全盘加密兜底防介质泄露,字段级加密针对高敏感字段精确保护,常结合使用。

全盘加密是"整体兜底",字段级加密是"精准防护"。前者透明但粗粒度,后者可控但需改应用。按敏感度结合。

#
★★

37. "密钥轮换"(key rotation)的频率与工程影响,性能抖动与零停机。

"密钥轮换"(key rotation)的频率与工程影响是什么?如何避免性能抖动与零停机?

  • 密钥轮换
  • 性能抖动
  • 零停机轮换

密钥轮换(key rotation)定期更换密钥降低泄露风险。频率与工程影响:频繁轮换提升安全性但增加密钥管理开销与中断风险;轮换时机不当会带来性能抖动(如重新加密数据、重建缓存、握手重新协商)与停机(服务不可用)。零停机轮换策略:双密钥支持(新旧密钥同时有效,轮换期过渡)、蓝色-绿色(先部署新密钥再切换)、后台批量重加密(非高峰期)、密钥版本化(key version 标识,兼容新旧)。工程上:轮换要在低峰期、用双密钥过渡、监控性能与错误,避免一次性大规模重加密导致抖动。

密钥轮换是"安全 vs 可用性"的权衡。零停机靠双密钥过渡 + 后台渐进重加密 + 低峰期切换,避免一次性重加密带来的抖动。

#
★★

38. "证书透明度"(CT log)的合规与性能。

"证书透明度"(CT log)的合规与性能如何权衡?

  • CT log 概念
  • 合规要求
  • 性能影响

证书透明度(Certificate Transparency,CT)通过公开的可审计日志记录所有签发的 TLS 证书,用于检测被滥用/错误签发的证书。合规:多数浏览器要求证书包含 SCT(Signed Certificate Timestamp)证明其已提交到 CT log,否则可能被拒绝。性能影响:签发证书时需提交 CT log 并获取 SCT(多份以增强信任),增加签发延迟;证书链中 SCT 扩展增加证书大小(握手传输字节)。工程上:CT 是合规硬要求,用预签发/缓存 SCT 减少每次签发延迟,注意证书大小对握手的影响。

CT 是浏览器强制合规,SCT 是证书必须携带的证明。性能影响主要在签发延迟与证书大小,用缓存/预签发缓解。

#
★★

39. "API 版本"(API versioning)的三种策略,URL 版本、Header 版本、媒体类型版本。

"API 版本"(API versioning)的三种策略(URL 版本、Header 版本、媒体类型版本)有何取舍?

  • 三种版本策略
  • 各自取舍
  • 选型

API 版本化三种策略:URL 版本(/v1/...)——版本在 URL 中,直观、易缓存/日志/调试,客户端实现简单,但语义上版本属于"资源 URI"且难演进;Header 版本(X-API-Version)——版本在请求头,URL 干净但不易发现、易被忽略、缓存/网关处理复杂;媒体类型版本(Accept: application/vnd.api+json;version=1)——版本在 Accept 头,符合 REST 语义(内容协商),但对客户端/工具不友好、实现复杂。工程上:URL 版本最常用(直观易用),Header/媒体类型版本适合严格遵循 REST 与内部 API 的场景。

版本策略是"可见性 vs 语义纯粹性"的权衡。URL 版本直观易用,header/媒体类型版本更符合 REST 但实现复杂。

#
★★

40. "向前兼容"(forward compatible)vs"向后兼容"(backward compatible)的协议演进。

"向前兼容"(forward compatible)vs"向后兼容"(backward compatible)在协议演进中有何区别?

  • 前后兼容定义
  • 协议演进
  • 工程取舍

向后兼容(backward compatible)指新版本能处理旧版本产生的数据/消息(旧客户端可用新服务器);向前兼容(forward compatible)指旧版本能处理新版本产生的数据(新客户端可用旧服务器)。工程上:向后兼容是协议演进的基本要求(新服务需兼容旧客户端);向前兼容更难(旧代码需忽略未知字段),需用扩展性设计(如 protobuf 字段号预留、版本字段、容忍未知字段)。协议演进用"加字段、不删字段、不重定义" + 版本协商,兼顾前后兼容。取舍:向后兼容是底线,向前兼容提升鲁棒性但需设计投入。

后向兼容是"新处理旧",前向兼容是"旧处理新"。前向兼容更难,靠扩展性设计(未知字段容忍、版本号)实现。

#
★★

41. "字节序"(endianness)的跨平台处理,网络协议、文件格式、序列化。

"字节序"(endianness)的跨平台处理:网络协议、文件格式、序列化如何考虑?

  • 字节序概念
  • 网络/文件/序列化
  • 跨平台处理

字节序(endianness)指多字节数据在内存中的排列:大端(big-endian,高字节在前)与小端(little-endian,低字节在前)。跨平台处理:网络协议——TCP/IP 规定大端(network byte order),发送/接收用 htonl/ntohl 转换;文件格式——需在格式规范中明确字节序(或写 BOM/魔数标识),读取时按规范转换;序列化——跨平台序列化格式(protobuf、JSON 用文本或明确字节序)规定字节序,避免平台差异。工程上:统一采用"网络字节序(大端)"或明确标注,跨平台读写时用转换函数,避免直接按内存字节序解释。

字节序是跨平台数据交换的坑。网络用大端、文件/序列化要明确字节序,读写时用标准转换函数,避免平台依赖。

#
★★

42. "前端慢"现象的拆解,TTFB、FCP、LCP、TBT、CLS 的 Web Vitals。

"前端慢"现象如何拆解?TTFB、FCP、LCP、TBT、CLS 各 Web Vitals 指标如何理解?

  • Web Vitals 指标
  • 各指标含义
  • 前端性能定位

前端性能指标拆解:TTFB(time to first byte)——首字节到达时间,反映网络/服务端;FCP(first contentful paint)——首次内容绘制,反映首屏内容出现;LCP(largest contentful paint)——最大内容绘制,反映主要内容可见;TBT(total blocking time)——主线程阻塞总时间,反映交互响应;CLS(cumulative layout shift)——布局偏移,反映视觉稳定性。定位"前端慢":先看 TTFB 判断是网络/服务端还是前端;再看 FCP/LCP 判断首屏渲染慢(JS 大、资源多);TBT 高说明主线程被 JS 阻塞;CLS 高说明布局抖动。优化:TTFB 用 CDN/缓存/服务端优化,LCP 用资源优化/懒加载,TBT 用代码分割/减少长任务,CLS 用固定尺寸。

Web Vitals 是 Web 性能的"分级指标"。TTFB 定位网络/服务端,FCP/LCP 定位首屏,TBT 定位交互阻塞,CLS 定位布局稳定性,逐级拆解。

#
★★

43. "请求重试"(retry)的副作用,放大故障、毒丸请求、客户端幂等性。

"请求重试"(retry)的副作用是什么?放大故障、毒丸请求、客户端幂等性如何理解?

  • retry 副作用
  • 放大故障
  • 幂等性

请求重试会放大故障:当一个服务故障时,大量客户端同时重试会加剧负载(retry storm),使故障恶化甚至雪崩;毒丸请求(poison pill)——重试的请求本身有问题(如参数错误、处理固定失败),重试无意义且持续占用资源;客户端幂等性——重试可能重复执行操作(如重复扣款、重复下单),需客户端幂等(用副作用、幂等 key)才能安全重试。工程上:重试要加指数退避 + jitter(错开重试时间)、限制重试次数、重试只对幂等操作、用熔断/限流防止重试风暴。

retry 是"可靠性 vs 放大"的权衡。重试带来可靠,但会放大故障(retry storm)与重复副作用(幂等)。需配退避 + jitter、限次、限幂等操作、熔断/限流防风暴。

#
★★

44. 请求从接入到持久化的完整链路(接入、鉴权、业务逻辑、WAL、落盘)中,哪些环节可能成为吞吐瓶颈,如何用延迟分解与队列深度定位?

请求从接入到持久化的完整链路中,哪些环节可能成为吞吐瓶颈?如何用延迟分解与队列深度定位?

  • 完整链路环节
  • 吞吐瓶颈点
  • 延迟分解与队列深度

请求完整链路:接入(网络/连接/协议解析)→ 鉴权(认证/权限)→ 业务逻辑(计算/调用)→ WAL(写日志)→ 落盘(持久化)。吞吐瓶颈可能在各环节:接入——连接数/epoll/协议解析 CPU;鉴权——鉴权调用慢/缓存 miss;业务逻辑——CPU/锁/下游调用;WAL——fsync/磁盘写;落盘——磁盘 I/O/页缓存。定位用延迟分解:打点各环节耗时(trace),看哪段占比高;用队列深度:看各环节队列(连接队列、线程池队列、磁盘队列)是否积压——队列满说明该环节是瓶颈。吞吐不增时,队列深度上升的环节即瓶颈。

链路瓶颈是"排队积压"的地方。延迟分解找"哪段耗时多",队列深度找"哪段积压",两者结合定位真实瓶颈,再对症(加连接、缓存、优化 fsync)。

#
★★

45. "令牌桶"(token bucket)、"漏桶"(leaky bucket)、"滑动窗口"(sliding window)限流的工程取舍。

"令牌桶"(token bucket)、"漏桶"(leaky bucket)、"滑动窗口"(sliding window)限流各有何工程取舍?

  • 三种限流算法
  • 各自特性
  • 选型

限流算法取舍:令牌桶(token bucket)——按速率生成令牌,请求需取令牌,桶容量允许突发(积攒令牌),适合允许突发流量(正常业务突发);漏桶(leaky bucket)——请求以固定速率流出(排队),输出平滑,无突发,适合限速平滑(如流量整形);滑动窗口(sliding window)——统计窗口内请求数,滑动时间窗口,能精确控制速率(如固定窗口的边界问题),适合精确 QPS 限流。工程上:令牌桶允许突发(常用,如 Guava RateLimiter),漏桶平滑输出(限速),滑动窗口精确限流(毫秒级边界)。取舍是"突发容忍 vs 平滑 vs 精确"。

令牌桶允许突发(桶积令牌),漏桶强制平滑(无突发),滑动窗口精确(细分窗口)。按业务对突发的容忍度选型。

#
★★

46. "熔断器"(circuit breaker)的三态(Closed、Open、Half-Open)切换逻辑。

"熔断器"(circuit breaker)的三态(Closed、Open、Half-Open)切换逻辑如何理解?

  • 熔断器三态
  • 切换条件
  • 自动恢复

熔断器三态:Closed(关闭)——正常转发请求,统计失败率,当失败率超过阈值(如 50%)或错误数超阈值时打开;Open(打开)——直接拒绝请求(快速失败),不调用下游,让下游恢复,持续一段时间(如 30s)后进入 Half-Open;Half-Open(半开)——放行少量探测请求,若成功则恢复 Closed,若失败则回到 Open。切换逻辑:Closed→Open 由失败率超阈值触发;Open→Half-Open 由冷却时间到期触发;Half-Open→Closed 由探测成功触发,Half-Open→Open 由探测失败触发。工程上:熔断器自动恢复,防止下游故障时雪崩,Half-Open 作试探。

熔断器用"失败→拒绝→试探→恢复"的循环保护下游。三态切换由失败率、冷却时间、探测结果驱动,实现自动降级与恢复。

#
★★

47. "线程池"(thread pool)的核心/最大配置与任务队列的协同。

"线程池"(thread pool)的核心/最大线程数与任务队列如何协同?

  • 线程池核心/最大线程
  • 任务队列
  • 溢出策略

线程池配置:核心线程数(core)——常驻线程,即使空闲也保留;最大线程数(max)——允许的最大线程数;任务队列——当核心线程全忙时,任务入队等待。协同逻辑:任务到来,若核心线程未满则新建核心线程执行;若核心线程已满则任务入队;若队列也满则新建线程(直到 max);若 max 也满则执行拒绝策略(拒绝/丢弃)。取舍:核心线程应对稳态负载,队列应对突发(缓冲),max 线程应对队列满的峰值。工程上:核心线程数按稳态并发设,队列有界(防内存无限),max 与拒绝策略保护系统。

线程池是"核心线程 + 队列 + 最大线程"的激增联动。核心处理稳态,队列缓冲突发,max 兜底峰值,拒绝策略防溢出。

#
★★

48. "连接池"(connection pool)的最优大小,((core_count * 2) + effective_spindle_count) HikariCP 公式。

"连接池"(connection pool)的最优大小如何计算?HikariCP 公式 (core_count * 2) + effective_spindle_count 如何理解?

  • 连接池大小公式
  • 公式原理
  • 调整

HikariCP 建议的连接池大小公式为(core_count * 2)+ effective_spindle_count,其中 core_count 是 CPU 核心数,effective_spindle_count 是磁盘主轴数(HDD 数量,SSD 可视为 0)。原理:基于"数据库连接是稀缺资源,过多连接反而因上下文切换与锁竞争降低吞吐"的观察——单核上并行连接过多会因等待与切换变慢,理想并发与 CPU 核数相关。公式给出一个合理起点(如 4 核 HDD 约 9 个连接)。实际需按数据库负载、查询用时、CPU/磁盘特性压测调整。连接池过大浪费资源且可能压垮数据库,过小则排队。

连接池公式基于"CPU 是瓶颈,过多连接无益"的假设。用公式作起点,再按实际(CPU 利用率、查询耗时、磁盘)压测调优。

#
★★

49. "响应丢失"的处理,客户端超时 vs 服务端完成的隐性不一致。

"响应丢失"(response lost)如何处理?客户端超时 vs 服务端完成的隐性不一致如何理解?

  • 响应丢失场景
  • 客户端超时 vs 服务端完成
  • 幂等与重试

响应丢失指客户端发出请求后超时未收到响应,但服务端可能已完成处理(响应在途中丢失/延迟)。这造成"客户端认为失败,服务端已成功"的隐性不一致。处理:客户端超时后重试需幂等(若操作非幂等,重试会重复执行);用 Idempotency Key 让服务端识别并去重;或查询确认(先查再重试)。工程上:超时重试只对幂等操作安全;对非幂等(扣款、下单)用幂等 key 或状态查询,避免重复执行。客户端超时 ≠ 服务端失败,需区分。

响应丢失的坑是"客户端超时不代表服务端没执行"。处理靠幂等性(幂等 key)与状态确认,避免重试导致重复副作用。

#
★★

50. "幂等"(idempotency)在重试机制的工程实现,Idempotency Key、状态机、版本号。

"幂等"(idempotency)在重试机制中如何实现?Idempotency Key、状态机、版本号各有什么作用?

  • 幂等概念
  • Idempotency Key
  • 状态机与版本号

幂等(idempotency)保证同一操作多次执行结果一致,是重试安全的前提。实现:Idempotency Key——客户端生成唯一 key,服务端以 key 去重(首次执行、后续返回首次结果),常见于支付/下单;状态机——把操作做成有状态的转移(如"待支付→已支付→已退款"),重复执行到已终态则直接返回,避免重复;版本号(乐观锁)——数据带版本号,更新时校验版本,旧版本更新被拒,避免覆盖。工程上:写操作用幂等 key + 状态机 + 版本号,配合重试(指数退避)保证"重试不重复"。

幂等是重试的基石。Idempotency Key 去重、状态机保证终态、版本号防覆盖,三者结合实现"重试安全"。

#
★★

51. "故障转移"(failover)的 RTO/RPO 与自动切换的边界。

"故障转移"(failover)的 RTO/RPO 与自动切换的边界如何理解?

  • RTO/RPO 概念
  • 故障转移类型
  • 自动切换边界

RTO(Recovery Time Objective,恢复时间目标)——故障后恢复服务所需的最长时间;RPO(Recovery Point Objective,恢复点目标)——可容忍的数据丢失量(如 5 分钟内的数据)。故障转移(failover)在主节点故障时切换备用节点。RTO/RPO 决定切换策略:同步复制(RPO≈0)但延迟高;异步复制(RPO>0,可能丢数据)但延迟低。自动切换的边界:切换需判断"主确实故障"(避免误切换),需 quorum/健康检查;切换有成本(DNS 更新、连接重置、数据同步),要权衡 RPO(允许丢多少)与自动切换的可靠性。自动切换缩短 RTO 但引入误切换风险与数据丢失(RPO)。

failover 是"RTO/RPO 的权衡"。自动切换降 RTO,但受 RPO 限制(异步可能丢数据),且需防误切换(脑裂)。按业务容忍度设定。

#
★★

52. "部分成功"(partial success)场景的工程语义,订单成功但支付失败的补偿逻辑。

"部分成功"(partial success)场景的工程语义是什么?订单成功但支付失败的补偿逻辑如何设计?

  • partial success 定义
  • 分布式事务
  • 补偿逻辑

部分成功(partial success)指跨多个子系统/服务的一个业务操作,部分成功部分失败(如订单已创建但支付失败),无法用单事务原子性保证。工程语义:采用最终一致 + 补偿(SAGA)而非强一致。补偿逻辑:订单成功但支付失败——先记录订单状态,若支付失败则取消订单(反向补偿)、释放库存、标记异常;或先支付后建单,失败则回滚。实现:SAGA 编排(每个步骤 + 补偿步骤)、状态机驱动、失败重试与人工兜底。设计要点:每个步骤可补偿、补偿幂等、记录失败原因、最终一致。

部分成功是分布式事务的常态。用 SAGA/补偿达成最终一致,关键是"每个已执行步骤都有可逆的补偿操作",且补偿幂等。

#
★★

53. "重试"(retry)的指数退避(exponential backoff)与 jitter(抖动)。

"重试"(retry)的指数退避(exponential backoff)与 jitter(抖动)如何设计?

  • 指数退避
  • jitter 的作用
  • 防重试风暴

指数退避(exponential backoff)让重试间隔随时间指数增长(如 1s、2s、4s、8s),逐步降低重试频率,避免持续急促重试;jitter(抖动)在退避间隔上加随机扰动(如 1s + random(0-1s)),使多个客户端重试时间错开,避免"重试风暴"(所有客户端同时重试,形成同步尖峰)。工程上:指数退避 + 全抖动(full jitter)或相等抖动(equal jitter)是标准做法,配合重试上限(max retries)与超时预算,防止无限重试。AWS 等云服务推荐指数退避 + jitter。

指数退避防"频繁重试",jitter 防"同步重试"。二者结合错开重试时间,避免客户端同时重试放大故障。

#

54. "C10K"问题的工程演进,epoll、io_uring、DPDK 的吞吐提升。

"C10K"问题的工程演进:epoll、io_uring、DPDK 如何提升吞吐?

  • C10K 问题
  • epoll/io_uring/DPDK
  • 演进

C10K 指单机处理 1 万并发连接的问题。工程演进:epoll——事件驱动 I/O 复用,解决"每连接一线程"的线程爆炸,O(1) 事件通知,支撑高并发;io_uring——异步 I/O 框架,减少系统调用开销(共享内存队列提交/回收),支持高效异步读写,吞吐更高;DPDK——用户态数据面,绕过内核协议栈直接操作网卡,实现超高吞吐(百万级包处理),亚微秒延迟,用于高性能网络/DPDK 场景。演进是"从事件复用(epoll)到异步 I/O(io_uring)再到用户态网络(DPDK)",逐步降低系统调用与内核开销。

C10K 演进是"减少内核开销"。epoll 复用事件、io_uring 异步减少 syscall、DPDK 绕过内核,吞吐逐级提升,代价是复杂度与隔离性。

#

55. "JWT"vs"Session"在无状态与有状态服务的取舍。

"JWT"vs"Session"在无状态与有状态服务中有何取舍?

  • JWT 与 Session 区别
  • 无状态 vs 有状态
  • 取舍

JWT(JSON Web Token)——客户端持有自包含的签名令牌,服务端无状态(验签即可,无需存会话),适合分布式/无状态服务、水平扩展,但令牌无法主动失效(需等过期)、易被滥用(需短 TTL)、令牌大小随载荷增长;Session——服务端存储会话状态(如 Redis),有状态,可主动失效/管理,但需会话存储(共享存储/粘性),增加存储与一致性。取舍:无状态服务/水平扩展用 JWT(无共享存储),需要控制会话/撤销用 Session(有状态)。混合:JWT + 服务端撤销名单(黑名单)。

JWT 无状态(验签即用)适合扩展,Session 有状态(可管理)适合撤销。取舍是"扩展性 vs 控制力"。

#

56. "OAuth scope"的细粒度与最小权限。

"OAuth scope"的细粒度与最小权限如何理解?

  • OAuth scope 概念
  • 最小权限
  • 授权设计

OAuth scope 是授权范围/权限粒度,客户端在授权时申请特定 scope(如"读取用户资料"、"读写邮件"),授权服务器按 scope 授予有限权限。细粒度:scope 应细分(不同资源/操作不同 scope),实现最小权限原则——客户端只被授予完成任务所需的最小权限,避免过度授权(如只读应用不应申请写权限)。工程上:scope 粒度要合理(过粗失控、过细复杂),按资源+操作定义,授权时校验 scope,客户端只申请所需 scope,配合权限审查。

OAuth scope 是"最小权限"的实现载体。细粒度 scope 让客户端只获得所需权限,降低泄露风险,但需权衡粒度与复杂度。

#

57. "RBAC"vs"ABAC"vs"PBAC"在权限模型的取舍。

"RBAC"vs"ABAC"vs"PBAC"在权限模型有何取舍?

  • 三种权限模型
  • 各自特性
  • 选型

权限模型取舍:RBAC(基于角色的访问控制)——用户绑定角色,角色绑定权限,简单直观、易管理,适合权限模式稳定的系统;ABAC(基于属性的访问控制)——用属性(用户、资源、环境、操作)组合策略判断,灵活表达复杂条件(如"工作时间+部门"),但策略复杂、难以管理;PBAC/PeP 等基于策略的扩展——把权限封装为策略(policy),细粒度、可审计。取舍:RBAC 简单易用(大多数系统),ABAC 灵活(复杂条件/动态),策略化(PBAC)适合细粒度合规。工程上常用 RBAC 为主 + ABAC 补充复杂场景。

权限模型是"简单 vs 灵活"的权衡。RBAC 简单易管,ABAC 灵活但复杂,PBAC 策略化细粒度,按业务复杂度选型。

#

58. "审计"(audit)的"全量"与"采样"取舍,合规 vs 存储成本。

"审计"(audit)的"全量"与"采样"取舍:合规 vs 存储成本如何平衡?

  • 审计全量或采样
  • 合规要求
  • 存储成本

审计(audit)记录敏感操作(登录、权限变更、数据访问)用于追踪与合规。全量审计——记录所有事件,合规最完整、可追溯但存储成本高(高吞吐下日志量大);采样审计——只记录部分事件(或按错误/关键事件),成本低但可能漏掉关键操作,不合规。取舍:合规要求(如安全规范)强制关键操作全量记录(登录、权限变更、支付),非关键可采样;存储成本用压缩、归档、分级(热/冷存)控制。工程上:关键/敏感操作全量审计,非关键采样,配合保留策略与归档平衡成本。

审计是"合规 vs 成本"的权衡。关键敏感操作全量(合规底线),非关键采样,用分级存储控成本。

#

59. "ABI 兼容性"(Application Binary Interface)的工程边界,版本升级的兼容性。

"ABI 兼容性"(Application Binary Interface)的工程边界是什么?版本升级如何保证兼容?

  • ABI 概念
  • 二进制兼容
  • 升级兼容

ABI(Application Binary Interface)兼容性指二进制层面(编译产物、库接口)的兼容——新版本库能否被旧编译的二进制直接使用,无需重编译。破坏 ABI 的因素:结构体布局变化(字段增删/重排)、函数签名变化、枚举/宏值变化、虚函数顺序变化。工程边界:升级动态库/插件时若 ABI 不兼容,旧二进制调用会崩溃/出错。保证 ABI 兼容:只在末尾追加字段、不删除/重排现有字段、不改变函数签名、使用版本化符号、用 pimpl 隐藏内部布局。工程上:对外发布库要维护 ABI 兼容声明,用语义化版本(major 变更 ABI)。

ABI 兼容是"二进制级"的兼容,比源码级更严格。升级库时需保持结构体布局与函数签名稳定,否则旧二进制崩溃。

#

60. "TLS 1.3"的兼容性与 TLS 1.2 的回退。

"TLS 1.3"与 TLS 1.2 的回退兼容性如何理解?

  • TLS 1.3 特性
  • 回退机制
  • 兼容性

TLS 1.3 相比 TLS 1.2 简化握手(1-RTT,恢复 0-RTT)、移除弱加密套件、增强安全。兼容性:TLS 1.3 通过版本协商(ClientHello 的 supported_versions 扩展)与旧版本共存,若服务端不支持 1.3 则回退到 1.2(或更低)。回退考量:TLS 1.3 与 1.2 的 ClientHello 兼容(1.3 用扩展标识版本,伪装成 1.2 兼容消息),但需防"降级攻击"(攻击者强制回退到弱版本)——TLS 1.3 用 downgrade sentinel(降级标记)检测并阻止回退。工程上:支持 TLS 1.3 同时保留 1.2 回退,但需启用降级防护,避免被降级到 1.1/1.0 等弱版本。

TLS 1.3 与 1.2 回退依赖版本协商,但需防降级攻击。工程上支持 1.3 且禁掉 1.0/1.1 弱版本,回退到 1.2 是可接受底线。

#

61. "消息格式升级"(schema evolution)的兼容性规则,Avro、Protobuf 的前后向兼容。

"消息格式升级"(schema evolution)的兼容性规则:Avro、Protobuf 如何保证前后向兼容?

  • schema evolution
  • Avro/Protobuf 兼容规则
  • 前后向兼容

消息格式升级(schema evolution)需保证新旧 schema 兼容。Protobuf 规则:字段号(field number)用于标识,升级时只能新增字段(不能删除/重排现有字段),旧客户端读新字段会忽略(未知字段保留),新客户端读旧消息用默认值填充缺失字段——天然向后兼容(新读旧)与前向兼容(旧读新,忽略未知)。Avro 规则:用 schema 注册(Schema Registry)与 reader/writer schema 匹配,通过字段名匹配,升级时新增字段需有默认值,重命名/删除需谨慎,靠 default 值保证兼容。共性:加字段不删、有默认值、靠字段号/名匹配。

schema evolution 的核心是"加字段、不删字段、带默认值"。Protobuf 用字段号,Avro 用字段名+Schema Registry,保证新旧互读。

#

62. "滚动升级"(rolling upgrade)与"蓝绿发布"(blue-green)的回滚速度差异。

"滚动升级"(rolling upgrade)与"蓝绿发布"(blue-green)的回滚速度有何差异?

  • 滚动升级与蓝绿发布
  • 回滚速度
  • 取舍

滚动升级(rolling)——分批逐个/小批升级实例,新旧共存,回滚需逐个回滚(慢、需重新部署旧版本),但不需额外资源;蓝绿发布(blue-green)——同时维护两套环境(蓝/绿),切换流量到新版本,回滚只需把流量切回旧环境(秒级,快),但需双倍资源(两套环境)。取舍:蓝绿回滚快(流量切换)但成本高(双环境),滚动回滚慢(逐实例回滚)但成本低。工程上:对回滚要求高(关键服务)用蓝绿,资源受限用滚动(配合自动回滚)。回滚速度是"快切 vs 成本"的权衡。

蓝绿靠"流量切换"实现瞬时空回滚,但需双环境;滚动靠"逐实例替换"回滚慢但省资源。按回滚重要性选型。