数据库MySQLPostgreSQLMongoDBRedisElasticsearchRocketMQ向量数据库架构

数据库与周边基础设施完全指南:关系型、NoSQL、向量库、Redis、Elasticsearch 与 RocketMQ

2026-06-275 Min Read

数据库与周边基础设施完全指南:关系型、NoSQL、向量库、Redis、Elasticsearch 与 RocketMQ

做系统做到一定阶段,团队几乎都会遇到同一类问题:

  • 核心业务数据到底该放 MySQL 还是 PostgreSQL?
  • MongoDB 到底适合做什么,不适合做什么?
  • Redis 真的只是缓存吗?
  • Elasticsearch 到底是数据库、搜索引擎,还是另一个“大号索引”?
  • 向量数据库是不是 AI 时代的新主库?
  • RocketMQ 是不是“能存消息,所以也算数据库”?

这些问题之所以反复出现,不是因为概念本身复杂,而是因为很多文章只讲“定义”,不讲边界,不讲取舍,也不讲系统组合方式。

这篇文章不打算列百科词条,而是按真实工程视角把这几个基础设施讲清楚:

  • 它们各自解决什么问题
  • 它们的数据模型是什么
  • 它们的优势和短板在哪里
  • 它们在一个系统里应该如何分工
  • 哪些选型是合理演进,哪些是典型过度设计

如果你是后端工程师、架构师,或者正在搭系统,这篇文章应该能直接帮你建立一套足够稳的判断框架。


先立边界:数据库、缓存、搜索引擎、消息队列不是一回事

这是最值得先讲清的一段。很多架构混乱,不是因为技术不会用,而是因为边界一开始就没划清。

四者的职责边界

类别 核心职责 典型产品 最擅长 不该承担的角色
数据库 持久化业务真相源 MySQL、PostgreSQL、MongoDB 存储、查询、约束、事务 异步事件总线、全文搜索引擎
缓存 加速热点访问、保存短期状态 Redis 低延迟读写、计数、状态、过期 业务长期真相源
搜索引擎 高效做全文检索和复杂搜索 Elasticsearch 倒排索引、全文检索、复杂搜索条件 事务主库
消息队列 传递事件、解耦系统、削峰异步 RocketMQ 异步处理、重试、广播、顺序消费 业务查询存储

一句话概括:

  • 数据库负责“数据最终是什么”。
  • 缓存负责“数据怎样更快拿到”。
  • 搜索引擎负责“数据怎样更容易被搜到”。
  • 消息队列负责“事情发生后谁来异步处理”。

这四类基础设施可以互相配合,但不能互相替代。

一个典型误用例子

以“支付成功后发券”为例:

  • 订单状态应该写数据库
  • 订单热点信息可以放 Redis
  • 用户搜索订单内容可以走 Elasticsearch
  • “支付成功”这个事件可以发到 RocketMQ

如果把这些职责搅在一起,就会出现:

  • 用 Redis 保存订单最终状态,结果状态不可追溯
  • 用 MQ 当业务日志查询源,排查困难
  • 用 Elasticsearch 当交易主库,结果一致性出问题
  • 用数据库轮询代替事件流,最终主链路越来越慢

边界先清楚,架构才不会越做越乱。


一张总览表先建立认知

技术类别 核心问题 数据模型 擅长什么 不擅长什么
关系型数据库 核心业务数据正确存储 表、行、列、关系 事务、约束、JOIN、报表 语义检索、高吞吐事件分发
文档数据库 半结构化对象存储 JSON/BSON 文档 灵活模型、整体读写 复杂关系与强约束
Key-Value 数据库 极快映射访问 key -> value 缓存、状态、计数 多条件复杂查询
列族数据库 海量宽表与分布式写入 RowKey + 列族 大规模写入、时序、埋点 复杂 OLTP
图数据库 关系路径分析 点、边、属性 图谱、路径、关联分析 通用业务主库
向量数据库 相似度检索 向量 + 元数据 RAG、语义搜索、召回 强事务与精确查询
Redis 高性能内存数据结构服务 String/Hash/List/Set/ZSet 等 缓存、会话、限流、实时状态 主交易存储
Elasticsearch 全文检索与复杂搜索 文档 + 倒排索引 关键词搜索、筛选聚合 强事务主库
RocketMQ 异步事件传递 Topic / Message / Group 解耦、削峰、重试、顺序 替代数据库

关系型数据库是什么

关系型数据库,英文是 Relational Database,典型代表包括:

  • MySQL
  • PostgreSQL
  • Oracle
  • SQL Server

它的核心不只是“数据放在表里”,而是:

  • 数据结构清晰
  • 关系可以被明确表达
  • 约束可以由系统保证
  • 多个操作可以纳入同一事务
  • SQL 可以稳定地支撑查询、统计、审计和治理

它解决的根问题是什么

在业务系统里,有些数据不是“尽量正确”,而是“必须正确”:

  • 一个订单只能属于一个用户
  • 一笔支付不能重复扣款
  • 一个手机号不能注册多个账号
  • 库存不能扣成负数
  • 财务流水必须可追溯

这类问题的共同特征是:

  • 有结构
  • 有规则
  • 有约束
  • 有事务边界
  • 错了代价很高

关系型数据库就是为这类问题设计的。


关系型数据库的数据模型

关系型数据库最常见的要素包括:

  • 表(Table)
  • 行(Row)
  • 列(Column)
  • 主键(Primary Key)
  • 外键(Foreign Key)
  • 索引(Index)
  • 约束(Constraint)
  • 事务(Transaction)

下面用一个非常典型的电商结构来说明。

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(64) NOT NULL UNIQUE,
    email VARCHAR(128) NOT NULL UNIQUE,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    order_no VARCHAR(64) NOT NULL UNIQUE,
    total_amount DECIMAL(10, 2) NOT NULL,
    status VARCHAR(32) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE order_items (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_id BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    quantity INT NOT NULL,
    unit_price DECIMAL(10, 2) NOT NULL,
    CONSTRAINT fk_order_items_order FOREIGN KEY (order_id) REFERENCES orders(id)
);

这个建模的价值在于:

  • order_no 可以唯一约束
  • 订单必须归属某个用户
  • 子项必须归属某个订单
  • 金额、数量、状态都有明确数据类型
  • 查询和审计边界很清楚

这类能力是很多业务系统最需要的底座。


SQL 的价值,不只是“会查数据”

SQL 最重要的价值在于它是声明式的,而且经过几十年工程验证,已经非常成熟。

典型查询

查询某个用户最近 30 天订单:

SELECT
    o.order_no,
    o.total_amount,
    o.status,
    o.created_at
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.username = 'alice'
  AND o.created_at >= NOW() - INTERVAL 30 DAY
ORDER BY o.created_at DESC;

聚合统计订单状态分布:

SELECT
    status,
    COUNT(*) AS order_count,
    SUM(total_amount) AS total_amount
FROM orders
GROUP BY status
ORDER BY order_count DESC;

事务为什么关键

最经典的例子是库存扣减和订单创建要一起成功或一起失败:

START TRANSACTION;

UPDATE products
SET stock = stock - 1
WHERE id = 1001 AND stock > 0;

INSERT INTO orders (user_id, order_no, total_amount, status)
VALUES (1, 'ORD202606270001', 99.00, 'CREATED');

COMMIT;

如果没有事务,你会很快遇到这些事故:

  • 库存扣了,但订单没建成功
  • 订单建了,但库存没扣成功
  • 并发请求把库存扣成负数
  • 接口重试导致重复写入

很多人讨论“新架构”时容易忽略这一点:真正贵的不是技术栈,而是业务错误。


PostgreSQL 为什么常被更偏工程能力的团队偏爱

如果说 MySQL 是“非常普及、非常稳妥”的业务主库选择,那么 PostgreSQL 常常被很多偏平台型、数据型或架构型团队偏爱,原因也很直接:

  • SQL 标准支持更完整
  • 数据类型更丰富
  • JSONB、数组、地理空间、全文检索、窗口函数等能力更强
  • 扩展生态非常丰富,例如 pgvector、PostGIS
  • 在一个系统内能承载更复杂的查询和扩展需求

这不是说 PostgreSQL 一定“比 MySQL 高级”,而是它在“功能上限”这件事上往往更宽。

一个 PostgreSQL 例子:JSONB 与结构化查询结合

PostgreSQL 很适合处理“核心字段结构化,但部分扩展字段灵活”的场景。

CREATE TABLE events (
    id BIGSERIAL PRIMARY KEY,
    event_type TEXT NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_events_payload_gin ON events USING GIN (payload);

INSERT INTO events (event_type, payload)
VALUES (
    'order_paid',
    '{
        "orderNo": "ORD202606270001",
        "userId": 1001,
        "channel": "wechat",
        "amount": 199.00
    }'::jsonb
);

SELECT
    id,
    payload->>'orderNo' AS order_no,
    payload->>'channel' AS channel
FROM events
WHERE event_type = 'order_paid'
  AND payload->>'channel' = 'wechat';

这个模式在实际工程里很常见:

  • 核心关系数据仍然放标准表
  • 扩展字段放 JSONB
  • 查询又不至于像“无结构文档”那样失控

PostgreSQL 与向量检索的一个现实优势

如果你的向量场景规模不大、系统复杂度要控制,可以直接基于 PostgreSQL 的 pgvector 做第一版,而不是一上来部署独立向量数据库。

这是一条非常务实的路径:

  • 小规模数据先用 PostgreSQL
  • 跑通检索和效果评估
  • 数据量、QPS、过滤复杂度上来之后,再考虑拆到专用向量库

这比“还没形成稳定需求就先引入三种新中间件”稳得多。


关系型数据库的优势与边界

优势

优势 说明
强事务 特别适合订单、支付、库存、账务
强约束 主键、唯一键、外键、检查约束非常重要
SQL 成熟 查询、聚合、报表、审计能力强
治理能力强 模型清晰,适合团队协作和长期演进
工具链成熟 监控、备份、迁移、审计都很完善

局限

局限 说明
模式变更要谨慎 大表 schema 变更通常要规划
横向扩展复杂 分库分表之后复杂度会明显上升
不适合灵活文档为主的场景 字段变化极快时维护成本变高
不擅长语义检索 向量相似度不是它的核心能力

最适合的典型场景

  • 用户、权限、组织
  • 订单、支付、退款
  • 商品、库存、价格
  • 财务、账本、对账
  • 核心主数据管理

常见误解

误解一:关系型数据库已经过时

不是。绝大多数真正重要的业务系统,核心真相源仍然是关系型数据库。

误解二:有 JSON 字段就等于有了 NoSQL

不是。JSON 字段是很实用的补充能力,但并不等于“关系型数据库已经变成文档数据库”。


非关系型数据库是什么

NoSQL 不是某一个产品,而是一大类数据库的统称。更准确地理解,它表示:

  • 不只依赖关系模型
  • 不把 SQL 和表关系视为唯一方式
  • 针对特定问题采用更适合的数据模型

NoSQL 的主流类型

类型 代表产品 数据模型 典型用途
文档数据库 MongoDB、Couchbase JSON/BSON 文档 内容、画像、配置、半结构化数据
Key-Value 数据库 Redis、DynamoDB 键值映射 缓存、会话、计数
列族数据库 HBase、Cassandra 宽表 / 列族 时序、埋点、海量写入
图数据库 Neo4j、JanusGraph 节点、边、属性 图谱、推荐、风控关联

NoSQL 解决的不是“关系型数据库不行”,而是“有些问题不是关系模型的强项”。


文档数据库:以 MongoDB 为例

MongoDB 是最典型的文档数据库。它适合的数据,天然更像一个完整对象,而不是一个要拆成多张表的严格关系模型。

它解决什么问题

以下场景通常很适合文档数据库:

  • 用户画像字段经常变
  • 商品属性很多且不固定
  • 内容系统的结构高度灵活
  • 表单定义和配置项迭代快
  • 你更关心“整体读出一个对象”,而不是复杂 JOIN

文档是什么样子

{
  "_id": "ord_202606270001",
  "userId": 1001,
  "status": "PAID",
  "totalAmount": 199.00,
  "items": [
    {
      "productId": 2001,
      "name": "机械键盘",
      "quantity": 1,
      "price": 199.00
    }
  ],
  "shippingAddress": {
    "province": "浙江",
    "city": "杭州",
    "detail": "xx 路 xx 号"
  },
  "tags": ["首单", "活动订单"],
  "createdAt": "2026-06-27T10:00:00Z"
}

如果同样建到关系型数据库里,往往会拆成多张表。文档数据库的优点是对象整体自然、读写路径短。

MongoDB 示例

插入文档:

db.orders.insertOne({
  orderNo: "ORD202606270001",
  userId: 1001,
  status: "PAID",
  totalAmount: 199.0,
  items: [
    { productId: 2001, name: "机械键盘", quantity: 1, price: 199.0 }
  ],
  createdAt: new Date()
});

条件查询:

db.orders.find(
  {
    userId: 1001,
    status: "PAID",
    totalAmount: { $gte: 100 }
  },
  {
    _id: 0,
    orderNo: 1,
    totalAmount: 1,
    status: 1
  }
);

数组字段查询:

db.orders.find({
  "items.productId": 2001
});

创建索引:

db.orders.createIndex({ userId: 1, createdAt: -1 });

MongoDB 的优势

优势 说明
模型灵活 字段调整快,适合业务迭代
与应用对象接近 JSON 对前后端都友好
整体读写自然 聚合对象存储方便
扩展能力较好 分片方案成熟

MongoDB 的边界

边界 说明
复杂关系不是强项 跨集合强关联建模不如关系型自然
强事务核心系统要谨慎 并不是它最舒服的工作负载
结构治理容易失控 “灵活”如果缺少规范,很快变成“混乱”

最适合的场景

  • 内容系统
  • 用户画像
  • 配置中心
  • 表单与模板定义
  • 半结构化业务快照

一个常见误区

MongoDB 很适合某些业务,但它不是“因为写 JSON 更舒服,所以可以替代所有关系型数据库”。


Key-Value 数据库:简单模型背后的高价值

Key-Value 数据模型看起来极其简单:

key -> value

但很多高性能场景正是因为足够简单,才足够高效。

它适合解决什么问题

  • 已知 key,直接取值
  • 不需要复杂条件查询
  • 需要低延迟
  • 需要高吞吐
  • 数据生命周期较短或结构简单

典型场景

  • 登录会话
  • 验证码
  • token
  • 限流计数
  • 去重标记
  • 缓存

代表产品包括:

  • Redis
  • DynamoDB
  • Aerospike

其中最常见、最容易被用到的就是 Redis,但 Redis 又不只是一个普通 KV 库,这一点后面会单独展开。


列族数据库:为海量宽表而生

列族数据库平时在普通业务系统里没有 MySQL、Redis 那么常见,但在大规模数据场景里很重要。

代表产品:

  • HBase
  • Cassandra
  • ScyllaDB

它解决什么问题

  • 海量写入
  • 宽表存储
  • 按 RowKey 访问
  • 分布式扩展
  • 时序、埋点、设备数据

它的特点

  • 不擅长复杂关系
  • 不以事务和 JOIN 为核心能力
  • 更关注海量数据下的分布式读写能力

典型场景

  • 用户行为埋点
  • 设备遥测
  • 海量日志底层存储
  • 超大规模时序数据

如果你的系统本质上还是标准 OLTP 业务,不要因为“听说大厂在用”就盲目引入列族数据库。


图数据库:当关系本身成为查询对象

图数据库不是为了“数据之间有关系”,而是为了“关系链路本身就是核心分析对象”。

代表产品:

  • Neo4j
  • JanusGraph
  • TigerGraph

典型问题

  • 两个账号之间通过几跳关联
  • 欺诈团伙是否共享设备、手机号、IP
  • 知识图谱中的概念关系
  • 推荐路径传播

数据模型

  • 节点(Node)
  • 边(Edge)
  • 属性(Property)

最适合的场景

  • 风控图谱
  • 社交网络
  • 推荐系统中的关系传播
  • 知识图谱

不适合的场景

  • 订单、支付、库存主库
  • 常规事务型业务系统

很多系统“有关系”,但只有少数系统真的“以关系遍历为核心”。别把这个边界搞混。


向量数据库是什么

向量数据库是这几年随着 AI、Embedding、RAG 普及而迅速升温的一类基础设施。

典型代表包括:

  • Milvus
  • Qdrant
  • Weaviate
  • Pinecone
  • pgvector
  • Elasticsearch / OpenSearch 的向量检索能力

它到底解决什么问题

传统数据库擅长:

  • 精确匹配
  • 范围过滤
  • 排序聚合
  • 结构化条件查询

向量数据库擅长的是:

  • 语义相似检索
  • 相似内容召回
  • 高维向量近邻搜索

举个例子,用户输入:

  • “怎么防止订单重复提交”

文档里未必写“重复提交”,可能写的是:

  • “幂等控制”
  • “防重设计”
  • “请求去重”

关键词检索不一定能很好命中,但向量检索可能把这些内容召回出来。

什么是向量

文本、图片、音频都可以被编码成高维向量,例如:

[0.021, -0.337, 0.114, ...]

语义越相近,通常向量距离越近。

向量数据库的数据模型

一般包括:

  • id
  • vector
  • payload / metadata

例如:

{
  "id": "doc-1001",
  "vector": [0.12, -0.08, 0.44, "..."],
  "payload": {
    "title": "订单幂等设计",
    "category": "payment",
    "lang": "zh",
    "source": "internal-wiki"
  }
}

向量数据库与全文检索的区别

维度 全文检索 向量检索
核心依据 倒排索引、词项匹配 向量距离、语义相似
擅长 精确关键词、短语、过滤聚合 语义召回、相似案例查找
优势 可解释、过滤强、成熟稳定 同义表达、改写表达召回能力强
局限 对语义改写不敏感 结果可解释性较弱,易出现“看起来相近但并不准确”的内容

实际系统里,最稳的方案通常不是二选一,而是:

  • 全文检索负责关键词召回
  • 向量检索负责语义召回
  • 两路结果再重排

向量检索示例:Python 伪真实代码

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
from sentence_transformers import SentenceTransformer

client = QdrantClient(url="http://localhost:6333")
model = SentenceTransformer("BAAI/bge-small-zh-v1.5")

collection_name = "knowledge_docs"

client.recreate_collection(
    collection_name=collection_name,
    vectors_config=VectorParams(size=512, distance=Distance.COSINE)
)

docs = [
    {"id": 1, "text": "幂等是指同一个请求重复执行多次,结果仍然一致。", "category": "payment"},
    {"id": 2, "text": "分布式锁用于协调并发访问共享资源,但要谨慎处理超时和误释放。", "category": "infra"},
    {"id": 3, "text": "消息队列可以实现异步解耦和流量削峰。", "category": "mq"}
]

vectors = model.encode([d["text"] for d in docs], normalize_embeddings=True)

client.upsert(
    collection_name=collection_name,
    points=[
        PointStruct(
            id=d["id"],
            vector=vectors[i].tolist(),
            payload={
                "text": d["text"],
                "category": d["category"]
            }
        )
        for i, d in enumerate(docs)
    ]
)

query = "如何避免重复扣款"
query_vector = model.encode(query, normalize_embeddings=True).tolist()

result = client.search(
    collection_name=collection_name,
    query_vector=query_vector,
    query_filter=Filter(
        must=[
            FieldCondition(
                key="category",
                match=MatchValue(value="payment")
            )
        ]
    ),
    limit=3
)

for item in result:
    print(item.score, item.payload["text"])

向量数据库的优势

优势 说明
语义召回强 适合 RAG、语义搜索、案例检索
可以带元数据过滤 不只是“相似”,还能按分类、权限、来源筛选
适合高维向量索引 专门为 ANN 检索设计

向量数据库的边界

边界 说明
不适合事务主库 订单、支付、库存不该放这里
检索结果不是“绝对正确” 它返回的是“相似”,不是“真相”
调优是系统工程 chunk、embedding、topK、rerank 都影响效果

常见误解

误解一:向量数据库就是 AI 时代的新主数据库

不是。它主要是检索层或召回层。

误解二:做 RAG 必须独立部署向量库

不一定。很多团队第一阶段直接用 PostgreSQL + pgvector 就够了。


Redis 到底是什么

Redis 最常被简化成“缓存”,这会误导很多工程判断。

更准确地说,Redis 是:

  • 高性能内存数据结构服务器
  • 支持一定持久化能力
  • 经常扮演缓存层、状态层、协调层、轻量流处理层

Redis 解决什么问题

Redis 适合这些问题:

  • 访问延迟必须非常低
  • 数据结构简单,但访问频繁
  • 需要计数、限流、去重、排序
  • 需要短期状态管理
  • 需要基于过期时间控制数据生命周期

Redis 的数据结构,不只是字符串

数据结构 典型用途
String 缓存对象、计数器、锁 key
Hash 会话数据、对象字段
List 简单队列、时间线
Set 去重、标签集合
Sorted Set 排行榜、延时任务
Bitmap 活跃统计、签到
HyperLogLog UV 近似去重
Stream 轻量消息流
Geo 地理位置

Redis 示例

缓存商品详情:

SET product:2001 '{"id":2001,"name":"机械键盘","price":199.0}' EX 300
GET product:2001

会话存储:

HSET session:token:abc123 userId 1001 role admin loginAt 1719450000
EXPIRE session:token:abc123 1800
HGETALL session:token:abc123

限流计数:

INCR api:rate_limit:user:1001
EXPIRE api:rate_limit:user:1001 60

排行榜:

ZADD sales_rank 1200 product:2001
ZADD sales_rank 800 product:2002
ZREVRANGE sales_rank 0 9 WITHSCORES

Stream 示例:

XADD order_events * orderNo ORD202606270001 status PAID
XGROUP CREATE order_events order_group 0 MKSTREAM
XREADGROUP GROUP order_group consumer_1 COUNT 10 STREAMS order_events >

Redis 持久化怎么理解

Redis 不是完全不落盘。常见机制有:

  • RDB 快照
  • AOF 追加日志
  • 混合持久化

但不要因为它“能持久化”,就把它理解成主交易数据库。它的核心优势是内存速度和数据结构,不是复杂业务持久化治理。

Redis 分布式锁:能用,但别神化

最常见的加锁写法:

SET lock:order:1001 "request-uuid-123" NX PX 30000

这能解决一些简单并发协调问题,但要注意:

  • 释放锁时不能无脑 DEL
  • 要校验 value,避免误删别人的锁
  • 锁超时、网络抖动、GC 暂停都可能导致误判
  • 很多问题本质上更适合用数据库唯一约束或业务幂等解决

经验上说一句直白的话:

如果一个系统到处都在上 Redis 分布式锁,往往说明业务状态设计本身出了问题。

Redis 的优势

优势 说明
性能极高 内存读写非常快
原子操作丰富 计数、集合、排序都方便
数据结构多样 能解决很多实时状态问题
生态成熟 各语言支持完善

Redis 的边界

边界 说明
内存成本高 不适合存一切
复杂查询能力弱 不是关系查询引擎
作为主存储风险高 一致性与治理语义不是主打
容易被滥用 key 设计失控会很难维护

常见误解

误解一:Redis 就是缓存

不是。缓存只是它最常见的一个角色。

误解二:有了 Redis,数据库性能问题就解决了

不一定。很多项目只是把问题从慢 SQL 转成了缓存击穿、热 key、双写不一致和大 key。


Elasticsearch 是什么,为什么经常和数据库一起出现

Elasticsearch 经常被顺手提到,但如果不单独讲清楚,很多人会对它的定位产生混淆。

Elasticsearch 本质上是:

  • 搜索引擎
  • 基于倒排索引
  • 擅长全文检索、复杂过滤、聚合分析
  • 常被当成数据库的检索副本,而不是业务真相源

它解决什么问题

以下问题不是关系型数据库的强项,却是 Elasticsearch 的强项:

  • 商品搜索
  • 文章全文搜索
  • 日志检索
  • 错误码、接口名、关键字搜索
  • 复杂筛选 + 排序 + 聚合统计

为什么数据库不直接做搜索

关系型数据库当然能做 LIKE,PostgreSQL 也有全文检索能力,但当你要处理这些需求时,搜索引擎通常更合适:

  • 中文分词
  • 倒排索引
  • 多字段加权
  • 高亮
  • 拼写纠错
  • 复杂布尔搜索
  • 搜索相关性排序

Elasticsearch 示例:商品索引文档

{
  "id": 2001,
  "name": "机械键盘 K87",
  "brand": "KeyTech",
  "category": "keyboard",
  "tags": ["机械键盘", "蓝牙", "热插拔"],
  "description": "支持蓝牙与有线双模连接,适合办公与编程。",
  "price": 399.00,
  "stock": 120
}

搜索示例:

POST /products/_search
Content-Type: application/json

{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "蓝牙机械键盘",
            "fields": ["name^3", "tags^2", "description"]
          }
        }
      ],
      "filter": [
        { "term": { "category": "keyboard" } },
        { "range": { "price": { "lte": 500 } } }
      ]
    }
  },
  "sort": [
    { "_score": "desc" },
    { "price": "asc" }
  ]
}

Elasticsearch 的优势

优势 说明
全文检索强 倒排索引成熟高效
搜索体验好 分词、相关性排序、高亮都成熟
聚合强 很适合日志与搜索分析场景
可扩展 支持大规模检索集群

Elasticsearch 的边界

边界 说明
不适合作为交易主库 一致性和事务语义不是核心设计目标
通常是副本数据 需要从主库同步索引
索引更新有成本 设计不好容易造成数据延迟和同步复杂度

一个很实用的定位原则

如果你在做:

  • “把东西存下来” -> 优先想数据库
  • “把东西搜出来” -> 优先想搜索引擎
  • “把相似内容召回出来” -> 优先想向量检索

这三个动作看起来接近,底层目标完全不同。


RocketMQ 是什么

RocketMQ 不是数据库,它是 消息队列,或者更准确一点,是 面向分布式系统的消息中间件

它要解决的问题不是“如何把数据存起来”,而是:

  • 事件怎么异步传播
  • 服务怎么解耦
  • 高峰流量怎么削峰
  • 失败怎么重试
  • 多系统如何最终一致地协作

RocketMQ 解决什么问题

举一个非常常见的支付场景:

用户支付成功后,往往不止一件事要做:

  • 更新订单状态
  • 发优惠券
  • 发短信或邮件
  • 加积分
  • 同步物流
  • 记录审计日志
  • 通知推荐系统

如果支付服务同步调用所有这些下游服务:

  • 主链路会变长
  • 一个下游抖动会拖慢整体
  • 系统之间强耦合
  • 高峰流量容易把下游打垮

MQ 的思路是:

  • 支付服务先发一个“支付成功事件”
  • 谁关心这个事件,谁自己订阅
  • 主链路尽快返回
  • 下游异步处理、失败重试

RocketMQ 的核心概念

  • Producer:生产者
  • Consumer:消费者
  • Topic:主题
  • Message:消息
  • Consumer Group:消费组
  • Retry:重试
  • Dead Letter Queue:死信
  • Ordered Message:顺序消息
  • Transaction Message:事务消息

RocketMQ Producer 示例

@Service
public class OrderEventProducer {

    private final RocketMQTemplate rocketMQTemplate;

    public OrderEventProducer(RocketMQTemplate rocketMQTemplate) {
        this.rocketMQTemplate = rocketMQTemplate;
    }

    public void sendOrderPaidEvent(String orderNo, Long userId, BigDecimal amount) {
        Map<String, Object> payload = new HashMap<>();
        payload.put("orderNo", orderNo);
        payload.put("userId", userId);
        payload.put("amount", amount);
        payload.put("eventType", "ORDER_PAID");

        rocketMQTemplate.convertAndSend("order-events", payload);
    }
}

RocketMQ Consumer 示例

@Slf4j
@Service
@RocketMQMessageListener(
    topic = "order-events",
    consumerGroup = "coupon-service-group"
)
public class CouponConsumer implements RocketMQListener<Map<String, Object>> {

    @Override
    public void onMessage(Map<String, Object> message) {
        String orderNo = (String) message.get("orderNo");
        String eventType = (String) message.get("eventType");

        if (!"ORDER_PAID".equals(eventType)) {
            return;
        }

        log.info("receive paid event, orderNo={}", orderNo);

        // 这里必须做幂等控制
        // 例如以 orderNo + eventType 建唯一键,防止重复消费发券
    }
}

顺序消息怎么理解

顺序消息通常不是全局顺序,而是 同一业务实体的局部顺序

例如同一个订单的事件:

  • 创建
  • 支付
  • 发货
  • 完成

这类消息可以按 orderNo 作为 sharding key 路由到同一队列,从而保证同一订单事件按顺序被消费。

RocketMQ 的重点,不是“能发”,而是“消费正确”

真正难的从来不是生产一条消息,而是下面这些问题:

  • 消费会不会重复
  • 重试会不会造成副作用
  • 幂等怎么保证
  • 堆积了怎么处理
  • 死信怎么回放
  • 事务消息怎么和本地事务对齐

RocketMQ 的优势

优势 说明
解耦能力强 服务之间不用强同步依赖
能削峰 高峰流量不必瞬间压垮下游
支持可靠投递 重试、死信、顺序等能力成熟
适合事件驱动架构 方便系统演进

RocketMQ 的边界

边界 说明
不是数据库 不适合承载查询和主存储职责
会增加复杂度 监控、补偿、重试都要治理
最终一致性不是自动获得的 需要业务设计配合

常见误解

误解一:有 MQ 之后就不需要事务

不对。MQ 解决的是跨系统异步协作,不替代本地事务。

误解二:消息发出去了,业务就算完成了

不对。消息发出去只表示“事件进入通道”,并不表示所有消费者都已经正确完成业务动作。


如何在真实系统里分工:MySQL、PostgreSQL、MongoDB、Redis、Elasticsearch、向量数据库、RocketMQ

这是最有价值的一部分。不要只比较单个组件,要看系统组合。

一张对照表

技术 最适合的问题 不建议拿来做什么
MySQL 标准 OLTP 业务、订单、用户、支付 语义检索
PostgreSQL OLTP + 更复杂的数据能力与扩展能力 超高性能缓存层
MongoDB 半结构化文档、内容、画像、配置 强关系事务核心系统
Redis 缓存、会话、计数、排行、状态 业务长期真相源
Elasticsearch 全文搜索、日志搜索、复杂筛选 强事务主库
向量数据库 语义搜索、RAG、相似召回 订单支付主库
RocketMQ 异步解耦、削峰、事件驱动 查询数据库

MySQL 还是 PostgreSQL

工程上最靠谱的判断不是“谁更先进”,而是:

  • 团队是否熟悉
  • 业务模型是否标准
  • 是否需要更丰富扩展能力
  • 是否希望一个数据库承载更多高级能力

一个很务实的建议:

  • 如果是典型业务系统,团队对 MySQL 很熟,MySQL 没问题
  • 如果团队熟悉 PostgreSQL,且确实会用到 JSONB、全文检索、地理空间、向量扩展等能力,PostgreSQL 往往更有上限

MongoDB 什么时候合适

当数据天然更像“一个对象文档”,而不是“多表关系事务模型”时,MongoDB 很合适。

Redis 什么时候几乎必选

当系统开始出现以下需求时,Redis 往往会自然出现:

  • 热点缓存
  • 会话管理
  • 原子计数
  • 排行榜
  • 限流
  • 幂等标记

Elasticsearch 什么时候必须上

当用户明确是“搜索”行为时,例如:

  • 商品检索
  • 文档搜索
  • 日志排查
  • 关键字分析

这时 Elasticsearch 很有价值。别让数据库去硬扛搜索引擎的工作。

向量数据库什么时候值得上

当业务核心是:

  • 语义搜索
  • 企业知识库问答
  • RAG
  • 相似案例召回
  • 图文相似匹配

这时向量数据库值得引入。

RocketMQ 什么时候值得上

当你出现这些信号时:

  • 主链路同步调用越来越长
  • 一个动作要通知很多下游系统
  • 流量高峰压不住
  • 多系统之间靠轮询同步状态
  • 业务允许最终一致而非强同步

这时上 MQ 通常是合理的。


实战架构示例一:典型电商订单系统

技术分工

  • MySQL / PostgreSQL:订单、支付、库存、用户主数据
  • Redis:商品热点缓存、会话、幂等标记、限流
  • Elasticsearch:商品搜索
  • RocketMQ:支付成功事件、发券、通知、物流同步
  • 向量数据库:智能客服知识库、商品语义召回

架构示意

flowchart LR
    A[用户请求] --> B[API 服务]
    B --> C[(MySQL / PostgreSQL)]
    B --> D[(Redis)]
    B --> E[(Elasticsearch)]
    B --> F[(Vector DB)]
    C --> G[RocketMQ]
    G --> H[优惠券服务]
    G --> I[通知服务]
    G --> J[物流服务]

订单链路说明

  1. 用户提交订单。
  2. 订单服务校验幂等和库存可用性。
  3. 核心订单写入关系型数据库。
  4. 热点商品和部分会话状态走 Redis。
  5. 支付成功后更新订单状态。
  6. 事务提交后发送 ORDER_PAID 事件到 RocketMQ。
  7. 发券、通知、积分、物流等服务异步消费。
  8. 商品检索走 Elasticsearch。
  9. 智能客服问答走向量检索与 RAG。

这个分工的关键在于:

  • 真相放数据库
  • 性能放 Redis
  • 搜索放 Elasticsearch
  • 语义召回放向量检索
  • 事件传播放 RocketMQ

职责清晰之后,系统复杂度其实是下降的。


实战架构示例二:企业知识库与 RAG 系统

技术分工

  • PostgreSQL:文档元数据、权限、版本、知识库配置
  • 对象存储:原始文件
  • Elasticsearch:关键词检索
  • 向量数据库:语义召回
  • Redis:会话缓存、热点问题缓存
  • RocketMQ:异步切片、抽取、向量化、索引更新

数据流

  1. 用户上传 PDF、Word、Markdown。
  2. 元数据写入 PostgreSQL。
  3. 文件保存到对象存储。
  4. 系统发送异步处理消息到 RocketMQ。
  5. 文档处理服务执行:
    • 文本抽取
    • 切片
    • 生成 embedding
    • 写入向量数据库
    • 写入 Elasticsearch
  6. 查询阶段:
    • 权限与知识库配置从 PostgreSQL 获取
    • 热点问题优先查 Redis
    • 关键词召回走 Elasticsearch
    • 语义召回走向量数据库
    • 结果重排后再喂给大模型

为什么这个架构比“只上向量库”更稳

因为企业知识库从来不只是“找语义相近文档”,还包括:

  • 标题和关键字搜索
  • 权限过滤
  • 版本控制
  • 数据回溯
  • 来源标记
  • 更新流水线治理

只靠向量数据库,通常做不完整。


SQL、MongoDB、Redis、Elasticsearch、RocketMQ 在同一业务里的角色差异

以“订单支付成功”这个动作举例。

1. 关系型数据库:记录最终业务状态

UPDATE orders
SET status = 'PAID', paid_at = NOW()
WHERE order_no = 'ORD202606270001'
  AND status = 'CREATED';

它负责“真相”。

2. Redis:做快速状态判断或幂等辅助

SETNX idem:pay:ORD202606270001 1
EXPIRE idem:pay:ORD202606270001 86400

它负责“防重”和“加速”。

3. MongoDB:记录支付事件快照

db.order_snapshots.insertOne({
  orderNo: "ORD202606270001",
  status: "PAID",
  paidAt: new Date(),
  snapshotType: "ORDER_PAID_EVENT",
  payload: {
    amount: 199.0,
    channel: "wechat"
  }
});

它适合“半结构化快照”。

4. Elasticsearch:让运营或客服能快速搜索订单文档副本

POST /order_search/_search
Content-Type: application/json

{
  "query": {
    "multi_match": {
      "query": "ORD202606270001 微信支付",
      "fields": ["orderNo^3", "paymentChannel", "status"]
    }
  }
}

它负责“搜”。

5. RocketMQ:通知别的系统后续处理

rocketMQTemplate.convertAndSend("order-events", Map.of(
    "eventType", "ORDER_PAID",
    "orderNo", "ORD202606270001",
    "amount", 199.0
));

它负责“传事件”。

看清这五种角色之后,很多选型争论会自然消失。


常见误区集中澄清

误区一:NoSQL 比关系型数据库更先进

不是。技术不是按“先进落后”选,而是按“问题匹配”选。

误区二:MongoDB 没 schema,所以开发更快

短期可能快,长期如果缺少约束和治理,也可能变成维护灾难。

误区三:Redis 可以替代数据库

除非你的业务极其特殊,否则大多数时候不应该这么做。

误区四:Elasticsearch 既然也能存 JSON,就可以直接当主库

不建议。能存不等于适合承担核心交易真相源职责。

误区五:向量数据库会取代 Elasticsearch

不会。两者解决的问题重叠一部分,但不是同一类引擎。

误区六:有了 RocketMQ,系统自然就解耦了

错。没有清晰事件边界、没有幂等、没有补偿,MQ 只会把复杂度从同步调用搬到异步调用里。

误区七:组件越多,架构越先进

大多数时候正好相反。组件越多,治理成本越高。真正成熟的架构不是组件堆叠,而是职责分离恰到好处。


如何避免把存储选型做成过度设计

这是最后必须讲的一段。很多系统不是技术做错,而是“想得太大、上得太早”。

一个很实用的反过度设计清单

在你准备新引入一种存储或中间件之前,先过一遍下面这张表。

检查项 应该问自己的问题
问题是否真实存在 是真的有性能瓶颈,还是只是预设会有?
现有系统是否已经够用 当前数据库或现有组件真的扛不住了吗?
新组件职责是否清晰 它到底负责真相、缓存、搜索,还是异步事件?
数据边界是否清楚 谁是主数据,谁是副本,谁可以重建?
团队是否有运维能力 监控、备份、告警、容量规划、故障演练能否跟上?
是否会引入双写一致性问题 主库与缓存、索引、向量库之间如何同步?
是否会让排查变复杂 出问题后是更容易定位,还是更难?
是否真有替代价值 新组件带来的收益,是否明显大于治理成本?

一条非常实用的经验

如果一个需求能用现有主库 + 少量索引 + 合理 SQL 解决,就先别急着上 MongoDB。

如果一个语义检索需求还没验证价值,就先别急着上独立向量数据库,先试 PostgreSQL + pgvector

如果一个异步流程只有一个消费者、量也不大,就先别急着拆成完整事件总线。

如果只是热点查询慢,就先看数据库索引和 SQL,再决定是否加 Redis,而不是一上来就把全链路缓存化。

架构设计最难的不是“知道有哪些组件”,而是知道什么时候不要引入它们。


最后的选型速查表

优先选关系型数据库的场景

  • 订单、支付、库存、财务
  • 用户、权限、组织主数据
  • 需要事务和约束
  • 需要报表、聚合和审计

优先选 MongoDB 的场景

  • 文档结构经常变化
  • 对象整体读写多
  • 内容、画像、配置、模板型数据

优先选 Redis 的场景

  • 热点缓存
  • 登录态和 token
  • 限流、计数、排行、去重
  • 轻量实时状态

优先选 Elasticsearch 的场景

  • 商品搜索
  • 文档全文搜索
  • 日志检索
  • 多字段相关性搜索与聚合

优先选向量数据库的场景

  • RAG
  • 语义搜索
  • 相似案例召回
  • 图文相似检索

优先选 RocketMQ 的场景

  • 异步解耦
  • 流量削峰
  • 事件驱动协作
  • 多系统最终一致性

总结

如果把整篇文章压缩成几句话,其实结论并不复杂:

  • 关系型数据库 负责核心业务真相,特别适合事务和约束要求高的系统。
  • NoSQL 不是替代关系型数据库,而是为特定问题提供更合适的数据模型。
  • MongoDB 适合半结构化对象数据,但不等于天然适合所有业务主库。
  • Redis 不是“只是缓存”,而是高性能内存数据结构服务,擅长做性能层和状态层。
  • Elasticsearch 负责“搜”,不是负责“真相”。
  • 向量数据库 负责语义召回,不负责订单和支付。
  • RocketMQ 负责异步事件和系统解耦,不负责业务查询存储。

真正成熟的架构,不是每个问题都引入一个新组件,也不是执着于“全都放到一个库里”。

真正成熟的架构是:

  • 真相源明确
  • 边界清晰
  • 组件职责单一
  • 数据流可追踪
  • 故障时能排查
  • 团队能长期维护

做到这些,存储与基础设施选型通常就不会走偏。