MongoDB存储跨境海量产品数据库
场景与准备
假设你正在维护一个跨境电商平台,每天新增数十万条产品数据(含多语言标题、价格、库存、图片链接等),传统关系型数据库已无法支撑写入和查询速度。
MongoDB 天然支持文档存储和水平扩展,非常适合这种场景。
你需要准备:
- 至少 3 台 Linux 服务器(建议 CentOS 7.9 或 Ubuntu 20.04),2 核 4G 以上。
- MongoDB 7.0 社区版(从官方 repo 安装,不要直接 apt 默认版本)。
- 所有服务器之间内网互通,防火墙放行 27017、27018、27019 等端口。
部署分片集群
MongoDB 分片集群由三个组件组成:配置服务器(Config Server)、分片节点(Shard)、路由节点(mongos)。
1. 安装 MongoDB
每台服务器依次执行:
# 导入 GPG key 并添加 repo(以 Ubuntu 为例)
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update
sudo apt install -y mongodb-org
2. 配置 Config Server
选一台服务器(例如 10.0.0.1)作为配置服务器副本集。
编辑 /etc/mongod.conf:
# 仅保留关键配置
net:
port: 27019
bindIp: 0.0.0.0
sharding:
clusterRole: configsvr
replication:
replSetName: cfgrs
启动服务并初始化副本集:
sudo systemctl restart mongod
mongosh --port 27019 --eval 'rs.initiate({_id:"cfgrs", members:[{_id:0,host:"10.0.0.1:27019"}]})'
3. 配置 Shard(分片)
每台作为分片的服务器(至少 2 台),同样修改 /etc/mongod.conf:
net:
port: 27018
bindIp: 0.0.0.0
sharding:
clusterRole: shardsvr
replication:
replSetName: shard1 # 第一组分片副本集名
同一分片内的服务器都用相同 replSetName,完成后启动并初始化副本集(类似 config server 步骤)。
4. 启动 mongos
在任一台服务器(也可独立一台)上启动 mongos,配置指向 config server:
mongos --configdb cfgrs/10.0.0.1:27019 --port 27017 --bind_ip 0.0.0.0 &
连接 mongos:
mongosh --port 27017
在 mongos 中添加分片:
sh.addShard("shard1/10.0.0.2:27018,10.0.0.3:27018")
设计数据模型并设置分片键
跨境产品文档示例:
{
"sku": "US-123456",
"title": {
"en": "Wireless Mouse",
"es": "Ratón inalámbrico"
},
"price": 19.99,
"currency": "USD",
"stock": 500,
"category": "electronics",
"created_at": ISODate("2025-03-01T12:00:00Z")
}
分片键选择建议: 使用 { category: 1, created_at: 1 } 的复合分片键,既能保证数据均匀分布,又能按分类和日期高效查询。
sh.shardCollection("products.items", {category: 1, created_at: 1})
索引优化
为常用查询建立索引:
db.items.createIndex({ sku: 1 }, { unique: true }) // 精准查找
db.items.createIndex({ "title.en": "text", "title.es": "text" }) // 全文搜索
db.items.createIndex({ price: 1, currency: 1 }) // 价格区间查询
避坑指南
- 分片键不可更改,上线前一定要根据查询模式仔细选择。如果怕选错,先做小规模压测。
- 不要将 _id 作为分片键,否则容易导致热点。
- 分片集群不建议用默认的哈希分片,除非你的查询全是等值查询。
- 每个分片内的副本集至少有 3 个节点(一主两从),否则容灾能力弱。
- 定期检查分片均衡状态:
sh.status(),如果 chunk 分布不均,手动调用sh.startBalancer()。
效果验证
插入 100 万条测试数据并验证性能:
for (let i = 0; i < 1000000; i++) {
db.items.insertOne({
sku: "SKU-" + i,
title: { en: "Product " + i, es: "Producto " + i },
price: Math.random() * 100,
currency: "USD",
category: i % 3 === 0 ? "electronics" : i % 3 === 1 ? "clothing" : "home",
created_at: new Date()
})
}
查询最近 7 天电子类产品:
db.items.find({ category: "electronics", created_at: { $gte: new Date(Date.now() - 7*24*60*60*1000) } }).explain("executionStats")
观察 totalDocsExamined 是否接近返回条数,且查询仅在单个分片上完成(stage: SHARDING_FILTER)说明分片键设计合理。
常见问题解答
Q:分片集群中某个 shard 磁盘满了怎么办?
A:可以手动将部分 chunk 迁移到其他 shard:sh.moveChunk("products.items", { category: "home" }, "shard2"),或者增加一台新 shard 并开启 balancer。
Q:mongos 宕机会影响数据吗?
A:不会,数据在配置服务器和分片中,重启 mongos 即可恢复服务。
Q:跨境产品中多语言字段如何查询?
A:创建文本索引后使用 $text 操作符,同时可以结合 $language 选项指定语言权重。
如果你正在处理 MongoDB 存储跨境海量产品数据库,建议先按本文步骤完整部署,再根据实际业务调整分片键和索引。
遇到异常时优先检查配置文件和网络连通性。