261 lines
16 KiB
JSON
261 lines
16 KiB
JSON
|
|
{
|
|||
|
|
"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": []
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|