{ "topic": "cache-read-write-strategy", "type": "fill_blank", "schema_version": "1.0.0", "generated": "09-2026-09-05T00:00:00+08:00", "questions": [ { "id": "fb-001", "type": "fill_blank", "difficulty": 1, "tags": [ "Cache-Aside", "写策略" ], "question": "Cache-Aside 策略的写流程是:先写______,再______缓存。", "answer": [ "数据库", "删除(失效)" ], "answer_rule": "ordered", "explanation": "Cache-Aside 的标准写流程:先把数据库当作真相源写入,再把缓存中的该 key 删除使其失效,等下次读请求 miss 后再回填,从而避免缓存与数据库长时间不一致。", "source": null, "related": [] }, { "id": "fb-002", "type": "fill_blank", "difficulty": 1, "tags": [ "Cache-Aside", "Read-Through", "CacheLoader" ], "question": "Cache-Aside 的读流程是:先查缓存,若 miss 则查询______,并把结果______到缓存后返回。", "answer": [ "数据库", "回填(写入)" ], "answer_rule": "ordered", "explanation": "读请求先查缓存,miss 时由应用查数据库拿到最新值并回填缓存,再返回给调用方。这样后续相同 key 的读可以直接命中缓存,减少数据库压力。", "source": null, "related": [] }, { "id": "fb-003", "type": "fill_blank", "difficulty": 3, "tags": [ "Write-Through", "Write-Behind" ], "question": "Write-Through 策略写操作是______地把数据写入缓存和数据库;而 Write-Behind 是先写入缓存、数据库由后台______批量刷写。", "answer": [ "同步", "异步" ], "answer_rule": "ordered", "explanation": "Write-Through 写缓存即同步写数据库,强一致但慢;Write-Behind 写入缓存后立即返回成功,数据库由后台攒批/定时异步刷写,吞吐高但有丢失与乱序风险。", "source": null, "related": [] }, { "id": "fb-004", "type": "fill_blank", "difficulty": 3, "tags": [ "Write-Behind", "Write-Back", "数据安全" ], "question": "Write-Behind 策略在返回成功到数据落库之间若缓存进程宕机,会带来______风险;因此它只适合最终一致且可容忍______的数据,不适合交易、余额、库存。", "answer": [ "丢失", "丢失" ], "answer_rule": "any", "explanation": "Write-Behind 先缓存后异步落库,若缓存宕机且尚未刷库则数据永久丢失。因此只适用于「最终一致 + 可容忍丢失」的数据,例如计数、会话、中间态;交易、余额等绝不可用。", "source": null, "related": [] }, { "id": "fb-005", "type": "fill_blank", "difficulty": 3, "tags": [ "多级缓存", "L1", "L2" ], "question": "经典多级缓存结构是 L1 ______ 缓存 → L2 ______ 缓存 → DB。", "answer": [ "本地(进程内)", "Redis(共享)" ], "answer_rule": "ordered", "explanation": "经典多级缓存为「L1 本地进程内缓存(如 Caffeine)→ L2 Redis(共享)→ DB」。本地命中最快零网络,Redis 次之毫秒级,DB 兜底保证最终一致。", "source": null, "related": [] }, { "id": "fb-006", "type": "fill_blank", "difficulty": 4, "tags": [ "多级缓存", "一致性" ], "question": "多级缓存架构最大的代价是其______:同一数据在多个缓存层、多个节点上有副本,更新后若任一副本残留旧值就会不一致。写路径需要在先写数据库后,逐层________。", "answer": [ "一致性", "失效(删除/清理)" ], "answer_rule": "ordered", "explanation": "多级缓存中同一数据在 L1、L2 及多节点均有副本,跨层跨节点难以保证实时一致,所以一致性是最大代价。写路径以数据库为真相源,写后须逐层失效:删除 Redis 并广播清理各节点本地缓存。", "source": null, "related": [] }, { "id": "fb-007", "type": "fill_blank", "difficulty": 4, "tags": [ "双删", "延时", "竞态" ], "question": "双删方案是:更新数据库后先删一次缓存,延时约______毫秒后再删一次,用来清掉第一次删除之后刚被回填的旧值。", "answer": [ "50" ], "answer_rule": "any", "explanation": "标准双删的延时通常在几十毫秒(教材常取约 50ms),目的是让可能已读取旧值并发起回填的并发读请求完成回填,然后用第二次删除把它清掉。延时过短则回填可能还没发生,过长则会放大读 miss 窗口。", "source": null, "related": [] }, { "id": "fb-008", "type": "fill_blank", "difficulty": 4, "tags": [ "版本号回填", "竞态" ], "question": "在解决「旧值被回填」竞态问题的方案里,最彻底的是______回填:缓存数据带版本号,回填前比较,旧版本直接丢弃。", "answer": [ "版本号" ], "answer_rule": "any", "explanation": "版本号回填在缓存里同时存业务值和版本号,回填前比较新旧版本,旧版本直接丢弃,杜绝读线程把库里的旧值重新写回缓存。相比双删的「概率性清理」更彻底,是根治竞态窗口来源2的方案。", "source": null, "related": [] }, { "id": "fb-009", "type": "fill_blank", "difficulty": 3, "tags": [ "CacheLoader", "refreshAfterWrite", "Read-Through" ], "question": "Caffeine 用 ________ 把 Cache-Aside 封装成 Read-Through,缓存 miss 时自动加载;用 ________ 在写后到点异步刷新,防止热点 key 被击穿。", "answer": [ "CacheLoader", "refreshAfterWrite" ], "answer_rule": "ordered", "explanation": "CacheLoader 让 Caffeine 在 miss 时自动回调加载数据(Read-Through 的本地版);refreshAfterWrite 在写入指定时长后异步刷新,避免过期瞬间大量请求同时穿透数据库造成击穿。", "source": null, "related": [] }, { "id": "fb-010", "type": "fill_blank", "difficulty": 3, "tags": [ "Caffeine", "TinyLFU" ], "question": "Caffeine 的淘汰算法是 ________,它通过记录 key 的访问________来判定淘汰,比 LRU 更能保留高频 key。", "answer": [ "TinyLFU", "频率" ], "answer_rule": "ordered", "explanation": "Caffeine 使用 TinyLFU 淘汰算法,维护计数器记录 key 的访问频率并带时间衰减与最近访问,可避免 LRU 被批量顺序扫描冲垮,更适合热点集中的真实负载。", "source": null, "related": [] } ] }