GridFS在MongoDB 6.0+分片集群中必须提前用{"_id": "hashed"}分片fs.files,fs.chunks不可单独分片且会自动按files_id路由;分片须在写入前完成,否则失败;非_id查询需建二级索引优化性能。

GridFS 在 MongoDB 6.0+ 分片集群中不能“自动分片”,fs.files 和 fs.chunks 必须手动、提前、且严格按规则分片;否则写入后无法补救,查询会跨分片广播,性能崩塌。
必须用 {"_id": "hashed"} 对 fs.files 分片,fs.chunks 不允许单独分片
MongoDB 6.0 起彻底禁止对 fs.chunks 使用 {files_id: "hashed"} 或任何非 _id 字段的分片键。执行 sh.shardCollection("mydb.fs.chunks", {"files_id": "hashed"}) 会直接报错:cannot shard collection with non-_id shard key on a GridFS namespace。
-
fs.files是唯一可显式分片的 GridFS 集合,命令必须是:sh.shardCollection("mydb.fs.files", {"_id": "hashed"}) - 该操作完成后,
fs.chunks会自动按files_id值路由到与对应fs.files._id相同的分片——这是 MongoDB 内部硬编码行为,无需、也不允许干预 - 如果你看到旧文档建议对
chunks单独分片,那仅适用于 ≤3.2 版本,当前已失效
分片必须在写入任何文件前完成,已有数据无法原地分片
一旦 fs.files 或 fs.chunks 中存在文档,sh.shardCollection() 就会失败,典型错误:Cannot shard collection with existing data unless it has a shard key index。
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
- 确认集合为空:
db.fs.files.countDocuments({})和db.fs.chunks.countDocuments({})都必须返回0 - 如果已有文件,必须先导出(
mongodump -d mydb -c fs.files+-c fs.chunks),清空集合(db.fs.files.deleteMany({})),再分片,最后重新导入 - 不要依赖“先写再分片”的侥幸心理——MongoDB 不支持后期修改 GridFS 集合的分片键
按 filename 查询慢?不是分片问题,是缺索引
因为分片键锁死为 _id,所有非 _id 查询(如 filename、uploadDate、metadata.user_id)都会触发广播查询(scatter-gather),耗时随分片数线性增长。
- 解决方式不是换分片键(做不到),而是建二级索引:
db.fs.files.createIndex({"filename": 1, "uploadDate": -1}) - 避免对低基数字段建单字段索引,例如
{"metadata.status": 1}(若 status 只有 "pending"/"done" 两种值),会导致严重倾斜 - 高频查询字段必须显式建索引,驱动不会自动创建;索引需在每个分片上生效,mongos 会自动下发
驱动层写入时,_id 必须存在且类型正确
分片依赖 fs.files._id 的哈希值路由,若驱动未显式指定或传入空/非法值,sh.shardCollection 会报错:shard key not found in document。
- 使用官方驱动(如 Java Spring Data、Python PyMongo)时,默认生成
ObjectId,通常没问题 - 若业务自定义
_id(如时间戳字符串、UUID 字符串),必须确保其具备足够散列度;否则所有文件会集中写入少数分片,造成热点 - 检查写入后的
fs.files文档,确认_id字段存在、非 null、且类型为ObjectId或其他合法 BSON 类型
真正容易被忽略的是:分片生效后,fs.chunks 的物理分布完全由 fs.files._id 决定,你无法通过任何配置让一个文件的块分散到多个分片——这既是保证读取一致性的前提,也是限制横向扩展粒度的硬约束。

















