feat: add database topic group with 105 questions
Deploy Examination / deploy (push) Successful in 4s

- mysql-acid (35): undo/redo log, WAL, 崩溃恢复三阶段, 两阶段提交
- mysql-transaction-isolation (35): 四隔离级别, 三异常, Read View, 快照读/当前读, next-key lock
- redis-persistence (35): RDB/AOF/混合持久化, AOF 重写, vs binlog/redo log
- 每子主题: single_choice×10 + fill_blank×10 + short_answer×10 + code_reading×5
- 全部通过 question.schema.json 校验
This commit is contained in:
2026-09-07 19:17:38 +08:00
parent 0015449dcf
commit 515acbcc7f
16 changed files with 2951 additions and 1 deletions
@@ -0,0 +1,254 @@
{
"topic": "redis-persistence",
"type": "code_reading",
"schema_version": "1.0.0",
"generated": "2026-09-07T00:00:00+08:00",
"questions": [
{
"id": "cr-001",
"type": "code_reading",
"difficulty": 2,
"tags": [
"AOF",
"AOF重写",
"命令序列",
"状态快照"
],
"question": "请阅读下面这段 AOF 文件里按时间顺序追加的命令流。假设这些命令都已被 Redis 执行并写入 AOF,随后触发了一次 AOF 重写(BGREWRITEAOF)。",
"code": "SET user:1001 zhangsan\nSET user:1001 zhangsanfeng\nSET user:1002 lisi\nDEL user:1001\nINCR view:homepage\nSET counter 5\nINCRBY counter 1\nDEL counter",
"language": "plaintext",
"source": null,
"related": [],
"sub_questions": [
{
"index": 1,
"type": "single_choice",
"question": "经过 AOF 重写后,新 AOF 文件里针对 user:1001 这条 key 记录的命令是什么?",
"options": {
"A": "SET user:1001 zhangsan 和 SET user:1001 zhangdanfeng(保留两条)",
"B": "DEL user:1001(因为最后被删除了)",
"C": "SET user:1001 zhangdanfeng(最终值)",
"D": "不写该 key(因为最终不存在)"
},
"answer": "D",
"explanation": "AOF 重写不再按命令逐条重放,而是遍历当前内存数据库的状态,为每个 key 生成一条能重建其最终值的命令。user:1001 的最后一条命令是 DEL,即该 key 当前已不存在,因此重写后根本不生成任何关于 user:1001 的命令。A 保留了被覆盖的旧命令,B 生成一条 DEL 是错误的(key 已无,无需再删),C 误以为留下中间值,都错。"
},
{
"index": 2,
"type": "short_answer",
"question": "重写后,counter 和 view:home 这两个 key 对应的命令分别是什么?为什么 AOF 重写能把这些命令从 8 条大幅精简?",
"answer": "重写后:counter 被最后一条 DEL 删除,key 已不存在,所以不生成命令;view:home 只剩 INCRBY view:home 1。\n\n能大幅精简的根本原因:AOF 存的是『命令序列』(append-only log),大量早期命令的中间结果会被后续命令覆盖(user:1001 被反复覆盖后删除、counter 被 INC/INCRBY 后再 DEL)。AOF 重写遍历当前内存哈希表,为每个 key 只生成一条『重建当前最终状态』的最小命令,把存储的具体『操作时间线』等价转换为『键值状态快照』,冗余的历史操作被丢弃,文件因此变小,恢复也更快。",
"explanation": "本题考察 AOF 重写的本质:将『命令序列』重新组织为『状态快照』。counter 终态不存在故无命令;只有仍存在的 key 才生成最小重建命令。压缩的核心依据是:大量命令对同一 key 是互相覆盖的,只保留最终值就能恢复一致状态。",
"keywords": [
"不存在",
"状态快照",
"命令序列",
"重建最终值",
"最小命令",
"覆盖",
"压缩"
],
"scoring_rubric": "①答出 counter 不存在、view 为 INCRBY 得 1 分;②答出 counter key 已删不生成命令得 1 分;③说明重写是把命令序列转换为键值状态快照、丢弃被覆盖的中间命令、文件变小得 3 分。"
}
],
"explanation": "AOF 本身是一条一条 append 命令的时间线(log 结构),AOF 重写则遍历当前内存把时间线精简为哈希的 key→最终状态。凡是被删除或被后续命令覆盖的中间命令全部丢弃,达到『压缩』。这是理解 AOF 能压缩的本质(log 结构→状态快照)。"
},
{
"id": "cr-002",
"type": "code_reading",
"difficulty": 3,
"tags": [
"AOF",
"RDB",
"恢复",
"持久化配置"
],
"question": "下面是一台 Redis 实例的持久化配置(精简展示)。请阅读配置并回答进程崩溃重启时的数据恢复行为。",
"code": "# redis.conf 片段\nsave 900 1\nsave 300 10\nappendonly no",
"language": "bash",
"source": null,
"related": [],
"sub_questions": [
{
"index": 1,
"type": "single_choice",
"question": "以上配置下,若 Redis 距离上一次 RDB 快照 10 分钟时进程宕机,最多可能丢失多少数据?",
"options": {
"A": "0,因为 Redis 每次写都实时落盘",
"B": "最近 5 分钟内写入的所有数据(有 save 300 的兜底)",
"C": "从上一次成功完成 RDB 快照之后到宕机前写操作的所有数据",
"D": "最后 30 秒的数据"
},
"answer": "C",
"explanation": "本配置中 appendonly 为 no(关闭),只靠 RDB 快照持久化。RDB 是『定时的全量快照』,save 300 1 表示 300 秒内至少有 1 次写才触发一次生成点。宕机时只恢复到最近一次成功快照,快照之后的所有写操作全部丢失。所以『最长可能丢失上一次快照到宕机之间的全部写数据』(选 C)。A 错误,Redis 不是每次写都落盘;B 混淆了 save 触发间隔与丢数据范围;D 是 AOF 场景不适用于这里。"
},
{
"index": 2,
"type": "short_answer",
"question": "同样的业务若想几乎不丢数据,应如何调整配置?为什么?",
"answer": "开启 AOF(将 appendonly 改为 yes),并根据数据重要程度选择同步策略,例如 appendfsync always(每条写命令都 fsync,最安全但性能低,几乎不丢)或 everysec(每秒同步,最多丢约 1 秒数据)。原因:RDB 是周期快照,快照间隔之间的数据没有任何日志兜底;AOF 是追加写命令日志,崩溃后通过重放命令恢复,丢失窗口被压缩到 appendfsync 决定的粒度(always=几乎不丢,everysec≤1s,如果需要可用 appendfsync no 让系统决定)。",
"explanation": "本题考察 RDB vs AOF 在数据安全上的取舍。开启 AOF 后,丢失窗口会从『上一次快照点』缩小到『appendfsync 策略决定的粒度』。平常推荐 everysec(性能/安全平衡),绝对不可丢的选 always。",
"keywords": [
"appendonly yes",
"appendfsync",
"everysec",
"always",
"重放",
"丢失窗口"
],
"scoring_rubric": "①答出开启 appendonly/AOF 得 1 分;②答出 appendfsync 取值及对应丢失窗口得 2 分;③说明 AOF 基于命令重放还原、丢失窗口从 RDB 快照周期缩小到同步粒度得 2 分。"
}
],
"explanation": "RDB 快照与 AOF 日志在『丢数据范围』上差异极大:RDB 丢到上次快照,AOF 丢到 appendfsync 粒度。本题考查在给定持久化配置下计算最大丢数据量、以及如何调整降低丢失。"
},
{
"id": "cr-003",
"type": "code_reading",
"difficulty": 3,
"tags": [
"redo log",
"环形缓冲",
"崩溃恢复",
"循环复用"
],
"question": "下面用伪代码描述 InnoDB redo log 的『环形』复用思想。阅读并回答:为什么 redo log 不像 AOF 那样无限膨胀、也不像 AOF 需要主动重写压缩。",
"code": "# 伪代码:redo 环形缓冲区覆盖逻辑\ndef write_redo(head_lsn, tail_lsn, capacity):\n # 环形缓冲区大小固定(如 1GB)\n while (head_lsn - tail_lsn) >= capacity:\n flush_dirty_page_to_disk() # 强制刷脏页,推进 rev per tail/checkpoint\n append_record(page_lsn)\n head_lsn = head_lsn + 1",
"language": "readtext",
"source": null,
"related": [],
"sub_questions": [
{
"index": 1,
"type": "single_choice",
"question": "redo log 采用『环形固定大小』覆盖最旧记录,覆盖旧记录最典型的前提条件是什么?",
"options": {
"A": "只要文件满了就直接覆盖最旧记录,不考虑数据页是否已落盘",
"B": "被覆盖的记录所对应的脏页必须先成功刷回磁盘(checkpoint 推进),否则崩溃会丢数据",
"C": "先把 redo log 文件长度翻倍再覆盖",
"D": "每次启动都清空整个 redo 文件"
},
"answer": "B",
"explanation": "redo log 用于崩溃后重放:它记录的是尚未安全刷盘的数据页修改。覆盖旧记录的前提是,这些旧记录对应的脏页已经成功刷到数据文件(即 checkpoint 位置推进),否则一旦被覆盖而对应页面还没落盘,崩溃后就无法重放、造成永久丢失。所以先触发脏页刷盘(推进 checkpoint)再覆盖。A 直接覆盖会丢数据,C/D 与场景无关。"
},
{
"index": 2,
"type": "short_answer",
"question": "从『数据结构(覆盖 vs 追加)』角度,说明 redo log 为何天然不膨胀、不需要像 AOF 那样主动重写;它们对中间过程的保留策略分别是什么?",
"answer": "redo log 是固定大小的环形缓冲(记录按 LSN 排序),当旧记录对应的脏页已落盘后,新记录就覆盖旧记录,天然丢弃了『已安全落盘、无需再重放』的物理页变更,只保留尚未落盘的部分,文件体积固定、不膨胀,无需主动重写。AOF 是末尾追加、累进的命令序列,命令一 append 就永久保留,会随时间无限膨胀,才需要 BGREWRITEAOF 主动把命令序列压缩成状态快照。\n对中间过程:redo 是物理层覆盖合并,不保留每次中间变更,重放只针对尚未落盘的最终页状态;AOF 则保留全部命令历史,直到重写时才丢弃被覆盖/删除的命令。",
"explanation": "二者数据结构(环形覆盖 vs 末尾追加)决定了是否需要主动压缩。redo『环形+checkpoint 推进』→ 天然不膨胀;AOF『append 追加』→ 需显式重写。这正是题目伪代码(后半是覆盖)与 AOF(后半是追加)的对照。",
"keywords": [
"环形缓冲",
"覆盖",
"checkpoint",
"脏页落盘",
"LSN",
"不膨胀",
"追加",
"重写",
"状态快照"
],
"scoring_rubric": "①答出 redo 是环形固定大小、覆盖已落盘旧页、天然不膨胀得 2 分;②答出 AOF 是末尾追加、积累全部命令、才需显式重写得 2 分;③说到中间过程差异(物理覆盖合并 vs 保留历史到重写)得 1 分。"
}
],
"explanation": "关键在『覆盖 vs 追加』的数据结构差异:redo 环形覆盖天然合并中间过程、体积固定,AOF 追加增长→需要主动重写。这正是 AOF 为何要压缩而 redo 不用压缩的根因。"
},
{
"id": "cr-004",
"type": "code_reading",
"difficulty": 2,
"tags": [
"binlog",
"PITR",
"时间点恢复",
"mysqlbinlog"
],
"question": "某运维在 14:00 误删除了一张表,希望恢复到 13:59 的状态。已有 12:00 的全量备份。阅读下面的恢复思路并回答。",
"code": "# 1. 先恢复 12:00 的全量备份\ntar -xzf backup_1200.tar.gz && mysql < backup_1200.sql\n\n# 2. 再用 binlog 做增量重放,停在误操作前\nmysqlbinlog --start-position=<pos1> --stop-position=<pos2> binlog.000123 | mysql",
"language": "bash",
"source": null,
"related": [],
"sub_questions": [
{
"index": 1,
"type": "single_choice",
"question": "binlog 做时间点恢复时,'' 为什么用 '--stop-position'(文件+偏移)比单纯用 '--stop-datetime'(时间字符串)更能保证精确?",
"options": {
"A": "--stop-datetime 只对 ROW 格式生效,对 statement 格式失效",
"B": "时间戳是按 SQL 语句粗略过滤的,可能在一条事务/语句内部截止,导致该事务只执行了一半;而 position 是 binlog 里精确的字节偏移,可对准完整事件边界",
"C": "--stop-position 参数并不存在,MySQL 只支持 --stop-datetime",
"D": "--stop-position 会把日志里的所有事务一起截断,无法只保留部分"
},
"answer": "B",
"explanation": "binlog 中能唯一定位重放位置的是文件的物理偏移(position),而非时间。--stop-datetime 按语句/事务的记录时间过滤,可能把一个未结束的事务切在中间(一半重放一半不重放),破坏事务原子性;position 能精确对准一个事件边界,所以做 PITR 用它最安全。A、D 说法无依据,C 错误(--stop-position 存在)。"
},
{
"index": 2,
"type": "short_answer",
"question": "『从全量备份 + binlog 增量重放』这一整套恢复操作官方叫什么?为什么 AOF 做不到像 binlog 这样精准重放到任意历史点?",
"answer": "这套操作叫 point-in-time recovery(PITR,时间点恢复)。binlog 为 PITR 设计:逐条记录事务(含文件号+字节位置),配合全量备份可精确拼到任何一个历史提交点;mysqlbinlog 支持 --start-position/--stop-position(字节精确)和 --stop-datetime(时间近似)。AOF 是 Redis 的持久化日志,虽然记录了全部写命令,但它是『从文件头按顺序重放到文件尾』,命令本身没有内建可精确到事务边界的 position 切片接口,也没有标准的『从中间某条开始/停止』重放工具,要从历史某一时刻恢复需要手工截断文件再重放,非常不便,因此只说『可大致回到历史某个时间点、但需手动截断』,不像 binlog 原生支持精确切片。",
"explanation": "PITR 是 binlog 的核心能力,靠每条记录的位置+完整事务边界。AOF 虽也是命令日志,但其定位是『崩溃后从头把内存状态重放到当前』,而非『精确停在历史某一事务横切』,加上缺少原生 position/时间点切片命令,所以只能手动截断。",
"keywords": [
"PITR",
"时间点恢复",
"position",
"全量备份",
"增量重放",
"从头顺序重放",
"无时间切片"
],
"scoring_rubric": "①答出 PITR 得 1 分;②说明 binlog 用备份+position 增量重放实现精确到点得 2 分;③点出 AOF 只能从头顺序重放到末尾、缺少原生时间点重放而需要手动截断得 2 分。"
}
],
"explanation": "考察 binlog 与 AOF 在时间点恢复上的差异。核心:binlog 支持 position/位点(PITR 精确),AOF 只能从头到末尾顺序重放、无原生时间点切片。"
},
{
"id": "cr-005",
"type": "code_reading",
"difficulty": 3,
"tags": [
"AOF",
"appendfsync",
"丢失窗口",
"AOF重写",
"配置"
],
"question": "下图为某 Redis 的 AOF 相关配置片段。请理解其含义并回答相应问题。",
"code": "appendonly yes\nappendfsync everysec\nauto-aof-rewrite-percentage 100\nauto-aof-rewrite-min-size 64mb",
"language": "bash",
"source": null,
"related": [],
"sub_questions": [
{
"index": 1,
"type": "single_choice",
"question": "在 appendfsync everysec 下,当进程宕机(不是主机断电)时,最多大约丢失多少数据?",
"options": {
"A": "1 秒的写入数据",
"B": "0 数据,一条都不丢",
"C": "距离上一次自动重写之间的全部写入数据",
"D": "最多 64MB 数据"
},
"answer": "A",
"explanation": "everysec 表示每 1 秒把 AOF 缓冲 fsync 到磁盘一次,因此最多丢失『最后一次 fsync 到崩溃之间』这一秒的写入。'always' 才是一条不丢(B 错);C 混淆了 AOF 重写间隔与丢失窗口;D 把 auto-aof-rewrite-min-size 当成丢数据量,错误。"
},
{
"index": 2,
"type": "short_answer",
"question": "auto-aof-rewrite-percentage 100 和 auto-aof-rewrite-min-size 64mb 这两个参数控制什么行为?这里的『重写』做了什么?",
"answer": "它们控制 AOF 自动重写(BGREWRITEAOF)的触发条件:当当前 AOF 文件体积相对上次重写后的文件增长幅度超过 100%(即翻倍),并且当前文件大小已经超过 64MB 的下限时,Redis 自动在后台触发一次 AOF 重写。\n重写的行为:遍历当前内存数据库,为每个 key 只重新生成一条重建其最终状态的最小命令(可配合前缀批量,尽量小段),丢弃掉大量被覆盖或已删除的旧命令,把膨胀的命令日志压缩为接近『状态快照』的小体积日志,文件变小,重启重放更快。",
"explanation": "auto-aof-rewrite-percentage/min-size 是 AOF 自动重写的双阈值:相对上一轮的增长百分比 + 最小文件下限,两者同时满足才自动触发。重写本质是把『命令日志 → 状态快照』压缩,避免 AOF 无限膨胀。",
"keywords": [
"auto-aof-rewrite-percentage",
"100%增长",
"64MB下限",
"BGREWRITEAOF",
"状态快照",
"压缩"
],
"scoring_rubric": "①解释 percentage 是相对上一轮增长幅度、min-size 是最小下限、需要同时满足得 2 分;②说明重写把命令日志转成最小状态快照、避免膨胀得 3 分。"
}
],
"explanation": "考查 AOF 配置阈值与后台重写。appendfsync 决定丢失窗口,rewrite 阈值决定何时压缩 AOF 文件,两者结合掌握 AOF 的核心运维。"
}
]
}
@@ -0,0 +1,215 @@
{
"topic": "redis-persistence",
"type": "fill_blank",
"schema_version": "1.0.0",
"generated": "2026-09-07T00:00:00+08:00",
"questions": [
{
"id": "fb-001",
"type": "fill_blank",
"difficulty": 1,
"tags": [
"Redis",
"持久化",
"AOF",
"RDB"
],
"question": "Redis 的 AOF 通过把每条____命令依次____到文件末尾,重启后按序____这些命令来恢复数据;Redis 的 RDB 则是把某时刻的____序列化成语义 sized 的全量快照文件。",
"answer": [
"写",
"追加",
"重放",
"键值状态"
],
"answer_rule": "ordered",
"explanation": "AOF 保存的是“命令”(逻辑增量),以追加方式写入,恢复时重放命令;RDB 保存的是“键值状态”(全量快照)。这个“追加命令 vs 状态快照”的对立是理解两种持久化的关键。",
"source": null,
"related": []
},
{
"id": "fb-002",
"type": "fill_blank",
"difficulty": 1,
"tags": [
"Redis",
"持久化",
"RDB"
],
"question": "RDB 采用____(定时/每次写)方式做全量快照,因此文件____(更小/更大)、重载____(更快/更慢),但两次快照之间的数据在宕机后会____。",
"answer": [
"定时",
"更小",
"更快",
"丢失"
],
"answer_rule": "ordered",
"explanation": "RDB 定时全量快照:占用内存状态的极小二进制文件,恢复时直接载入状态而非逐命令重放,因此更小更快;代价是两次快照间隔内写入的数据在异常宕机时会丢失。",
"source": null,
"related": []
},
{
"id": "fb-003",
"type": "fill_blank",
"difficulty": 2,
"tags": [
"AOF",
"AOF重写",
"状态快照",
"命令序列"
],
"question": "AOF 重写(BGREWRITEAOF)的本质是把____序列重新生成为____描述,把命令流“压缩”成等价的键值状态;它丢弃的是被后续____覆盖的大量____命令。",
"answer": [
"命令",
"键值状态快照",
"命令/写操作",
"中间"
],
"answer_rule": "ordered",
"explanation": "重写的本质是“命令序列 → 状态快照”的等值转换:从当前内存状态出发生成重建所需的最小命令集,把被最终值覆盖的中间命令(如重复 SET、先增后删等)丢弃,从而压缩文件体积。注意四点顺序:命令、状态快照、中间命令。",
"source": null,
"related": []
},
{
"id": "fb-004",
"type": "fill_blank",
"difficulty": 2,
"tags": [
"AOF",
"AOF重写"
],
"question": "给定 AOF 命令序列:SET k 1;INCRBY k 5;SET k 9;DEL k;SET k 2。执行 AOF 重写后,恢复同样状态(k=2)的最小等价命令应为____(写出命令)。",
"answer": [
"SET k 2"
],
"answer_rule": "any",
"explanation": "前 4 条命令产生的任何状态都被最后的 SET k 2 完全覆盖,因此只需保留最后这条 SET。答案等价写法如 `SET k 2` 即可。",
"source": null,
"related": []
},
{
"id": "fb-005",
"type": "fill_blank",
"difficulty": 2,
"tags": [
"AOF",
"binlog",
"追加日志",
"重放"
],
"question": "Redis 的 ____ 与 MySQL 的 ____ 都属于记录写操作并可重放的追加日志;但 binlog 支持丰富的位点控制,而 AOF 没有原生的时间切片点,要做定点重放需要手动____文件。",
"answer": [
"AOF",
"binlog",
"截断"
],
"answer_rule": "ordered",
"explanation": "AOF 与 binlog 对应关系是“记录写操作并可重放”这一面;差别在于 binlog 具备 --start-position/--stop-position(精确)与 --start/--stop-datetime(近似)位点能力,AOF 则需人工截断 append 文件实现定点重放。",
"source": null,
"related": []
},
{
"id": "fb-006",
"type": "fill_blank",
"difficulty": 3,
"tags": [
"binlog",
"重放"
],
"question": "MySQL 基于 binlog 的 Point-In-Time Recovery(PITR)核心做法是:先用____恢复全量备份,再用 ____ 以 ____(精确)或 ____(近似)位点重放增量变更。",
"answer": [
"全量备份/mysqldump",
"mysqlbinlog",
"--start-position/--stop-position",
"--start-datetime"
],
"answer_rule": "ordered",
"explanation": "PITR 流程:先恢复最近的逻辑/物理全备,再回放备份之后的 binlog;精确恢复使用 mysqlbinlog 的 --start-position/--stop-position(字节位点),近似用 --start/--stop-datetime。因此顺序为:全量备份、mysqlbinlog、位置参数、datetime 参数。",
"source": null,
"related": []
},
{
"id": "fb-007",
"type": "fill_blank",
"difficulty": 3,
"tags": [
"redo log",
"物理日志"
],
"question": "InnoDB 的 redo log 记录的是对____(页面)层面所做的物理变更(页号、偏移、字节),属于____日志;AOF/ binlog 记录的是____层逻辑操作,属于____日志。",
"answer": [
"物理页",
"物理",
"逻辑/命令/SQL/行变更",
"逻辑"
],
"answer_rule": "ordered",
"explanation": "redo 面向物理页(页号+偏移+字节)描述最终状态变化,是物理日志;AOF 记录命令、binlog 记录 SQL/行变更,都在逻辑层,属逻辑日志。这是 redo 与 AOF/binlog 在“物理 vs 逻辑”层面的核心差异。",
"source": null,
"related": []
},
{
"id": "fb-008",
"type": "fill_blank",
"difficulty": 3,
"tags": [
"redo log",
"环形缓冲",
"追加日志"
],
"question": "InnoDB redo log 使用____大小的____结构,旧页写入磁盘后对应记录即可被循环____,因此它天然不会无限膨胀,无需像 AOF 那样进行显式____。",
"answer": [
"固定",
"环形缓冲",
"覆盖/复用",
"重写/压缩"
],
"answer_rule": "ordered",
"explanation": "redo 固定大小 + 环形复用(旧日志可被覆盖)实现隐式防膨胀;AOF 需显式重写(BGREWRITEAOF)合并命令。四空分别对应:固定、环形缓冲、覆盖、重写。",
"source": null,
"related": []
},
{
"id": "fb-009",
"type": "fill_blank",
"difficulty": 3,
"tags": [
"AOF",
"redo log",
"AOF重写",
"环形缓冲"
],
"question": "AOF 通过____方式应对日志膨胀(命令序列重新生成成语义快照),而 redo log 通过环形缓冲____旧页来隐式控制大小;两者防止膨胀的____不一致性正是“显式重写合并 vs 隐式覆盖”的体现。",
"answer": [
"重写/重写合并",
"覆盖",
"时机"
],
"answer_rule": "ordered",
"explanation": "AOF 日志会持续放大,需用户显式触发/策略配置自动触发的重写压缩;redo 则依靠环形覆盖机制在检查点后自动隐式回收。三空为:重写、覆盖、时机。",
"source": null,
"related": []
},
{
"id": "fb-010",
"type": "fill_blank",
"difficulty": 4,
"tags": [
"redo log",
"undo log",
"一致",
"恢复"
],
"question": "MySQL 崩溃恢复中,redo log 对所有____事务被脏页做前向____,undo log 对____事务做____,二者配合保证恢复后的持久性与一致性。",
"answer": [
"已提交",
"重做",
"未提交",
"回滚"
],
"answer_rule": "ordered",
"explanation": "崩溃恢复:已提交但落盘不全的事务用 redo 前向重做使其持久;未提交事务用 undo 回滚其部分写入。顺序为:已提交、重做、未提交、回滚。",
"source": null,
"related": []
}
]
}
@@ -0,0 +1,57 @@
{
"slug": "redis-persistence",
"name": "Redis 持久化与日志对比",
"description": "AOF/RDB 持久化机制、AOF 重写压缩原理、与 MySQL binlog/redo log/undo log 的对比(数据结构角度)",
"tags": [
"AOF",
"AOF重写",
"InnoDB成",
"MySQL",
"PITR",
"RDB",
"Redis",
"WAL",
"appendfsync",
"binlog",
"innodb_flush",
"position",
"redo",
"redo log",
"不膨胀",
"压缩",
"同步配置对比",
"对应关系",
"对比",
"持久化",
"持久性",
"日志",
"日志对比",
"时间点恢复",
"状态快照",
"环形",
"综合",
"覆盖",
"选型"
],
"difficulty_range": [
2,
4
],
"schema_version": "1.0.0",
"updated": "2026-09-07",
"question_files": [
"single_choice",
"fill_blank",
"code_reading",
"short_answer"
],
"stats": {
"total": 35,
"by_type": {
"single_choice": 10,
"fill_blank": 10,
"code_reading": 5,
"short_answer": 10
}
}
}
@@ -0,0 +1,261 @@
{
"topic": "redis-persistence",
"type": "short_answer",
"schema_version": "1.0.0",
"generated": "2026-09-07T00:00:00+08:00",
"questions": [
{
"id": "sa-001",
"type": "short_answer",
"difficulty": 2,
"tags": [
"AOF",
"持久化",
"Redis"
],
"question": "什么是 AOF 持久化?它记录『什么类型的信息』(命令还是数据状态),重启后如何恢复数据?",
"answer": "AOF(Append Only File)是 Redis 的持久化机制之一:每一条写命令(如 SET/LPUSH/INCRBY)以 RESP 协议格式追加写入一个 aof 文件中。它记录的是『写命令(操作)』,而不是『数据的最终状态』。重启恢复时,Redis 读取 AOF 文件,从第一条命令开始按顺序逐条重新执行(重放),把命令再次应用到空的内存数据库,最终恢复到崩溃/关闭前的一致状态。",
"keywords": [
"写命令",
"追加",
"重放",
"RESP"
],
"scoring_rubric": "①答出记录写命令而非数据状态得 2 分;②答出追加写入得 1 分;③答出重启后从头顺序重放命令恢复得 2 分。",
"explanation": "AOF 区别于 RDB 的本质:记录『操作』不记录『状态』,靠重放而非读快照。这是理解 AOF 重写、命令可压缩的基础。",
"source": null,
"related": []
},
{
"id": "sa-002",
"type": "short_answer",
"difficulty": 2,
"tags": [
"AOF",
"RDB",
"对比",
"选型"
],
"question": "RDB 快照和 AOF 日志在数据安全性、恢复速度、文件大小三方面各有什么特点?如何取舍?",
"answer": "RDB(快照):存定时的全量快照,文件小、恢复快、加载快;但两次快照间隔若宕机,会丢失这段数据,安全性相对低。\nAOF(日志):存追加命令,数据更安全(丢失窗口可压到 appendfsync 粒度),但文件随命令增长、恢复需逐条重放所以较慢;自动重写可压缩体积。\n取舍:能容忍少量丢失、求恢复快文件小用 RDB;数据必须尽量不丢(如秒杀成交、订单)用 AOF 甚至 always;生产通常 RDB + AOF 混合兼顾。",
"keywords": [
"RDB",
"AOF",
"安全性",
"恢复速度",
"文件大小",
"混合"
],
"scoring_rubric": "①正确列出 RDB/AOF 在数据形式与安全性差异得 2 分;②恢复速度、文件大小差异得 2 分;③给出取舍得 1 分。",
"explanation": "RDB=状态快照、AOF=命令日志。安全、恢复速度、文件大小三维度对比是持久化选型的核心题。",
"source": null,
"related": []
},
{
"id": "sa-003",
"type": "short_answer",
"difficulty": 3,
"tags": [
"AOF重写",
"压缩",
"状态快照"
],
"question": "从数据结构角度解释:AOF 为什么可『压缩』?重写到底改变哪些内容,本质是什么转换?",
"answer": "因为 AOF 是『命令序列』(log 结构),同一个 key 的多次写命令只有最后一次才决定其最终状态,早期命令基本可被覆盖/丢弃。例如 SET a=1 → SET a=2 → SET a=3 共存时,只有最后一条有意义;被 DEL 的 key 连任何命令都不需要。大量历史命令对恢复最终状态是冗余的,这才有压缩空间。\n\nAOF 重写(BGREWRITEAOF)的本质:不复用旧命令,而是遍历当前内存数据库的键值状态,为每个 key 重新生成一条『重建其最终值』的最小命令,生成一份新文件替换旧文件。这相当于把『命令序列 / 操作日志』等价转换为『键值状态快照』——丢弃所有可被最终状态覆盖的中间命令,文件从『随命令无限膨胀的命令日志』压缩成『接近最终状态的快照』。",
"keywords": [
"命令冗余",
"只看最终值",
"状态快照",
"BGREWRITEAOF",
"遍历内存",
"最小命令"
],
"scoring_rubric": "①说明 AOF 是命令序列、大量中间命令冗余可被覆盖得 2 分;②说出重写遍历当前内存为每个 key 生成最小重建命令、把命令序列转成状态快照得 3 分。",
"explanation": "这是『AOF 为何可压缩』的核心。关键在于『log(命令时间线)→ 状态快照』的数据结构切换,丢弃被覆盖的冗余命令使文件变小。",
"source": null,
"related": []
},
{
"id": "sa-004",
"type": "short_answer",
"difficulty": 2,
"tags": [
"binlog",
"AOF",
"对应关系",
"日志对比"
],
"question": "常说 Redis 的 AOF 相当于 MySQL 的 binlog,这个类比哪里对、哪里不完全对?",
"answer": "对的地方:二者都是记录『写操作』的追加日志,都可以通过重放/执行日志恢复数据,都是持久化与复制的载体。\n不完全对的地方:\n1. 定位与服务对象——binlog 主要服务主从复制、逻辑备份、PITR(时间点恢复)、审计,是 Server 层、可跨引擎;AOF 主要服务 Redis 自身持久化与崩溃恢复。\n2. 时间点恢复能力——binlog 原生支持 --start-position/--stop-position(字节精确)与 --start/--stop-datetime(时间近似),可直接做 PITR;AOF 无原生精确到历史某个事务位置的时间切片重放工具,需要手动截断,所以『回到任意历史时刻』对 AOF 是近似/需手工的。\n3. 记录粒度——binlog 记录 SQL(statement)或行变更(row),而 AOF 记录命令(RESP)。",
"keywords": [
"写操作日志",
"重放恢复",
"binlog",
"AOF",
"PITR",
"position",
"行变更",
"RESP"
],
"scoring_rubric": "①答出两者都是写操作日志、可重放恢复得 2 分;②指出 binlog 服务主从/PITR、AOF 服务自身持久化得 1 分;③指出 binlog 原生支持 position 切片、AOF 需手动截断得 1 分。",
"explanation": "类比对在对『都是写操作日志、可重放恢复』,不完全对在服务对象与时间点恢复能力(binlog 位点精确、AOF 需手工)。",
"source": null,
"related": []
},
{
"id": "sa-005",
"type": "short_answer",
"difficulty": 2,
"tags": [
"binlog",
"redo log",
"日志",
"MySQL"
],
"question": "MySQL 中 binlog 与 redo log 有什么区别?分别是『什么时候用』?",
"answer": "本质区别:\n- redo log:InnoDB 引擎内部自己用,记录物理页变更,目的是崩溃恢复、保证已提交事务数据不丢(WAL 重放);是固定大小环形缓冲。\n- binlog:MySQL Server 层产生,记录 SQL 或行变更,供主从复制、PITR、CDC、审计使用。\n\n什么时候用:关注崩溃数据不丢、恢复一致性 → 涉及 redo 机制与配置;主从复制、误删恢复到某时间点、把变更同步到外部系统(Canal 等)、审计 → 用 binlog。一句话:redo 是引擎内层『保底不丢』,binlog 是对外扩散/复制/审计层。",
"keywords": [
"redo log",
"binlog",
"崩溃恢复",
"主从",
"PITR",
"Server层",
"物理页"
],
"scoring_rubric": "①答出 redo 记录物理变更、引擎内用于崩溃后重放得 1 分;②答出 binlog 记录 SQL/行变更、用于主从/PITR/审计得 2 分;③说清两种场景分别用哪个日志得 2 分。",
"explanation": "redo 是引擎级崩溃恢复日志,binlog 是 server 级对外扩散日志,服务对象与场景截然不同的 ESR 是核心。",
"source": null,
"related": []
},
{
"id": "sa-006",
"type": "short_answer",
"difficulty": 3,
"tags": [
"redo",
"环形",
"不膨胀",
"覆盖"
],
"question": "为什么 redo log 采用『固定大小环形缓冲』而不像 AOF 那样无限追加?覆盖不影响数据安全由什么保证?",
"answer": "redo log 是物理日志,只服务于崩溃恢复,因此容量可以固定:它采用固定大小的环形缓冲循环写入,写到末尾就回到开头覆盖最旧的记录,空间天然可控,不会像 AOF 那样随写入量无限膨胀,也就不需要 AOF 那种显式的重写压缩。\n\n覆盖之所以不影响数据安全,关键在于 checkpoint 机制:一条 redo 记录只有在它对应的脏页已经刷到磁盘之后才允许被覆盖——因为页已落盘,崩溃后不再需要这条 redo 来重做。checkpoint 会随脏页刷盘不断向前推进,推进点之前的空间才可复用。若写入速度过快、redo 快要追上 checkpoint,InnoDB 会强制推进刷脏页(表现为线上偶发的写入抖动),从而保证绝不覆盖尚未落盘的记录。",
"keywords": [
"redo log",
"环形缓冲",
"固定大小",
"checkpoint",
"脏页刷盘",
"物理日志"
],
"scoring_rubric": "总分 5 分:答出 redo 是固定大小环形缓冲、写满循环覆盖所以不膨胀、无需显式重写得 2 分;答出覆盖安全由 checkpoint 保证(对应脏页已刷盘才允许覆盖)得 2 分;答出 redo 追上 checkpoint 时会强制刷脏页得 1 分。",
"source": null,
"related": [],
"explanation": "redo 之所以不膨胀,根本在于它是物理日志且容量固定:环形缓冲写满就回到开头覆盖,空间天然可控。而覆盖不破坏安全性靠 checkpoint——只有对应脏页已刷盘,该 redo 记录才允许被覆盖,因为崩溃后已不需要它重做。若 redo 快追上 checkpoint,InnoDB 会强制刷脏页(表现为写入抖动)。"
},
{
"id": "sa-007",
"type": "short_answer",
"difficulty": 3,
"tags": [
"binlog",
"AOF",
"PITR",
"时间点恢复",
"position"
],
"question": "『可以回到有记录的任意时间节点』这句话,对 binlog 和 AOF 各成立到什么程度?请从精确性说明区别。",
"answer": "对 binlog:基本成立且是核心能力之一。binlog 每条事务都有文件号+offset(position),mysqlbinlog 支持 --start-position/--stop-position(字节精确),也可用 --start/--stop-datetime(时间近似)。配合全量备份可拼到准确的任意历史提交点;位置比时间更精确,并能停在一个完整事务边界。对 AOF:只能说『大致能回到某时刻,但需手动截断文件再重放』。AOF 本质是『从头到尾顺序重放』,命令没有内建可精确到某个事务边界的切片重放接口,因此要从历史某一刻恢复需人工截断,不是像 binlog 那样原生精确到 position 并重放到那儿。",
"keywords": [
"binlog",
"AOF",
"PITR",
"position",
"手动截断",
"从头重放"
],
"scoring_rubric": "①对 binlog 说明支持 position/时间切片、可精确 PITR 得 2 分;②对 AOF 说明默认从头到尾重放、缺原生精准切片、需要手动截断得 3 分。",
"explanation": "区别核心:binlog 有【文件+position】原生精确切片,AOF 是顺序重放日志、缺 position/时间片切入命令,需人为兜底。",
"source": null,
"related": []
},
{
"id": "sa-008",
"type": "short_answer",
"difficulty": 2,
"tags": [
"InnoDB成",
"WAL",
"redo log",
"持久性"
],
"question": "什么是 WAL(Write-Ahead Logging)?MySQL InnoDB 为什么『先写 redo log 再落数据页』?",
"answer": "WAL(预写日志)核心:先提交前先把『本次修改对应的日志』写到磁盘,再做数据页修改。InnoDB 的做法:事务的 UPDATE 先记一条 redo 并 fsync 落盘(WAL),数据页先缓存内存 Buffer Pool,延迟刷盘;redo log fsync 之后 COMMIT 才算成功。好处:①顺序写比随机写快,redo 顺序 append、数据页随机刷,用顺序写低开销换持久性;②崩溃后重放 redo 把未落盘的已提交事务补上,保证失败不丢。本质:日志先行落盘,数据页延迟落盘,『已提交不丢』由日志而非页面落盘保证。",
"keywords": [
"WAL",
"先写日志",
"Buffer Pool",
"顺序写",
"崩溃恢复一",
"持久性"
],
"scoring_rubric": "①解释 WAL 是先写日志再写数据页得 2 分;②顺序写更快为何延迟刷得 1 分;③崩溃后重放 redo 保证已提交不丢得 2 分。",
"explanation": "WAL 是 InnoDB 持久性核心:COMMIT 只刷 redo log(顺序写),数据页由 Buffer Pool 管理、量通过同盘,崩溃重放。",
"source": null,
"related": []
},
{
"id": "sa-009",
"type": "short_answer",
"difficulty": 3,
"tags": [
"innodb_flush",
"AOF",
"appendfsync",
"同步配置对比"
],
"question": "对比 MySQL innodb_flush_log_at_trx_commit 与 Redis appendfsync:各自取值与『安全 / 性能』取舍?",
"answer": "innodb_flush_log_at_trx_commit(MySQL):0=提交由系统定时批量刷,性能最高、进程崩溃可能丢最近数据;1(默认)=每次提交 fsync redo,最安全、性能最低;2=每次提交写 OS 写缓存不 fsync,由 OS 稍后刷,进程崩溃不丢但 OS 宕机丢,性能居中。\nappendfsync(Redis AOF):always=每条写命令 fsync,丢失最少、性能最差;every每秒=每秒 fsync,最多丢 1 秒、性能/安全平衡(默认);no=交给 OS,性能最好、安全最差。\n两者思想一致:用一个刷盘频率旋钮权衡『实时安全(慢)』与『批量(快)』。",
"keywords": [
"innodb_flush_log_at_trx_commit",
"0/1/2",
"appendfsync",
"always/everysec/no",
"fsync"
],
"scoring_rubric": "①列出 innodb_flush 三个值并说明取舍各等 1 分(共 2-3 分);②列出 append 三个值并取舍(2 分);③点明两者都是安全/性能权衡得 1分。",
"explanation": "二者分别对应 MySQL redo、Redis AOF 的 fsync 策略,核心是『每次提交是否立刻刷盘』带来的安全/性能权衡。",
"source": null,
"related": []
},
{
"id": "sa-010",
"type": "short_answer",
"difficulty": 4,
"tags": [
"AOF",
"binlog",
"redo",
"时间点恢复",
"综合"
],
"question": "用『记录内容、主要使用者/场景起落、覆盖/追加结构、是否便于时间点恢复』四个维度对 AOF、binlog、redo log 做横向对比。",
"answer": "1. 记录内容:AOF 记 Redis 写命令(RESP);binlog 记 MySQL SQL(statement)或行变更(row);redo 记 InnoDB 物理页变更。\n2. 使用者/场景:AOF → Redis 持久化与崩溃恢复;binlog → 主从、PITR、CDC、审计(Server 层可跨引擎);redo → InnoDB 崩溃恢复、WAL。\n3. 记录结构:AOF 追加 append、可主动重写(压缩成状态快照);binlog 追加文件、靠 rotate+过期清理不主动压成快照;redo 环形覆盖已落盘记录、天然不膨胀也无需重写。\n4. 时间点恢复:AOF 从头顺序重放、无原生切片需手工截断;binlog 支持 position/时间、可直接做 PITR;redo 面向崩溃重放到当前、不用于历史时间点恢复。",
"keywords": [
"AOF",
"binlog",
"redo log",
"记录内容",
"使用者",
"覆盖",
"环形",
"append",
"PITR"
],
"scoring_rubric": "四维度各约等 1.25 分。要点:AOF 命令日志可显式重写、binlog 带 position 可用于 PITR、redo 物理环形覆盖用于崩溃重放。",
"explanation": "横向比较最综合。四组:记录内容、对象/场景、覆盖方式、时间点恢复能力。",
"source": null,
"related": []
}
]
}
@@ -0,0 +1,229 @@
{
"topic": "redis-persistence",
"type": "single_choice",
"schema_version": "1.0.0",
"generated": "2026-09-07T00:00:00+08:00",
"questions": [
{
"id": "sc-001",
"type": "single_choice",
"difficulty": 1,
"tags": [
"Redis",
"持久化",
"AOF",
"RDB"
],
"question": "Redis 的 AOF(Append Only File)与 RDB(快照)两种持久化方式,下列说法正确的是?",
"options": {
"A": "AOF 每隔固定时间做一次全量内存快照,文件小、重启加载快",
"B": "RDB 记录每条写命令文本,重启时依次重放命令来恢复数据",
"C": "AOF 通过记录每条写命令文本并在重启后重放来恢复数据;RDB 是定时全量快照",
"D": "RDB 与 AOF 都记录的是写命令序列,二者唯一的区别是文件格式文本/二进制"
},
"answer": "C",
"explanation": "AOF(Append Only File)的本质是把每条写命令按序追加到文件,重启后从文件头部开始按顺序重放这些命令恢复内存数据;RDB 则是把某个时刻的完整键值对状态序列化成一个体积较小、重启加载更快的二进制快照文件,两次快照之间写入的数据在宕机时会丢失。A 把 AOF 说成快照、B 把 RDB 说成命令重放、D 声称二者都记录命令,均错误;C 准确描述了二者差异。",
"source": null,
"related": []
},
{
"id": "sc-002",
"type": "single_choice",
"difficulty": 1,
"tags": [
"Redis",
"持久化",
"RDB"
],
"question": "下列关于 RDB(快速文件快照)持久化的说法,错误的是?",
"options": {
"A": "RDB 生成的是某时刻内存键值状态的全量快照文件",
"B": "RDB 文件尺寸更小,重启后加载恢复速度远快于重放海量 AOF 命令",
"C": "RDB 采用定时触发,两次快照之间发生的写操作在宕机后会丢失",
"D": "RDB 会记录下每一条写命令,因此始终能恢复到任意一条指令级时刻"
},
"answer": "D",
"explanation": "RDB 是内存状态的定时快照,只保存某个格式点时刻的全量数据,两次快照之间写入的数据在宕机时确实会丢失(C 正确)。其文件小、重载快(B 正确),保存的是状态本身而非命令序列(A 正确)。D 中“记录每一条写命令”是 AOF 的隐式,RDB 并无命令级别的恢复能力,因此 D 是错误说法。",
"source": null,
"related": []
},
{
"id": "sc-003",
"type": "single_choice",
"difficulty": 2,
"tags": [
"Redis",
"AOF",
"AOF重写",
"状态快照",
"命令序列"
],
"question": "AOF 重写(Rewrite / BGREWRITEAOF)的核心本质是什么?",
"options": {
"A": "把追加文件里的命令逐条压缩成更短的命令,仍然是命令序列",
"B": "把命令序列重新生成为键值(状态快照)的等价描述,丢弃大量被最终值覆盖的中间命令,文件因此被“压缩”",
"C": "将 AOF 文件按时间切片,只保留最近一天的写命令",
"D": "把 AOF 与 RDB 混合份成一个文件,以便同时利用两者优势"
},
"answer": "B",
"explanation": "AOF 重写的本质是“状态快照 vs 命令序列”的转换:它扫出当前内存里每个 key 的最终值,只生成恢复这些极简值所需的最小命令集(如直接 SET / RPUSH),把大量被后续命令覆盖的中间命令丢弃,从而大幅缩小文件。它并非简单的压缩/截断/混用 RDB,故 B 正确,A、C、D 均偏离本质。",
"source": null,
"related": []
},
{
"id": "sc-004",
"type": "single_choice",
"difficulty": 2,
"tags": [
"Redis",
"AOF",
"AOF重写"
],
"question": "有一段 AOF 命令流:SET k 1;INCRBY k 5;DEL k;SET k 9。执行 AOF 重写后,恢复同样状态的最小等价命令序列最可能是?",
"options": {
"A": "SET k 1; SET k 6; DEL k; SET k 9",
"B": "SET k 9; INCRBY k 0",
"C": "只保留 SET k 9",
"D": "SETDEL: 只保留 DEL k"
},
"answer": "C",
"explanation": "重写生成的是能重建当前内存状态的命令,mid 命令(SET k a、INCR k 5、DEL k)都被最终结果 k=9 覆盖/湮灭,因此只需保留末尾写 k=9 的 SET 即可。A、B 保留冗余中间命令不符合“最小等价”目标,D 错误因为最终 play 值应为 9 而非删除。",
"source": null,
"related": []
},
{
"id": "sc-005",
"type": "single_choice",
"difficulty": 2,
"tags": [
"AOF",
"binlog",
"追加日志",
"重放",
"复制"
],
"question": "关于 Redis AOF 与 MySQL binlog 的对应关系,下列说法正确的是?",
"options": {
"A": "两者都只记录物理页的最终状态,且都天然支持到任意事务时刻的点恢复",
"B": "两者都属于记录写操作并可重放的逻辑追加日志,但 binlog 支持原生时间/位置切片点,AOF 没有,需要手动截断文件来定点重放",
"C": "AOF 是物理日志而 binlog 是逻辑日志,二者原理完全不同",
"D": "binlog 不具备重放能力,只是改库主从同步的审计文件"
},
"answer": "B",
"explanation": "AOF 与 binlog 都按追加的方式,把写操作记录成可回放的重放日志(statement/row)后者。binlog 提供 --start-position/--stop-position 精确位点与 --start/--stop-datetime 近似时间来点恢复(PITR 核心工具);AOF 没有原生的按时间点切片重放能力,要回到过去某个时刻,通常需要手动根据 appendfile 做截断后再重放。B 正确。C 误把 AOF 当物理日志,D 假言 binlog 不可重放,均错误。",
"source": null,
"related": []
},
{
"id": "sc-006",
"type": "single_choice",
"difficulty": 3,
"tags": [
"AOF",
"redo log",
"binlog",
"物理日志",
"一致"
],
"question": "相比 binlog 的 statement/row 逻辑格式,InnoDB 的 redo log 之所以是物理日志,是因为它记录的是?",
"options": {
"A": "每条 SQL 语句的完整文本,用于主从重放",
"B": "某个事务提交的行级前后镜像(before/after 值),用于回滚",
"C": "已提交事务可能修改过的页面、页号与偏移位置的增量变更,描述“物理页的最终状态变化”",
"D": "对数据库数据的完整状态快照(类 BTCA 快照)"
},
"answer": "C",
"explanation": "redo log 记录的是对数据页物理层面的连续变更:哪个页(页号/偏移)、哪些字节被改成了什么,属于“逻辑日志”的物理状态。它不记录 SQL 文本(那是 binlog statement),不记录行 before/after 镜像(那是 undo log 的回滚图),也不做全量状态快照(RDB 的职责)。崩溃恢复依靠 redo 进行前向重做,C 正确。",
"source": null,
"related": []
},
{
"id": "sc-007",
"type": "single_choice",
"difficulty": 3,
"tags": [
"redo log",
"环形缓冲",
"追加日志"
],
"question": "InnoDB 的 redo log 采用固定大小环形缓冲结构,因此它天然不会无限膨胀,其根本原因是?",
"options": {
"A": "它定期把日志导出到外部保存,磁盘满了就丢弃最旧日志",
"B": "环形固定大小,允许覆盖旧页,旧页写盘后再循环复用,旧记录被隐式覆盖弃——无需显式“压缩/重写”",
"C": "只允许写入固定字节数后强制关闭数据库要求人工清理",
"D": "InnoDB 每一条 redo 记录都写成后来会话内的最终状态,不再产生新日志"
},
"answer": "B",
"explanation": "redo log 被设计成固定大小的循环(circular)缓冲:数据页在检查点后已写入磁盘,其对应日志就允许被覆盖,环形缓冲因此不断循环倒约 map 同一块存储空间,永远只占固定磁盘空间,不需要像 AOF 那样显式重写压缩(BG技术重写)。这就是“隐式覆盖” vs AOF“显式重写合并”的核心差别。B 正确。",
"source": null,
"related": []
},
{
"id": "sc-008",
"type": "single_choice",
"difficulty": 3,
"tags": [
"AOF",
"redo log",
"AOF重写",
"环形缓冲"
],
"question": "关于 AOF 与 InnoDB redo log 在“日志膨胀控制”上的时机差异,正确的是?",
"options": {
"A": "两者都靠固定大小环形缓冲天然防膨胀,无需任何压缩",
"B": "redo 靠固定大小环形覆盖旧页隐式防止膨胀;AOF 是追加式命令日志,会持续放大,需要显式手动/触发 AOF 重写(BGREWRITEAOF)合并压缩",
"C": "AOF 一经开启就自动压缩命令,从不会膨胀;redo 反而会无限增长",
"D": "两者都靠定时全量快照替代全部日志才能防膨胀"
},
"answer": "B",
"explanation": "AOF 追加记录的是命令序列,随写操作无限累积,只有通过显式重写(rewrite)把命令序列重实为等价的状态快照才能缩小文件;而 redo 位于固定大小的环形缓冲内,旧页写入盘后即可被覆盖复用,系统隐式防膨胀。因此“隐式覆盖 vs 显式重写合并”是二者膨胀控制时机的核心差异,B 正确。",
"source": null,
"related": []
},
{
"id": "sc-009",
"type": "single_choice",
"difficulty": 4,
"tags": [
"AOF",
"binlog",
"重放",
"互斥"
],
"question": "要让 MySQL 通过 binlog 精确回放到某个事务提交的物理写入点,首选工具与参数是?",
"options": {
"A": "使用 mysqldump 全备份并重灌,配合 --secondary-drop-root",
"B": "用 mysqlbinlog --start-position/--stop-position 定位 binlog 文件位置精确回放,或用 --start/--stop-datetime 按时间近似回放",
"C": "直接重放 redo log 环形缓冲即可定位到任意事务",
"D": "仅靠 undo log 回滚未提交事务就能精确到物理点"
},
"answer": "B",
"explanation": "binlog 是 MySQL 按位置(pos)与时间组织的事件流,mysqlbinlog 的 --start-position/--stop-position 可精确到事件字节位置,--start/--stop-datetime 提供近似时间点,是点恢复(PITR,Point-In-Time Recovery)核心工具。A 是全备份非精确位点;C 的 redo 是环形覆盖记录,只用于崩溃恢复前向重做,不能指定任意历史点;D 的 undo 只负责回滚未提交事务,B 正确。",
"source": null,
"related": []
},
{
"id": "sc-010",
"type": "single_choice",
"difficulty": 4,
"tags": [
"AOF",
"binlog",
"undo log",
"一致",
"恢复"
],
"question": "MySQL 崩溃恢复时,redo log 与 undo log 的分工关系是?",
"options": {
"A": "只用 undo log 把已提交数据全部回滚到事务前状态",
"B": "redo log 对未写入物理页的已提交事务做前向重做,undo log 回滚尚未提交的事务,二者是物理重做/滚两阶段恢复的前提,配合保证恢复后一致性",
"C": "redo 用于逻辑回滚,undo 用于物理前向重做",
"D": "崩溃恢复完全依赖 AOF 重放命令,redo/undo 只在宕机前起作用"
},
"answer": "B",
"explanation": "崩溃恢复遵循两条线索:对已经 commit 但脏页尚未落盘的事务,用 redo log 前向重做其物理页变更使其最终持久化;对尚未 commit 的事务,用 undo log 回滚已写入页中的部分改动,保证其最终被撤销。因此 redo 重做已提交 + undo 回滚未提交,配合完成恢复后的一致性与持久性,B 正确。",
"source": null,
"related": []
}
]
}