容灾切换后gridfs下载失败,八成是fs.chunks缺files_id索引或fs.files元数据未完整同步;需立即检查并创建索引、验证_id类型及驱动兼容性。

容灾切换后 GridFS 下载失败,八成是 fs.chunks 集合在新集群里没索引,或者元数据查询路径没对齐——不是连接问题,而是索引和元数据状态不一致。
查 fs.chunks 是否有 files_id 索引
容灾切换常走 mongodump/mongorestore 或物理复制,这些方式不会自动重建驱动级默认索引。而 openDownloadStream() 依赖 fs.chunks.files_id 索引做 chunk 拼接,缺它就会全表扫描,超时或返回空流。
- 连上新集群,执行
db.fs.chunks.getIndexes(),确认输出含{ "files_id": 1 } - 若缺失,立刻运行
db.fs.chunks.createIndex({ "files_id": 1 });别等“下次上传触发”,容灾后首次下载就可能卡死 - 顺手检查
fs.files是否有{ "filename": 1, "_id": 1 }(分页用)和{ "metadata.fileId": 1 }(业务去重用),否则后续查询也慢
确认 files 集合文档是否完整同步
GridFS 下载流程是:先查 fs.files 得元数据 → 再按 _id 查 fs.chunks 拼内容。如果容灾时只同步了 fs.chunks、漏了 fs.files,或 fs.files 里 _id 字段类型被转换(比如 ObjectId 变成字符串),openDownloadStream() 就会静默失败或报 No such file。
- 挑一个已知存在的文件 ID,手动查
db.fs.files.findOne({ _id: ObjectId("...") }),确认文档存在且_id类型为 ObjectId - 对比新旧集群的
fs.files.count()和fs.chunks.count(),比例应接近(chunk 数 ≈ 文件大小 ÷ 255KB);若 chunks 多但 files 少,说明 chunks 孤立了 - 特别注意:mongorestore 默认不恢复索引,必须加
--restoreDbUsersAndRoles参数才带索引;没加就等于裸数据上线
检查驱动是否还在用已废弃的 GridFS 类
老系统容灾后常忽略驱动版本兼容性。Java 项目若仍用 com.mongodb.gridfs.GridFS,Node.js 若调 new mongodb.GridFS(db),这些类在 v4+ 驱动中已移除或行为异常——它们不支持新集群的连接池配置、SSL 设置,且 chunk 查询逻辑不兼容副本集角色切换。
- Java:搜代码里有没有
GridFSDBFile或GridFSInputFile,有就得迁到GridFSBucket - Node.js:确认初始化用的是
new mongodb.GridFSBucket(db),而不是new mongodb.GridFS(db)(后者在 v4.0+ 报错) - 容灾后若改过 MongoDB 连接串(如加了
?replicaSet=rs0),老 GridFS 类可能连不上 secondary,但错误日志只显示 “connection refused”,不提 GridFS 版本问题
验证下载流是否被中间件截断或缓存
容灾常伴随反向代理、CDN 或网关配置变更。NGINX 或 Kong 可能因超时设置太短(如 proxy_read_timeout 60)、缓冲区限制(proxy_buffering on)或 Content-Type 过滤规则,把 GridFS 的 chunk 流截断成 200 OK + 空 body。
- 绕过所有中间层,用
curl -v "http://target:27017/download/xxx"直连应用服务,看响应头和 body 是否正常 - 检查应用层是否还硬编码了旧集群的 DB 名(如
db = client.db("old_gridfs_db")),容灾后 DB 名变了但代码没更新 - 若用了 GraphQL 封装下载,注意 resolver 不能直接 return 流——容灾后若忘了把下载逻辑从 resolver 搬到独立路由,就会一直返回空对象
真正麻烦的不是找不到文件,而是索引缺失或元数据类型错位这种“看起来连上了,实际查不到”的问题;排查时优先盯住 fs.chunks 索引和 fs.files._id 字段类型,这两处错一个,下载就不可用。











