首批通过分布式安全可靠测评,为关键业务系统打造
恢复失败报错 -4016, last_restore_log_id 不匹配
更新时间:2026-05-13 01:51
适用版本
OceanBase 数据库 V2.x、V3.x 版本。
问题描述
当备份集群一直有数据更新操作、日志归档持续进行时,使用备份数据恢复租户到新的集群,恢复任务报错 -4016,last_restore_log_id is not match with local, unexpected。
observer.log.20231012185547:426662:[2023-10-12 18:54:54.601095] ERROR [CLOG] process_query_restore_end_id_resp (ob_partition_log_service.cpp:1961) [77034][1456][YB42Axxxxxxx-000607xxxxxxxxxx] [lt=25] [dc=0] last_restore_log_id is not match with local, unexpected(ret=-4016, partition_key={tid:112150xxxxxxxxxx, partition_id:0, part_cnt:0}, local_restore_end_id=113, last_restore_log_id=115, server="192.xxx.x.xxx:2882") BACKTRACE:0xd4f7faa 0x34b5e82 0x8b4cf09 0x8b4d6c8 0x8b4d8f1 0x8bec5b7 0x7fab37f 0x33ad806 0x33ad317 0x33ac9d3 0x33ac6ed 0x323a6fa 0x32380d2 0x3232e2d 0xa70d90b 0x3bc7db8 0xd2abe17 0xd2a9b70 0xd2a792f
问题原因
该问题的触发条件为:
- 备份集群一直有数据更新操作,日志归档持续写入新的日志。
- 恢复的过程中,恢复的分区发生了切主(通常是恢复集群压力过大,leader 和 follower 之间的心跳机制失效导致)。
因为备份集群一直新的日志归档,恢复的分区在 Leader 切换后,新旧 Leader 在拉取恢复日志时判断的日志终点位置(last_restore_log_id)不同,导致该错误。这是一个 by design 的问题,其根本原因如下文所述。
当前物理备份恢复功能实现中,为了优化大量分区场景下归档日志过多的问题,冷分区不再定期写 checkpoint 日志,而是在租户级统计一个当前可恢复的位点。这个优化会对恢复流程如何确认恢复日志终点(last_restore_log_id)造成影响。
考虑如下时序的场景:
- 分区 P1 是一个冷分区,在可恢复位点为 T1 时,它已经归档出去的最大 log_id 是 10。
- 恢复 P1 时有 A、B、C 三个副本,第一任
restore_leader是 A,restore_engine为它从归档存储中拉取日志,拉到 10 号日志发现后面没有了,故认为已拉完。此时 A 将本地的last_restore_log_id设为 10(持久化到pg_meta中),并进入转储阶段完成转储(此时 B、C 还未开始恢复)。 - 归档存储中又写入了 10 条日志,最大的
log_id变为 20。 - A 发生宕机重启,B 当选为新的
restore_leader,从头开始恢复流程,restore_engine再次为它拉日志,假设 11~20 号日志全部是事务日志,且其中没有 checkpoint 信息,那么 B 会拉到 20 号日志结束,并将本地的last_restore_log_id设为 20;C 最终从 B 上拷数据恢复完成。 - A 启动后会推进恢复状态结束,并从 B 拉到 11~20 号日志,本地的回放事务过滤逻辑会根据
last_restore_log_id做过滤,由于本地的last_restore_log_id是 10,导致 11~20 号日志无法被过滤。 - 结果就是 A 与 B/C 的数据不一致。
这个问题的直接原因是对于同一个恢复位点(restore_snapshot_version),归档存储无法保证每次返回的日志位点是一样的,根本原因是分区的日志流中没有快照的明确边界。
解决方法
采用单副本恢复,恢复完成后再通过 Locality 变更的方式扩展为多副本。