如何彻底突破 Anki 同步大小限制:解决 collection exceeds size limit 报错的完整指南
【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki
Anki 是一款智能间隔重复闪卡软件,它的跨设备同步让学习数据在电脑、手机间自由流动。但当你的卡片堆上媒体文件越滚越大,同步进度条就会卡死在一句冰冷的报错上——"collection exceeds size limit"(集合超出大小限制)。这篇文章带你从一句报错出发,摸清 Anki 同步服务里的三道大小闸门,再用三档方案(精简集合 → 自托管调参 → 源码级改造)把它彻底拆掉。
卡在同步进度条的那一刻:先分清错误来自哪一边
想象这个场景:深夜复习完,你点下同步,进度条爬了几秒后弹出错误,客户端显示的可能是152.36 MB > 300.00 MB,也可能是服务器直接回一句collection exceeds size limit。两种文案对应两套完全不同的检查逻辑,搞清楚这一点,后面的路就清晰了一大半。
Anki 的同步链路里,大小限制一共由三道闸门把关,全部写在 Rust 核心库中:
闸门一:服务器端 100MB 压缩上限。同步服务器启动时会读取环境变量MAX_SYNC_PAYLOAD_MEGS,不设则按 100MB 处理,这个值同时被塞进 HTTP 层的请求体限制里:
// rslib/src/sync/request/mod.rs pub static MAXIMUM_SYNC_PAYLOAD_BYTES: LazyLock<usize> = LazyLock::new(|| { env::var("MAX_SYNC_PAYLOAD_MEGS") .map(|v| v.parse().expect("invalid upload limit")) .unwrap_or(100) // 默认 100MB 上限 * 1024 * 1024 });闸门二:解压后 3 倍上限。服务器还盯着解压后的原始集合大小,它取压缩上限的 3 倍(即默认约 300MB)。你平时看到的 "collection exceeds size limit" 就是这里抛出的:
// rslib/src/sync/collection/upload.rs let max_bytes = *MAXIMUM_SYNC_PAYLOAD_BYTES_UNCOMPRESSED as usize; if new_data.len() >= max_bytes { return Ok(UploadResponse::Err("collection exceeds size limit".into())); }闸门三:客户端的提前自检。客户端在上传前会先量一次自己,但注意它只对官方 AnkiWeb 端点生效——一旦你配置了自定义同步服务器,这一关会被跳过:
// rslib/src/sync/collection/upload.rs if server.endpoint.as_str().contains("ankiweb") { check_upload_limit( total_bytes, *MAXIMUM_SYNC_PAYLOAD_BYTES_UNCOMPRESSED as usize, )?; }也就是说:官方服务器上三道闸门都卡着你;自托管服务器上只剩前两道,而它们都由同一个环境变量控制。这就是后文所有解法的理论支点。
顺带一提,Anki 在每次上传前会做一次自动瘦身(rslib/src/collection/mod.rs 中的before_upload会清空墓碑记录、待处理 USN 并优化数据库),但它只是"扫地",改变不了媒体文件本身占的空间——所以瘦身不能替代清理。
第一档:先给集合减重,零门槛操作
改任何配置之前,先确认你的集合里到底装了多少"死重"。这一步不需要懂技术,10 分钟能做完。
- 跑一次媒体检查:工具 → 检查媒体,删掉未被引用的图片、音频。长期积累的卡片库往往有几十 MB 是"孤儿文件"。
- 压缩大体积媒体:对特别大的图片用外部工具压到合理尺寸(卡片渲染用不到 4K),音频转成 mp3/m4a。
- 拆分牌组:把学完的、低频的牌组导出存档,日常只同步活跃集合。
⚠️导出前务必确认导出内容包含媒体文件,否则换设备后图片会丢。
减重后若仍超限,进入第二档。
第二档:自托管同步服务器 + 一个环境变量,把限制调到 500MB
Anki 自带的同步服务器代码就在仓库里,官方提供了完整的 Docker 部署方案(docs/syncserver/README.md)。因为客户端对自定义服务器不做大文件自检,你只要把服务器端的MAX_SYNC_PAYLOAD_MEGS调大,整条链路就通了。
第一步,构建镜像(在docs/syncserver目录下执行):
# 指定 Anki 版本构建,Dockerfile 会自动编译 sync-server 二进制 docker buildx build -f Dockerfile --no-cache \ --build-arg ANKI_VERSION=24.11 -t anki-sync-server .第二步,运行容器时用环境变量抬高上限:
docker run -d \ -e "SYNC_USER1=admin:admin" \ # 同步账号:密码,可加 SYNC_USER2 等多用户 -e "MAX_SYNC_PAYLOAD_MEGS=500" \ # 压缩上限提至 500MB(解压上限同步放大) -p 8080:8080 \ --mount type=volume,src=anki-sync-server-data,dst=/anki_data \ --name anki-sync-server \ anki-sync-server几个容易踩的坑:
- 如果你在 caddy/nginx 后面套了反向代理,代理层的
client_max_body_size/ 读取缓冲也要同步放宽,否则请求会在代理处先被截断,官方手册 docs-site/manual/sync-server.mdx 有对应说明。 SYNC_BASE与SYNC_PORT环境变量在 Docker 方案中会被忽略,改映射端口请用-p。- 客户端里进入 工具 → 首选项 → 网络,把同步服务器地址指向你的自托管端点即可。
第三档:源码级改造,给 Rust 开发者
如果你编译能力在线、且想彻底掌控限制行为(比如做成按账户动态配额),改动点非常集中:
- 上限定义:rslib/src/sync/request/mod.rs,两处
LazyLock静态量; - 服务器校验:rslib/src/sync/collection/upload.rs 的
handle_received_upload; - 客户端自检:同文件的
check_upload_limit,以及上传入口full_upload_with_server。
建议的改法不是删掉检查,而是把unwrap_or(100)换成你想要的默认值,或让校验读取数据库里的每账户配额,然后自行编译anki-sync-server部署。注意仓库本身是只读的,这类改动应在你自己的 fork 或检出副本上进行,编译、回归测试都完成后才替换线上二进制。
⚠️改大上限不等于无脑堆媒体:集合越大,每次全量上传的内存与带宽开销越高,服务器也要预留相应磁盘与内存余量。
动手验证:五步走通同步闭环
- 备份数据(改任何配置前的硬规则):
# 备份整个 Anki 数据目录(Linux 示例) cp -r ~/.local/share/Anki2/ ~/.local/share/Anki2_backup_$(date +%Y%m%d)- 按第二档命令构建并启动容器,
docker logs -f anki-sync-server确认启动无报错。 - 客户端指向自托管服务器,用小集合先试同步。
- 逐步把大集合同步上来,观察客户端不再报 "collection exceeds size limit"、日志中出现上传成功记录。
- 多设备交叉验证:A 设备新增卡片 → 同步 → B 设备拉取,确认数据一致、媒体完整。
一图决策:三档方案怎么选
| 方案 | 适合人群 | 技术难度 | 预期效果 |
|---|---|---|---|
| 集合减重(媒体清理/拆分) | 所有用户 | 低 | 体积降 10%~40%,可能直接过关 |
自托管 +MAX_SYNC_PAYLOAD_MEGS | 有服务器的用户 | 中 | 上限提升 5 倍以上,一劳永逸 |
| 源码级改造 | Rust 开发者 | 高 | 完全自定义限制逻辑 |
推荐路径是先减重、再自托管:减重能同时降低同步延迟,而自托管 + 环境变量调整基本能覆盖 99% 的超限场景;源码改造留给有特殊配额需求的场景。
从社区动向看,同步协议正在向更细粒度的增量传输演进,媒体与结构化数据分离存储也是讨论中的方向——集合越大,这类优化对你的意义越大。如果你排查过程中发现了新的边界问题,把报错原文、集合大小、服务器类型整理好抛给上游仓库,就是对项目最实际的贡献。现在,去把那个卡住的同步进度条跑完吧。
【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考