236 lines
15 KiB
JSON
236 lines
15 KiB
JSON
{
|
||
"topic": "cache-architecture",
|
||
"type": "short_answer",
|
||
"schema_version": "1.0.0",
|
||
"generated": "09-2026-09-05T00:00:00+08:00",
|
||
"questions": [
|
||
{
|
||
"id": "sa-001",
|
||
"type": "short_answer",
|
||
"difficulty": 2,
|
||
"tags": [
|
||
"单机缓存"
|
||
],
|
||
"question": "简述判断单机环境是否需要引入 Redis 的'判断三问',并说明每问回答'是'意味着什么。",
|
||
"answer": "判断三问:①缓存是否需要被多进程/多服务共享?②是否依赖 Redis 某项能力(AOF 持久化、分布式锁、原子计数 INCR、榜单 ZSET、PubSub 等)?③数据量是否大得本地进程内内存扛不住、或将来必然扩展为多机集群?只要任一回答'是',就应当引入 Redis;只有当三问全部为'否'时,进程内本地缓存(如 Caffeine)才足够。",
|
||
"keywords": [
|
||
"多进程共享",
|
||
"Redis能力",
|
||
"数据量",
|
||
"本地缓存",
|
||
"Caffeine"
|
||
],
|
||
"scoring_rubric": "答出三问各得 20 分(共 60 分);正确说明三问全否才选本地缓存得 20 分;能指出'单机≠单进程'这一易错点得 20 分。",
|
||
"explanation": "决定是否用 Redis 的核心是缓存是否需要被多进程/多能力共享,而不是机器是否单机。三问中任一命中就说明需要 Redis 的跨进程共享或特性能力;全否则本地缓存足够,加 Redis 反而引入网络与一致性麻烦。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-002",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"Write-Behind",
|
||
"回写式缓存"
|
||
],
|
||
"question": "请说明 Write-Behind(回写式/懒更新缓存)架构的运作方式,以及使用它需要注意哪几类代价或边界。",
|
||
"answer": "运作方式:客户端完全不直连 DB,统一读写缓存层;写操作只更新缓存并返回,由缓存层异步批量把写入同步回 DB(Read-Through + Write-Behind)。注意事项:①不丢写——缓存必须开启持久化(AOF)并配套兜底日志/队列,绝不可把缓存当唯一真源;②不乱序——批量落库需带时间戳/版本号防止旧覆盖新;③外部读到旧值——直查 DB 的外部/报表系统会看到滞后数据,因此只适合内部读、可容忍一致的数据,而交易/余额/库存等强一致数据绝不可进入该链路。",
|
||
"keywords": [
|
||
"异步落库",
|
||
"持久化",
|
||
"AOF",
|
||
"版本号",
|
||
"旧值",
|
||
"强一致"
|
||
],
|
||
"scoring_rubric": "正确描述异步落库机制得 30 分;说出缓存需持久化兜底不丢写得 25 分;说出版本号/时间戳防乱序得 20 分;指出外部读旧值风险并排除强一致数据得 25 分。",
|
||
"explanation": "Write-Behind 的优势是写异步化、可批量合并、降低 DB 写压力;代价是丢写风险、乱序风险和读滞后。本题考察对整个架构边界(可靠性、一致性、适用数据)的把握,是必考点。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-003",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"多级缓存"
|
||
],
|
||
"question": "多级缓存(L1 本地 + L2 Redis)副本不一致是核心难点,请给出至少三种缓解不一致的治理手段。",
|
||
"answer": "①本地缓存设置短 TTL + 逻辑过期兜底——即使没收到失效通知,本地数据也会在较短时间内自然过期回源,缩小不一致窗口;②主动失效 + 广播——写入时通过 MQ 发送失效事件,通知所有节点清除本地缓存副本;③版本号/时间戳判定过期——缓存项携带版本号或写入时间戳,读时对比 L2 判定本地副本是否已过期。",
|
||
"keywords": [
|
||
"短TTL",
|
||
"逻辑过期",
|
||
"广播",
|
||
"MQ",
|
||
"版本号",
|
||
"失效"
|
||
],
|
||
"scoring_rubric": "每种治理手段计约 33 分(共约 100 分)。答出短 TTL/逻辑过期得 33 分;答出 MQ 广播主动失效得 33 分;答出版本号/时间戳判过期得 34 分。",
|
||
"explanation": "多级缓存的根本矛盾是同一数据多个副本。思路分两条线:缩短过期窗口(短 TTL + 逻辑过期),和主动同步失效(广播 + 版本判定)。三者属于缓存一致性的经典治理手段。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-004",
|
||
"type": "short_answer",
|
||
"difficulty": 2,
|
||
"tags": [
|
||
"Caffeine",
|
||
"TinyLFU",
|
||
"多级缓存"
|
||
],
|
||
"question": "对比 Caffeine 与 Redis 两种缓存组件,说明各自适用场景,在多级缓存中各自适合承担哪一层。",
|
||
"answer": "Caffeine 是进程内 JVM 内存、TinyLFU 淘汰、纳秒级无网络单机访问,适合做 L1 极热/高访问层;但重启即失、无法跨进程共享。Redis 是独立进程、可跨机器,毫秒网络 I/O、支持持久化、分布式锁/原子计数/榜单/PubSub,适合做 L2 共享与兜底层。多级缓存中 Caffeine 放 L1 承接极端热点、Redis 放 L2 跨进程共享,两者组合兼顾极热性能与一致性。",
|
||
"keywords": [
|
||
"Caffeine",
|
||
"TinyLFU",
|
||
"L1",
|
||
"Redis",
|
||
"L2",
|
||
"多级缓存"
|
||
],
|
||
"scoring_rubric": "Caffeine 特点与 L1 定位各得 20 分;Redis 特点与 L2 定位各得 20 分;正确说明二者组合成多级缓存得 20 分。",
|
||
"explanation": "两者的本质差异是'进程内内存' vs '独立共享服务'。多级缓存正是发挥二者长处:L1 用 Caffeine 承接极热访问减网络开销,L2 用 Redis 保证跨进程一致与可靠性。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-005",
|
||
"type": "short_answer",
|
||
"difficulty": 4,
|
||
"tags": [
|
||
"缓存降级",
|
||
"限流",
|
||
"熔断"
|
||
],
|
||
"question": "在缓存架构的可靠性设计中,请说明限流、熔断、降级三种手段各自的职责,以及它们如何共同保护 DB 和后端服务。",
|
||
"answer": "限流:限制单位时间回源/请求的数量,防止突发流量瞬间打满 DB 连接或线程池;熔断:当后端(DB/缓存)连续失败达到阈值时快速失败而非继续请求,让其有喘息恢复时间;降级:当 Redis 等组件不可用时,返回兜底数据(如本地缓存副本、默认值、静态页)而不是无限回源。三者配合:Redis 抖动时先本地兜底降级 + 限流控制回源 + 熔断保护 DB,避免全量打爆后端。",
|
||
"keywords": [
|
||
"限流",
|
||
"熔断",
|
||
"降级",
|
||
"兜底",
|
||
"保护DB"
|
||
],
|
||
"scoring_rubric": "正确说明限流职责得 25 分;熔断职责得 25 分;降级兜底职责得 30 分;能整合说明三者协作保护 DB 得 20 分。",
|
||
"explanation": "可靠性设计不止是缓存本身高可用,更重要的是对下游的保护。限流控制流量、熔断快速失败、降级提供兜底,三者共同避免缓存故障演变为 DB 过载故障。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-006",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"Redis持久化",
|
||
"RDB",
|
||
"AOF"
|
||
],
|
||
"question": "请对比 Redis 的 RDB 快照与 AOF 日志两种持久化方式,说明各自在数据安全性与恢复方式上的特点,并给出选型建议。",
|
||
"answer": "RDB 按周期把内存数据整份快照序列化落盘,文件紧凑、恢复快,但两次快照之间的写入可能丢失,安全性较弱。AOF 记录每次写命令的追加日志,可重放到最近状态,数据更安全,但文件较大、在重写(bgrewriteaof)影响恢复速度/性能。选型:若对安全性要求高(如缓存作为准真源、写后异步落库)选 AOF 或两者同时开启、仅接受少量丢失选 RDB;一般高要求生产推荐同时开启 AOF 以保数据。",
|
||
"keywords": [
|
||
"RDB",
|
||
"AOF",
|
||
"快照",
|
||
"重放",
|
||
"持久化",
|
||
"选型"
|
||
],
|
||
"scoring_rubric": "正确说明 RDB 快照特点与丢失窗口得 30 分;正确说明 AOF 追加日志与重放得 30 分;给出符合场景的选型建议得 40 分。",
|
||
"explanation": "RDB 是周期性快照(紧凑、恢复快、可能丢最后窗口数据),AOF 是命令日志(数据更安全、可重放)。持久化选型属于缓存组件选型的核心点,尤其结合 Write-Behind 的落库需求更强调 AOF。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-007",
|
||
"type": "short_answer",
|
||
"difficulty": 2,
|
||
"tags": [
|
||
"单机缓存",
|
||
"多进程共享"
|
||
],
|
||
"question": "为什么说'单机'不等于'单进程',并基于此说明一台单机部署在手机多进程时为何仍需 Redis。",
|
||
"answer": "'单机'描述的是部署物理维度(一台机器),而'单进程'描述的是运行进程维度(应用进程个数)。决定是否需要 Redis 的是缓存是否被多进程/多能力共享:即使在同一台机器上运行多个业务进程,每个进程持本地副本会各自维护一份缓存而产生数据不一致;此时仍需要引入 Redis 作为跨进程的共享缓存层,保证所有进程读到同一份数据。因此'单机用本地缓存即可'的常见误判,本质是把'单机'误当成了'单进程'。",
|
||
"keywords": [
|
||
"单机",
|
||
"单进程",
|
||
"多进程",
|
||
"共享",
|
||
"不一致"
|
||
],
|
||
"scoring_rubric": "正确解释单机与单进程的维度区别得 40 分;指出多进程各自持副本不一致得 30 分;正确结论是仍需 Redis 做共享层得 30 分。",
|
||
"explanation": "该题是缓存选型中最常见的误判点。判断依据是'缓存是否需要被共享',与机器台数无关。只要多进程共享就需 Redis。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-008",
|
||
"type": "short_answer",
|
||
"difficulty": 4,
|
||
"tags": [
|
||
"哨兵",
|
||
"Redis Cluster"
|
||
],
|
||
"question": "区分哨兵(Sentinel)与 Redis Cluster 在体系结构中的职责,并说明二者是否可以同时使用及其各自解决的问题。",
|
||
"answer": "哨兵负责高可用:部署在主从复制之上,监控主从状态,在主库故障时自动发起投票并提升上手从库为主库,实现自动接管,不负责数据分片;Redis Cluster 负责横向扩展:按 hash slot(16384 个槽)把键分布到多个分片节点,支持大容量与更高吞吐,具有分片能力。两者职责不同可同时使用——在 Cluster 之上叠加基于哨兵的监控/运维切换,或对不同的独立 Redis 实例分别用哨兵保障。哨兵解决'主库挂了怎么办',Cluster 解决'单实例容量/吞吐不够怎么扩展'。",
|
||
"keywords": [
|
||
"哨兵",
|
||
"Sentinel",
|
||
"集群",
|
||
"Cluster",
|
||
"分片",
|
||
"自动切换"
|
||
],
|
||
"scoring_rubric": "正确说明哨兵负责故障检测与自动切换得 35 分;正确说明 Cluster 负责分片/横向扩容得 35 分;说明两个职责互补、可同时使用得 30 分。",
|
||
"explanation": "这是选型中易混淆的一对:哨兵是'高可用'组件(故障切换),Cluster 是'分片扩展'组件(横向扩容)。职责不同,可搭配使用。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-009",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"Write-Behind",
|
||
"回写式缓存"
|
||
],
|
||
"question": "Write-Behind 架构中,为什么'绝不能把缓存当作唯一真源'?请从一两个典型故障说明后果与应采取的兜底措施。",
|
||
"answer": "因为 Write-Behind 下数据先写缓存、异步落库,若缓存作为唯一真源而该缓存未持久化或崩溃,则尚未同步到 DB 的写入会直接丢失;同时如果只有一套副本,一旦重启清空则无法恢复任何待落库数据。典型故障:缓存进程崩溃且未开 AOF,队列中积压的上万笔写入全部丢失;或落库逻辑持续失败导致缓存与 DB 长期分歧。兜底措施:缓存开启持久化(AOF)+ 独立的可靠的落库日志/消息队列兜底,保证每比写入都被可靠记录并可重放;配合版本号防乱序、System对账重试。",
|
||
"keywords": [
|
||
"丢写",
|
||
"崩溃",
|
||
"持久化",
|
||
"AOF",
|
||
"消息队列",
|
||
"兜底"
|
||
],
|
||
"scoring_rubric": "指出缓存作为唯一真源会有崩溃丢写风险得 30 分;给出具体的故障场景(崩溃/清空/重放)得 30 分;提出持久化 + 队列兜底/对账措施得 40 分。",
|
||
"explanation": "Write-Behind 的可靠性核心是不把缓存当唯一真相源:必须要有持久化 + 兜底队列,把写入先可靠记下来再异步同步,避免缓存崩溃丢真源。",
|
||
"source": null,
|
||
"related": []
|
||
},
|
||
{
|
||
"id": "sa-010",
|
||
"type": "short_answer",
|
||
"difficulty": 5,
|
||
"tags": [
|
||
"多级缓存",
|
||
"Caffeine"
|
||
],
|
||
"question": "设计一个多级缓存的一致性读写如何做具体过程:热点数据写入时,如何保证 L1 本地、L2 Redis 与 DB 三方的新旧一致?",
|
||
"answer": "可采用的完整流程:写时先更新 DB,写成功后向 L2 Redis 写新值并发出失效事件/版本号;通过 MQ 把版本号/失效通知直接发给所有节点的 L1 本地缓存,各节点收到后删除对应本地 key(主动失效);本地 key 同时设置短 TTL + 逻辑过期作为兜底,即使广播丢失也会在短 TTL / 逻辑过期时触发校验回源,读时携带版本号判断过期;对外暴露时返回已确认一致的值。排列组合:更新 DB → 更新或失效 Redis → 广播失效本地 → 本地短 TTL 逻辑过期兜底 + 版本号判定,最终保证 DB 为真源、L2 与 L1 为可作废副本,缩短不一致窗口。",
|
||
"keywords": [
|
||
"RIO广播",
|
||
"失效",
|
||
"短TTL",
|
||
"版本号",
|
||
"DB真源"
|
||
],
|
||
"scoring_rubric": "答出 DB 为真源、写库先行得 20 分;答出 L2 更新/失效再加版本号得 20 分;答出 MQ 广播失效各节点 L1 得 25 分;答出短 TTL + 逻辑过期兜底得 15 分;答出版本号校验过期得 20 分。",
|
||
"explanation": "多级缓存一致性的核心是“DB 真源 + 主动失效 + 过期兜底”。题目考察对读写路径和一致性窗口最小化的全套设计理解,属于本子主题较难的综合题。",
|
||
"source": null,
|
||
"related": []
|
||
}
|
||
]
|
||
}
|