MongoDB vs Redis vs Elasticsearch:2026 年 NoSQL 数据库选型指南
90% 的 NoSQL 选型纠结,本质上是没搞清楚「你要解决什么问题」。这篇文章用 5 个真实场景 + 对比表格 + 完整代码,帮你一次性搞懂 MongoDB、Redis、Elasticsearch 到底该选谁。
一张图搞懂三者的定位
| 对比维度 | MongoDB | Redis | Elasticsearch |
|---|---|---|---|
| ——— | ——— | ——- | ————– |
| 数据模型 | 文档(BSON/JSON) | 键值对 + 数据结构 | 文档(JSON) |
| 核心能力 | 灵活存储、事务支持 | 极速读写、数据结构丰富 | 全文检索、聚合分析 |
| 持久化 | 磁盘优先,WiredTiger | 内存优先,RDB/AOF 可选 | 磁盘(Lucene 倒排索引) |
| 查询语言 | MQL(类 SQL) | 命令式 API | DSL(JSON 格式) |
| 事务支持 | 4.0+ 支持多文档事务 | Lua 脚本保证原子性 | 不支持跨文档事务 |
| 典型 QPS | 万级 | 十万级 | 千级(复杂查询) |
| 适用场景 | 通用数据存储 | 缓存/实时排行榜/会话 | 搜索/日志/数据分析 |
一句话总结:
场景 1:用户画像存储 → 选 MongoDB
需求:存储用户资料,字段经常变(今天加个「兴趣爱好」,明天加个「社交账号」),还要按条件查询。
# pip install pymongo
from pymongo import MongoClient, ASCENDING, DESCENDING
client = MongoClient("mongodb://localhost:27017")
db = client["user_profile"]
users = db["users"]
# 插入 — 字段完全自由,不需要提前建表
users.insert_many([
{
"name": "张三",
"age": 28,
"tags": ["Python", "云原生"],
"address": {"city": "郑州", "district": "金水区"},
},
{
"name": "李四",
"age": 35,
"tags": ["Go", "K8s"],
"company": "某大厂", # 李四多了个字段,完全没问题
"address": {"city": "北京", "district": "海淀区"},
},
])
# 灵活查询 — 按城市 + 年龄范围
results = users.find({
"address.city": "郑州",
"age": {"$gte": 25, "$lte": 30},
}).sort("age", ASCENDING)
for r in results:
print(r)
# 建索引加速
users.create_index([("address.city", ASCENDING), ("age", ASCENDING)])
# 更新 — 给所有郑州用户加个标签
users.update_many(
{"address.city": "郑州"},
{"$addToSet": {"tags": "河南老乡"}},
)
为什么不用 Redis? Redis 存复杂嵌套结构要手动序列化,查询能力弱。
为什么不用 ES? ES 更适合搜索,不是通用存储引擎,写放大问题明显。
场景 2:实时排行榜 + 限流 → 选 Redis
需求:游戏排行榜 Top 100,API 限流每用户 100 次/分钟。
# pip install redis
import redis
import time
import json
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
# ===== 排行榜:用 Sorted Set =====
leaderboard_key = "game:ranking:season1"
# 批量添加分数
r.zadd(leaderboard_key, {
"player_001": 9800,
"player_002": 12500,
"player_003": 11000,
"player_004": 8900,
"player_005": 15000,
})
# 增加某玩家分数
r.zincrby(leaderboard_key, 300, "player_001")
# 获取 Top 3(分数从高到低)
top3 = r.zrevrange(leaderboard_key, 0, 2, withscores=True)
print("🏆 Top 3:")
for name, score in top3:
print(f" {name}: {int(score)} 分")
# 查某玩家排名
rank = r.zrevrank(leaderboard_key, "player_001")
print(f"player_001 排名: 第 {rank + 1} 名")
# ===== API 限流:用 String + TTL =====
def check_rate_limit(user_id: str, max_requests: int = 100, window: int = 60) -> bool:
"""滑动窗口限流:每用户每分钟最多 max_requests 次请求"""
key = f"rate_limit:{user_id}"
current = r.get(key)
if current is None:
r.setex(key, window, 1)
return True
if int(current) >= max_requests:
return False
r.incr(key)
return True
# 测试限流
for i in range(105):
allowed = check_rate_limit("user_123", max_requests=100)
if not allowed:
print(f"🚫 第 {i+1} 次请求被限流")
break
为什么不用 MongoDB? 排行榜需要实时排序,MongoDB 排序要走磁盘,性能差几个数量级。
为什么不用 ES? 限流需要毫秒级读写,ES 的写入延迟不适合。
场景 3:商品搜索 + 聚合分析 → 选 Elasticsearch
需求:电商商品搜索,支持中文分词、多条件筛选、价格聚合。
# pip install elasticsearch
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
es = Elasticsearch("http://localhost:9200")
# 创建索引,配置中文分词器
index_name = "products"
if es.indices.exists(index=index_name):
es.indices.delete(index=index_name)
es.indices.create(index=index_name, body={
"settings": {
"analysis": {
"analyzer": {
"ik_smart_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word" # 需要安装 ik 分词插件
}
}
}
},
"mappings": {
"properties": {
"name": {"type": "text", "analyzer": "ik_smart_analyzer"},
"category": {"type": "keyword"},
"price": {"type": "float"},
"brand": {"type": "keyword"},
"tags": {"type": "keyword"},
}
}
})
# 批量写入商品
products = [
{"name": "腾讯云轻量应用服务器 2核4G", "category": "云服务器", "price": 68.0, "brand": "腾讯云", "tags": ["入门", "高性价比"]},
{"name": "阿里云 ECS 通用型 4核8G", "category": "云服务器", "price": 156.0, "brand": "阿里云", "tags": ["企业级", "稳定"]},
{"name": "华为云耀云服务器 2核2G", "category": "云服务器", "price": 49.0, "brand": "华为云", "tags": ["入门", "低价"]},
{"name": "大模型 API 调用包 100万 Token", "category": "AI 服务", "price": 29.9, "brand": "混元", "tags": ["AI", "大模型"]},
]
actions = [
{"_index": index_name, "_source": p}
for p in products
]
bulk(es, actions)
# 搜索:云服务器 + 价格 < 100
result = es.search(index=index_name, body={
"query": {
"bool": {
"must": [
{"match": {"name": "云服务器"}},
],
"filter": [
{"range": {"price": {"lte": 100}}}
]
}
},
"aggs": {
"brand_stats": {
"terms": {"field": "brand", "size": 10}
},
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{"key": "0-50", "to": 50},
{"key": "50-100", "from": 50, "to": 100},
{"key": "100+", "from": 100},
]
}
}
}
})
print("搜索结果:")
for hit in result["hits"]["hits"]:
src = hit["_source"]
print(f" {src['name']} - ¥{src['price']} ({src['brand']})")
print("\n品牌分布:")
for bucket in result["aggregations"]["brand_stats"]["buckets"]:
print(f" {bucket['key']}: {bucket['doc_count']} 个商品")
为什么不用 MongoDB? MongoDB 的文本搜索能力有限,中文分词支持差,聚合分析不如 ES 灵活。
为什么不用 Redis? Redis 的搜索模块(RediSearch)功能远不如 ES,生态差距大。
场景 4:混合架构 — 三者搭配才是王道
真实项目往往是三者搭配使用:
| 层次 | 技术 | 职责 |
|---|---|---|
| —— | —— | —— |
| 缓存层 | Redis | 热点数据缓存、会话管理、限流 |
| 存储层 | MongoDB | 核心业务数据持久化 |
| 搜索层 | Elasticsearch | 全文检索、日志分析、数据看板 |
数据流转示意:
用户请求 → Redis 缓存命中?
├── 是 → 直接返回(< 1ms)
└── 否 → MongoDB 查询 → 写入 Redis 缓存 → 返回
↓
异步同步到 ES(用于搜索)
# 混合架构示例:商品详情查询
import json
def get_product(product_id: str) -> dict:
"""三级查询:Redis → MongoDB → 返回并缓存"""
# 第 1 级:查 Redis 缓存
cache_key = f"product:{product_id}"
cached = r.get(cache_key)
if cached:
print("✅ Redis 缓存命中")
return json.loads(cached)
# 第 2 级:查 MongoDB
product = db["products"].find_one({"_id": product_id})
if not product:
return None
product["_id"] = str(product["_id"])
# 写入 Redis,TTL 5 分钟
r.setex(cache_key, 300, json.dumps(product, ensure_ascii=False))
print("📦 MongoDB 查询完成,已写入缓存")
return product
场景 5:云上部署成本对比
以腾讯云为例,同等 4C8G 配置的月费:
| 服务 | 腾讯云产品 | 月费(按量/包年包月) |
|---|---|---|
| —— | ———– | ——————— |
| MongoDB | 云数据库 MongoDB | ¥320 起 |
| Redis | 云数据库 Redis | ¥280 起 |
| Elasticsearch | 云搜索服务 ES | ¥450 起 |
| 自建(CVM 4C8G) | 云服务器 CVM | ¥180 起 |
自建 vs 托管怎么选?
| 对比项 | 自建 | 托管(云数据库) |
|---|---|---|
| ——– | —— | —————– |
| 运维成本 | 高(备份、监控、升级全自己来) | 低(一键高可用、自动备份) |
| 初始费用 | 低(只付 CVM 钱) | 高(溢价 50%-100%) |
| 可靠性 | 取决于运维水平 | SLA 99.95%+ |
| 适合 | 有运维能力的创业团队 | 追求稳定的企业 |
我的建议:初期用自建快速验证,业务跑起来后迁移到托管,别让运维拖了业务后腿。
选型决策速查表
| 你的需求 | 选谁 |
|---|---|
| ——— | —— |
| 通用数据存储,字段经常变 | MongoDB |
| 缓存、会话、排行榜、限流 | Redis |
| 全文搜索、日志分析、数据看板 | Elasticsearch |
| 存 JSON,偶尔按字段查 | MongoDB |
| 延迟要求 < 1ms | Redis |
| 中文搜索 + 聚合统计 | Elasticsearch |
| 需要事务 | MongoDB 4.0+ |
| 时序数据 + 实时计算 | Redis(TimeSeries 模块) |
小结
NoSQL 选型的核心逻辑就三句话:
1. MongoDB — 数据结构复杂、查询灵活,选它不会错
2. Redis — 追求极致性能、做缓存和实时计算,非它莫属
3. Elasticsearch — 搜索和分析是刚需,别犹豫
真正的难题从来不是「选哪个」,而是「你到底要解决什么问题」。搞清楚需求,选型自然就清晰了。
👤 作者简介
一枚在大中原腹地(河南)卖公有云的从业者,主营腾讯云/阿里云/火山云,曾踩坑无数,现专注AI大模型应用落地。关注公众号「公有云cloud」,围观AI前沿动态~
博客:yunduancloud.icu
