事情本身不复杂,线索都在日志里。按 offset 分页拉数据,每页一百条,失败后从最后一页的 offset 继续,最终少处理 137 条,日志显示失败那一页被直接跳过。
第一反应是「拉取期间有新数据写入 顺序被打乱」,验证下来不成立。
原因不止一个,得分开看。offset 前进了但该页并未成功。少数情况下是用页号而不是已成功条数做游标。
另外,结束时没有校验总数。
游标改成已成功条数
python -c "import sqlite3;print(sqlite3.connect('j.db').execute('select count(*) from done').fetchone())"
失败页不推进游标
python pull.py --cursor done --on-fail hold
接着用主键范围替代 offset
python -c "print('SELECT * FROM src WHERE id > 10240 ORDER BY id LIMIT 100;')"
结束时比对处理总数与源表
python check_total.py --src src.db --dst j.db
排查用的命令都是临时敲的,没有写成脚本,事后才整理。
手上没有现成的复现脚本,就照着线上请求手工拼了一个。
恢复的判定其实很直接。处理总数与源表完全一致,差值为零,失败页被重试后计入。
容易忽略的是,有写入的表上 offset 分页不可靠,主键游标更稳。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
