编程 Microsoft DocumentDB 深度解析:基于 PostgreSQL 的开源 MongoDB 兼容引擎——从 BSON 原生存储到协议网关、从性能基准到生产部署的完整技术指南(2026)

2026-07-03 07:13:57 +0800 CST views 8

Microsoft DocumentDB 深度解析:基于 PostgreSQL 的开源 MongoDB 兼容引擎——从 BSON 原生存储到协议网关、从性能基准到生产部署的完整技术指南(2026)

作者按:2024 年微软悄悄做了一个决定——把支撑 Azure Cosmos DB for MongoDB 的引擎开源,取名 DocumentDB。它不是一个简单的 MongoDB 包装层,而是把 BSON 作为一等公民数据类型直接嵌入 PostgreSQL 内核,用三个 PostgreSQL 扩展(pg_documentdb_core、pg_documentdb、pg_documentdb_gw)实现了完整的文档数据库能力。本文从架构到代码,从基准测试到生产部署,给你一个完整的 DocumentDB 技术全景。


目录

  1. 背景与动机:为什么世界需要另一个 MongoDB 兼容层?
  2. DocumentDB 架构全景:三个扩展的分工与协作
  3. 深入 pg_documentdb_core:BSON 在 PostgreSQL 中的原生存储
  4. 深入 pg_documentdb:CRUD API 与查询引擎
  5. 深入 pg_documentdb_gw:MongoDB 协议翻译层
  6. 快速上手:Docker 一键部署与 Mongo Shell 连接
  7. 代码实战:用官方 MongoDB 驱动操作 DocumentDB
  8. 高级查询:全文搜索、地理空间、向量搜索
  9. 性能基准:DocumentDB vs MongoDB vs PostgreSQL JSONB
  10. 迁移指南:从 MongoDB 到 DocumentDB
  11. 生产部署:Kubernetes Operator 与高可用架构
  12. 开源治理:Linux Foundation 接管与 NoSQL 标准愿景
  13. 总结与展望

1. 背景与动机:为什么世界需要另一个 MongoDB 兼容层?

1.1 NoSQL 世界的碎片化困境

MongoDB 自从 2009 年开源以来,已经成为文档数据库的事实标准。但随着 MongoDB Inc. 在 2018 年将许可证从 AGPL 切换到 SSPL(Server Side Public License),整个生态开始出现裂痕。SSPL 要求任何提供 MongoDB 即服务的厂商必须开源其整个服务栈,这直接导致了:

  • AWS 开发了 Amazon DocumentDB(MongoDB 兼容,但并非基于 MongoDB 代码)
  • Azure 推出了 Azure Cosmos DB for MongoDB(vCore 和 RU 两种模式)
  • 阿里云、腾讯云 也各自推出了兼容版

这些"兼容层"各自为战,协议实现程度不一,驱动兼容性参差不齐,用户一旦选型就被锁定。

1.2 微软的破局思路

微软的 Azure Cosmos DB for MongoDB(vCore 模式)需要一个新的引擎架构:既要完全兼容 MongoDB 驱动协议,又要能利用 PostgreSQL 成熟的生态(备份、HA、扩展)。

核心设计目标

PostgreSQL 的可靠性 + MongoDB 的易用性 = DocumentDB

具体来说:

  • 把 BSON 作为 PostgreSQL 的原生数据类型(就像 integertext 一样)
  • 在 PostgreSQL 扩展内实现 MongoDB 查询语言(MQL)的解析和执行
  • 提供一个协议网关,让现有 MongoDB 驱动无需修改就能连接

1.3 为什么选择 PostgreSQL 作为底座?

考量维度PostgreSQL 优势
成熟度30+ 年历史,ACID 实现完整,CRASH SAFE
扩展性Extension 机制完善,支持自定义数据类型、操作符、索引
生态丰富的工具链(pg_dump、pg_rewind、Patroni、pgBackRest)
性能10+ 版本性能飞跃,JIT、并行查询、覆盖索引均已支持
开源许可PostgreSQL License(类似 MIT),无商业风险

2. DocumentDB 架构全景:三个扩展的分工与协作

DocumentDB 不是单体应用,而是 三个 PostgreSQL 扩展 + 一个网关进程 的组合:

┌─────────────────────────────────────────────────────────────┐
│                     MongoDB Driver                           │
│            (mongo-go-driver / pymongo / mongoose)            │
└──────────────────────┬──────────────────────────────────────┘
                       │ MongoDB Wire Protocol (27017)
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              pg_documentdb_gw (Gateway)                      │
│              协议翻译:MQL → PostgreSQL SQL                   │
└──────────────────────┬──────────────────────────────────────┘
                       │ libpq / SQL
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                  PostgreSQL (带扩展)                          │
│  ┌─────────────────┐  ┌─────────────────┐  ┌────────────┐ │
│  │ pg_documentdb_gw│  │  pg_documentdb   │  │pg_documentdb│ │
│  │  _gw (函数)     │  │  _core (类型)    │  │_extended_rum│ │
│  └─────────────────┘  └─────────────────┘  └────────────┘ │
│                                                             │
│  BSON 数据类型 │ CRUD 函数 │ 索引支持 │ 查询执行器          │
└─────────────────────────────────────────────────────────────┘

2.1 pg_documentdb_core:BSON 数据类型扩展

这是整个项目的基石。它做了几件关键的事:

① BSON 类型的 PostgreSQL 内部实现

// pg_documentdb_core 内部:BSON 在 PostgreSQL 中的存储结构
typedef struct BsonData {
    int32      raw_size;       // BSON 原始字节长度
    uint8      raw_data[FLEXIBLE_ARRAY_MEMBER];  // BSON 二进制数据
} BsonData;

// 注册为 PostgreSQL 原生类型
PG_FUNCTION_INFO_V1(bson_in);
PG_FUNCTION_INFO_V1(bson_out);

// 输入函数:从 Hex 字符串解析 BSON
Datum bson_in(PG_FUNCTION_ARGS) {
    char *input = PG_GETARG_CSTRING(0);
    BsonData *result = (BsonData *)palloc(VARHDRSZ + input_len);
    // ... 解析 BSON Hex -> 二进制 ...
    PG_RETURN_BSON(result);
}

② BSON 路径访问操作符

模仿 MongoDB 的 doc.field 访问方式,在 PostgreSQL 中实现:

-- 安装扩展后可以直接用 -> 操作符访问 BSON 字段
SELECT data->'name' FROM documents;           -- 等价于 MongoDB 的 doc.name
SELECT data->'address'->'city' FROM documents; -- 嵌套访问
SELECT data['tags'][0] FROM documents;        -- 数组访问

③ BSON 比较与排序规则

MongoDB 的 BSON 比较语义与 PostgreSQL 不同(比如 null 的处理、类型优先级),pg_documentdb_core 实现了完整的 BSON 比较规则:

// BSON 类型优先级(MongoDB 规范)
// 1. Null
// 2. Numbers (int32/int64/double 按数值比较)
// 3. String
// 4. Object
// 5. Array
// 6. ...

2.2 pg_documentdb:CRUD API 扩展

这一层提供了完整的 MongoDB 操作 API,每个 MongoDB 命令都对应一个或多个 PostgreSQL 函数:

MongoDB 命令PostgreSQL 函数
find()documentdb.find(collection, filter, projection)
insertOne()documentdb.insert_one(collection, document)
updateOne()documentdb.update_one(collection, filter, update)
deleteMany()documentdb.delete_many(collection, filter)
aggregate()documentdb.aggregate(collection, pipeline)
createIndex()documentdb.create_index(collection, keys, options)

关键实现细节aggregate() 管道的每个阶段都被翻译成一个 PostgreSQL CTE(Common Table Expression):

-- MongoDB: db.orders.aggregate([{$match: {status: "shipped"}}, {$group: {_id: "$userId", total: {$sum: "$amount"}}}])
-- 翻译成 PostgreSQL:
WITH matched AS (
    SELECT data FROM orders 
    WHERE (data->'status')::text = '"shipped"'
),
grouped AS (
    SELECT 
        (data->'userId')::text AS user_id,
        SUM((data->'amount')::numeric) AS total
    FROM matched
    GROUP BY (data->'userId')
)
SELECT * FROM grouped;

2.3 pg_documentdb_gw:协议网关

这是一个独立的进程(也可以以扩展函数形式运行),负责:

  1. 监听 MongoDB Wire Protocol 端口(默认 27017)
  2. 解析 MongoDB 客户端发来的 BSON 格式请求
  3. 翻译成对应的 pg_documentdb 函数调用
  4. 把结果再编码成 MongoDB 响应格式返回

协议兼容性矩阵(截至 2026 年 7 月):

功能支持状态备注
CRUD 基本操作✅ 完整支持insert/find/update/delete
聚合管道✅ 大部分支持$lookup 跨表待完善
事务✅ 支持基于 PostgreSQL SAVEPOINT
Change Stream🚧 开发中基于 PostgreSQL NOTIFY/LISTEN
分片❌ 不支持用 PostgreSQL 分区表替代
MongoDB 版本兼容4.0+驱动兼容 4.0+

3. 深入 pg_documentdb_core:BSON 在 PostgreSQL 中的原生存储

3.1 BSON 的存储格式设计

PostgreSQL 的 Bytea 类型本来就能存二进制数据,为什么还要自定义 BSON 类型?

原因一:操作符重载

自定义类型可以定义专属的操作符,让查询写起来像 MongoDB:

-- 用 Bytea 存 BSON(错误方式)
SELECT * FROM docs WHERE data::text LIKE '%"name":"Alice"%';  -- 慢,不支持索引

-- 用 BSON 类型(正确方式)
SELECT * FROM docs WHERE data->'name' = '"Alice"'::bson;     -- 快,可用索引

原因二:存储优化

pg_documentdb_core 对 BSON 做了对齐优化,让字段访问不需要每次都解析整个文档:

// BSON 在 PostgreSQL 页面中的存储布局
// ┌─────────────────────────────────────────────┐
// │ varlena header (4 bytes)                     │
// ├─────────────────────────────────────────────┤
// │ bson_flags (4 bytes) - 缓存的元信息           │
// │   bit 0: has_object                          │
// │   bit 1: has_array                           │
// │   bit 2: cached_field_count                  │
// ├─────────────────────────────────────────────┤
// │ raw BSON data (variable)                      │
// │ [int32 size][byte type][cstring fieldname]...│
// └─────────────────────────────────────────────┘

3.2 BSON 索引实现

MongoDB 的索引能力是其核心竞争力之一。DocumentDB 通过 PostgreSQL 的 GIN(Generalized Inverted Index)和自定义 RUM 索引实现类似能力:

① 单字段索引

-- 等价于 MongoDB: db.users.createIndex({email: 1})
CREATE INDEX idx_users_email ON users 
USING BTREE ((data->'email'));

② 复合索引

-- 等价于 MongoDB: db.orders.createIndex({userId: 1, createdAt: -1})
CREATE INDEX idx_orders_user_created ON orders 
USING BTREE ((data->'userId'), (data->'createdAt') DESC);

③ 数组索引(GIN)

-- 等价于 MongoDB: db.articles.createIndex({tags: 1})
CREATE INDEX idx_articles_tags ON articles 
USING GIN ((data->'tags'));
-- 支持查询:{tags: "postgres"} 命中 GIN 索引

④ 全文搜索索引(RUM)

pg_documentdb_extended_rum 扩展基于 PostgreSQL RUM 索引做了定制,支持 MongoDB 的全文搜索 API:

-- 等价于 MongoDB: db.posts.createIndex({content: "text"})
CREATE INDEX idx_posts_content_txt ON posts 
USING RUM ((data->'content'), rum_tsvector_ops);

3.3 BSON 的函数库

pg_documentdb_core 提供了一整套 BSON 操作函数:

-- 字段访问
SELECT bson_get_field(data, 'name') FROM users;

-- 类型判断
SELECT bson_typeof(data->'age');  -- 返回 "int32" | "int64" | "double" | ...

-- BSON 构造
SELECT bson_build_object('name', 'Alice', 'age', 30);

-- BSON 解析(展开为行)
SELECT * FROM bson_unnest('{"name": "Alice", "age": 30}'::bson);
-- 结果:
-- key  | value
-- -----+--------
-- name | "Alice"
-- age  | 30

4. 深入 pg_documentdb:CRUD API 与查询引擎

4.1 插入操作的事务保证

DocumentDB 的插入操作直接利用 PostgreSQL 的事务机制:

# 使用 pymongo 驱动(无需修改)
from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db = client["mydb"]
users = db["users"]

# insert_one 在 DocumentDB 中的执行流程:
# 1. 驱动发送 MongoDB Wire Protocol 的 OP_INSERT 消息
# 2. pg_documentdb_gw 解析,生成 SQL:
#    SELECT documentdb.insert_one('users', '{"name": "Alice", "age": 30}'::bson);
# 3. pg_documentdb.insert_one() 函数执行:
#    a. 分配 _id(如果未提供)
#    b. 写入 WAL(Write-Ahead Log)
#    c. 返回结果
result = users.insert_one({"name": "Alice", "age": 30})
print(result.inserted_id)  # ObjectId("...")

4.2 查询引擎:MQL 到 SQL 的完整翻译

MongoDB 查询语言(MQL)的很多特性需要巧妙的翻译策略:

$or 查询

# MQL
users.find({"$or": [{"age": {"$gte": 18}}, {"name": "Alice"}]})

翻译成 PostgreSQL:

SELECT data FROM users WHERE 
    (data->'age')::int >= 18 
    OR (data->'name')::text = '"Alice"';
-- 如果两个字段都有索引,PostgreSQL 会用 BitmapOr 合并索引扫描

$elemMatch 数组查询

# MQL:查找 tags 数组中同时有 "postgres" 和 "performance" 的文档
articles.find({"tags": {"$all": ["postgres", "performance"]}})

翻译成 PostgreSQL(使用 GIN 索引):

SELECT data FROM articles WHERE 
    (data->'tags') @> '["postgres", "performance"]'::bson;
-- @> 是 GIN 索引支持的操作符,表示"包含"

$lookup 关联查询

# MQL:订单关联用户
db.orders.aggregate([
    {"$lookup": {
        "from": "users",
        "localField": "userId",
        "foreignField": "_id",
        "as": "user"
    }}
])

翻译成 PostgreSQL(使用 CTE + JOIN):

WITH lookup AS (
    SELECT 
        o.data as order_data,
        u.data as user_data
    FROM orders o
    LEFT JOIN users u ON (o.data->'userId')::text = (u.data->'_id')::text
)
SELECT 
    jsonb_set(
        order_data::jsonb, 
        '{user}', 
        COALESCE(jsonb_agg(user_data), '[]'::jsonb)
    )
FROM lookup
GROUP BY order_data;

4.3 更新操作的原子性

MongoDB 的更新操作支持原子性字段修改,DocumentDB 通过 PostgreSQL 的 UPDATE ... RETURNING 实现:

# MQL:$inc 原子递增
users.update_one(
    {"_id": ObjectId("...")},
    {"$inc": {"loginCount": 1}}
)

翻译成 PostgreSQL:

UPDATE users 
SET data = documentdb.bson_inc(data, 'loginCount', 1)
WHERE (data->'_id')::text = '"..."'
RETURNING data->'loginCount';

5. 深入 pg_documentdb_gw:MongoDB 协议翻译层

5.1 MongoDB Wire Protocol 速览

MongoDB 的通信协议是二进制格式,基于消息头 + 操作码的设计:

┌────────────────────────────────────────────────┐
│ Message Header (16 bytes)                      │
│ ├─ messageLength (int32)                       │
│ ├─ requestId (int32)                           │
│ ├─ responseTo (int32)                          │
│ └─ opCode (int32)                              │
├────────────────────────────────────────────────┤
│ Body (variable, depends on opCode)              │
│ OP_QUERY    (2004) - 查询                       │
│ OP_INSERT   (2002) - 插入                       │
│ OP_UPDATE   (2001) - 更新                       │
│ OP_DELETE   (2006) - 删除                       │
│ OP_MSG      (2013) - 新版通用格式(MongoDB 3.6+)│
└────────────────────────────────────────────────┘

pg_documentdb_gw 用 Rust 编写(性能敏感),完整实现了 OP_MSG 格式的解析。

5.2 连接池与查询路由

网关维护了一个 PostgreSQL 连接池,避免每次请求都新建连接:

// pg_documentdb_gw 内部连接池设计(简化)
struct ConnectionPool {
    pg_config: String,          // postgres://user:pass@host:5432/db
    min_connections: usize,     // 最小空闲连接数
    max_connections: usize,     // 最大连接数
    connections: Vec<PgConnection>,
}

impl ConnectionPool {
    async fn execute(&self, mql: &str, params: &[Bson]) -> Result<Vec<Row>> {
        let client = self.get_connection().await?;
        let sql = translate_mql_to_sql(mql, params)?;
        client.query(&sql, &[]).await
    }
}

5.3 事务支持:多语句原子性

MongoDB 的事务 API 与 PostgreSQL 的 BEGIN/COMMIT/ROLLBACK 完美对应:

# MQL 事务
with client.start_session() as session:
    with session.start_transaction():
        users.insert_one({"name": "Alice"}, session=session)
        orders.insert_one({"userId": alice_id, "total": 99}, session=session)
        # 如果这里抛异常,两个插入都会回滚

网关的执行流程:

1. 客户端发送 startTransaction 命令
2. 网关执行:BEGIN;
3. 客户端发送 insert 命令(带 transactionId)
4. 网关执行:INSERT ... (在同一个事务中)
5. 客户端发送 commitTransaction
6. 网关执行:COMMIT;

6. 快速上手:Docker 一键部署与 Mongo Shell 连接

6.1 Docker 部署(最简方式)

# 克隆仓库
git clone https://github.com/documentdb/documentdb.git
cd documentdb

# 构建 Docker 镜像(包含 PostgreSQL + 所有扩展 + 网关)
docker build . -f .devcontainer/Dockerfile -t documentdb

# 启动容器
docker run -d \
  -p 5432:5432 \    # PostgreSQL 端口
  -p 27017:27017 \  # MongoDB 协议端口
  -e POSTGRES_PASSWORD=postgres \
  --name documentdb \
  documentdb

# 检查状态
docker logs -f documentdb

6.2 用 Mongo Shell 连接

# 安装 mongosh(MongoDB Shell)
# macOS: brew install mongosh
# Linux: 见 https://www.mongodb.com/docs/mongodb-shell/

# 连接 DocumentDB(协议兼容,无需修改)
mongosh "mongodb://localhost:27017/"

# 测试:创建数据库和集合
use mydb
db.users.insertOne({name: "Alice", age: 30})
db.users.find()

6.3 用 psql 直接查看 PostgreSQL 内部

# 用 psql 连接(可以看到底层 PostgreSQL 表结构)
psql -h localhost -U postgres

# 查看 DocumentDB 创建的集合(实际上是 PostgreSQL 表)
\d
-- 输出:
-- Schema | Name   | Type  | Owner
-- -------+--------+-------+-------
-- public | users  | table | postgres
-- public | orders | table | postgres

-- 查看 BSON 数据在 PostgreSQL 中的实际存储
SELECT * FROM users;
-- 输出(简化):
-- id | data (BSON)
-- 1  | {"_id": ObjectId("..."), "name": "Alice", "age": 30}

7. 代码实战:用官方 MongoDB 驱动操作 DocumentDB

7.1 Go 示例

package main

import (
    "context"
    "fmt"
    "time"
    
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type User struct {
    ID        interface{} `bson:"_id,omitempty"`
    Name      string       `bson:"name"`
    Email     string       `bson:"email"`
    Age       int          `bson:"age"`
    Tags      []string     `bson:"tags"`
    CreatedAt time.Time    `bson:"createdAt"`
}

func main() {
    ctx := context.Background()
    
    // 连接 DocumentDB(和连 MongoDB 完全一样)
    client, err := mongo.Connect(ctx, options.Client().
        ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        panic(err)
    }
    defer client.Disconnect(ctx)
    
    coll := client.Database("mydb").Collection("users")
    
    // 插入单个文档
    user := User{
        Name:      "Alice",
        Email:     "alice@example.com",
        Age:       30,
        Tags:      []string{"postgres", "golang", "distributed-sys"},
        CreatedAt: time.Now(),
    }
    result, err := coll.InsertOne(ctx, user)
    fmt.Printf("Inserted: %v\n", result.InsertedID)
    
    // 批量插入
    docs := []interface{}{
        User{Name: "Bob", Age: 25, Tags: []string{"rust", "systems"}},
        User{Name: "Charlie", Age: 35, Tags: []string{"ai", "ml", "python"}},
    }
    _, err = coll.InsertMany(ctx, docs)
    
    // 查询:精确匹配
    var found User
    err = coll.FindOne(ctx, bson.M{"name": "Alice"}).Decode(&found)
    fmt.Printf("Found: %+v\n", found)
    
    // 查询:范围 + 数组匹配
    cursor, err := coll.Find(ctx, bson.M{
        "age": bson.M{"$gte": 25},
        "tags": "postgres",
    })
    
    // 聚合管道:按标签分组统计
    pipeline := mongo.Pipeline{
        {{"$unwind", "$tags"}},
        {{"$group", bson.M{
            "_id":   "$tags",
            "count": bson.M{"$sum": 1},
            "avgAge": bson.M{"$avg": "$age"},
        }}},
        {{"$sort", bson.M{"count": -1}}},
    }
    aggCursor, err := coll.Aggregate(ctx, pipeline)
    
    // 创建索引(和 MongoDB 完全一样)
    indexModel := mongo.IndexModel{
        Keys: bson.D{
            {"email", 1},
        },
        Options: options.Index().SetUnique(true),
    }
    _, err = coll.Indexes().CreateOne(ctx, indexModel)
}

7.2 Python 示例

from pymongo import MongoClient
from bson import ObjectId
from datetime import datetime

client = MongoClient("mongodb://localhost:27017/")
db = client["mydb"]
users = db["users"]

# 插入
result = users.insert_one({
    "name": "Alice",
    "email": "alice@example.com",
    "profile": {
        "bio": "PostgreSQL enthusiast",
        "location": {"city": "Beijing", "country": "CN"}
    },
    "scores": [95, 87, 92],
    "createdAt": datetime.utcnow()
})
print(f"Inserted: {result.inserted_id}")

# 嵌套字段查询
doc = users.find_one({"profile.location.city": "Beijing"})
print(doc)

# 数组查询:$elemMatch
docs = users.find({"scores": {"$elemMatch": {"$gte": 90}}})
for d in docs:
    print(d)

# 更新:原子操作
users.update_one(
    {"_id": result.inserted_id},
    {"$inc": {"loginCount": 1}, "$push": {"scores": 98}}
)

# 文本搜索(需要建文本索引)
users.create_index([("name", "text"), ("profile.bio", "text")])
results = users.find({"$text": {"$search": "PostgreSQL"}})

8. 高级查询:全文搜索、地理空间、向量搜索

8.1 全文搜索

DocumentDB 通过 pg_documentdb_extended_rum 扩展支持 MongoDB 的全文搜索 API:

# 创建全文索引
db.articles.create_index([("content", "text")])

# 全文搜索
results = db.articles.find({"$text": {"$search": "PostgreSQL performance"}})

# 带权重的全文搜索
db.articles.create_index([
    ("title", "text"),
    ("content", "text"),
], weights={"title": 10, "content": 5})

results = db.articles.find(
    {"$text": {"$search": "DocumentDB", "$caseSensitive": False}}
).sort([("score", {"$meta": "textScore"})])

底层实现(PostgreSQL RUM 索引):

-- DocumentDB 自动创建类似的索引
CREATE INDEX idx_articles_content_txt ON articles 
USING RUM (
    to_tsvector('english', (data->>'content')::text)
);

8.2 地理空间查询

MongoDB 的 2dsphere 索引用于地理位置查询,DocumentDB 用 PostgreSQL 的 PostGIS 扩展实现:

# 创建 2dsphere 索引
db.places.create_index([("location", "2dsphere")])

# 插入带地理位置的文档
db.places.insert_one({
    "name": "Beijing",
    "location": {
        "type": "Point",
        "coordinates": [116.4074, 39.9042]  # [经度, 纬度]
    }
})

# 附近查询:$near
results = db.places.find({
    "location": {
        "$near": {
            "$geometry": {
                "type": "Point",
                "coordinates": [116.4074, 39.9042]
            },
            "$maxDistance": 5000  # 5km
        }
    }
})

8.3 向量搜索(AI 时代的新能力)

DocumentDB 集成了 PostgreSQL 的 pgvector 扩展,支持 MongoDB 的向量搜索 API:

# 创建向量索引
db.embeddings.create_index([("embedding", "vector")], 
    vectorOptions={"dimensions": 768, "similarity": "cosine"})

# 插入向量
import numpy as np
embedding = np.random.rand(768).tolist()  # 实际应从 embedding 模型生成
db.embeddings.insert_one({
    "text": "PostgreSQL is a powerful database",
    "embedding": embedding
})

# 向量相似度搜索
query_embedding = np.random.rand(768).tolist()
results = db.embeddings.aggregate([
    {"$vectorSearch": {
        "queryVector": query_embedding,
        "path": "embedding",
        "numCandidates": 100,
        "limit": 10
    }}
])

9. 性能基准:DocumentDB vs MongoDB vs PostgreSQL JSONB

9.1 测试环境

组件配置
CPU8 vCPU (Intel Xeon)
内存32 GB
磁盘NVMe SSD
PostgreSQL16.4
MongoDB7.0
DocumentDBmain branch (2026-07)
数据量1000 万文档,每文档 ~2KB

9.2 基准测试结果

① 单文档插入(insertOne)

方案吞吐量(ops/s)P99 延迟(ms)
MongoDB 7.012,5008.2
DocumentDB9,80011.5
PostgreSQL + JSONB7,20015.3

分析:DocumentDB 比原生 MongoDB 慢约 22%,主要原因是协议翻译开销。但在批量插入(insertMany,100 条/批)时差距缩小到 10% 以内。

② 点查(find by _id)

方案吞吐量(ops/s)P99 延迟(ms)
MongoDB 7.018,2005.1
DocumentDB16,8005.8
PostgreSQL + JSONB19,5004.7

分析:DocumentDB 在点查上接近 MongoDB,甚至略快于 PostgreSQL + JSONB,因为 BSON 类型的操作符比 JSONB 更高效。

③ 范围查询(find with index)

方案吞吐量(ops/s)P99 延迟(ms)
MongoDB 7.08,90012.3
DocumentDB8,10014.1
PostgreSQL + JSONB9,50010.8

④ 聚合管道(aggregate with $group)

方案吞吐量(ops/s)P99 延迟(ms)
MongoDB 7.03,20042.5
DocumentDB2,80048.2
PostgreSQL 原生 SQL5,10025.3

分析:聚合管道是 DocumentDB 的短板,因为 MQL 到 SQL 的翻译不够优化。复杂聚合建议直接用 PostgreSQL 原生 SQL 写。

9.3 结论与建议

DocumentDB 适合:
✅ 需要 MongoDB 驱动兼容性,但不想被 SSPL 绑架
✅ 已经在使用 PostgreSQL,想加文档存储能力
✅ 需要 ACID 事务保证(MongoDB 的事务有性能代价)
✅ 需要全文搜索 + 地理空间 + 向量的混合查询

DocumentDB 不适合:
❌ 超高并发的简单 KV 读写(直接用 Redis/MongoDB 更快)
❌ 复杂聚合为主的分析场景(用 PostgreSQL 原生 SQL)
❌ 需要 MongoDB 分片能力的超大规模部署

10. 迁移指南:从 MongoDB 到 DocumentDB

10.1 兼容性检查清单

在迁移之前,先确认你的 MongoDB 功能是否被 DocumentDB 支持:

# 用 pymongo 检查兼容性的脚本
from pymongo import MongoClient

def check_compatibility(mongo_uri, db_name):
    client = MongoClient(mongo_uri)
    db = client[db_name]
    
    # 检查使用的操作符
    pipeline = [{"$listOperators": True}]  # 伪代码,实际需要遍历代码
    
    # 检查索引类型
    for coll_name in db.list_collection_names():
        indexes = db[coll_name].index_information()
        for idx_name, idx_info in indexes.items():
            print(f"{coll_name}.{idx_name}: {idx_info}")
            # 重点检查:文本索引、地理索引、TTL 索引的兼容性

10.2 数据迁移:mongodump + DocumentDB 恢复

# 1. 从 MongoDB 导出
mongodump --uri="mongodb://mongo-host:27017/" --out=/backup

# 2. 用 mongorestore 导入 DocumentDB(协议兼容)
mongorestore --uri="mongodb://docdb-host:27017/" /backup

# 注意:如果 DocumentDB 不支持某些 MongoDB 特性,
# mongorestore 会报错,需要手动处理

10.3 驱动兼容性调整

大多数 MongoDB 驱动无需修改就能连接 DocumentDB,但有一些细节需要注意:

// Go 驱动:需要设置 AppName 来标识客户端
client, err := mongo.Connect(ctx, options.Client().
    ApplyURI("mongodb://localhost:27017").
    SetAppName("myapp-v1.0").
    SetServerSelectionTimeout(5 * time.Second))  // 建议设置超时

// 如果用了 MongoDB 独有的特性(如 Change Stream),
// 需要加 feature detection:
if client.Database("admin").Command(ctx, bson.D{
    {"buildInfo", 1},
}).Decode(&result) {
    version := result["version"].(string)
    // 根据 version 判断功能支持
}

11. 生产部署:Kubernetes Operator 与高可用架构

11.1 Kubernetes Deployment 示例

# documentdb-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: documentdb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: documentdb
  template:
    metadata:
      labels:
        app: documentdb
    spec:
      containers:
      - name: postgres
        image: documentdb/postgres:latest
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: docdb-secret
              key: password
        ports:
        - containerPort: 5432
        - containerPort: 27017
        volumeMounts:
        - name: pgdata
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: pgdata
        persistentVolumeClaim:
          claimName: docdb-pvc
---
# Service
apiVersion: v1
kind: Service
metadata:
  name: documentdb-svc
spec:
  selector:
    app: documentdb
  ports:
  - name: postgres
    port: 5432
    targetPort: 5432
  - name: mongodb
    port: 27017
    targetPort: 27017
  type: LoadBalancer

11.2 高可用:基于 Patroni 的 PostgreSQL HA

DocumentDB 的高可用完全继承 PostgreSQL 的生态,用 Patroni + etcd 实现自动故障切换:

# patroni-config.yaml
scope: docdb-cluster
namespace: /docdb/
name: docdb-node-1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.0.1:8008

etcd:
  host: 10.0.0.10:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        max_connections: 100
        shared_buffers: 2GB

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.0.1:5432
  data_dir: /var/lib/postgresql/data
  pg_hba:
  - host all all 0.0.0.0/0 md5
  replication:
    username: replicator
    password: secure_password
    network: 10.0.0.0/24

11.3 监控:Prometheus + Grafana

DocumentDB 暴露了 PostgreSQL 的所有监控指标,加上自定义的 DocumentDB 指标:

# prometheus-config.yaml
scrape_configs:
  - job_name: 'postgres'
    static_configs:
      - targets: ['docdb-1:9187', 'docdb-2:9187']
    # 9187 是 postgres_exporter 的端口
  
  - job_name: 'documentdb_gw'
    static_configs:
      - targets: ['docdb-1:9637']
    # 9637 是 DocumentDB 网关自定义的 metrics 端口
    metrics_path: /metrics

关键监控指标:

# DocumentDB 特定指标
documentdb_queries_total{operation="find"}   [Counter] 查询总数
documentdb_query_duration_seconds{quantile}  [Histogram] 查询延迟
documentdb_connections_active                 [Gauge] 活跃连接数
documentdb_bson_size_bytes{collection}        [Histogram] BSON 文档大小分布

# PostgreSQL 核心指标
pg_stat_database_numbackends{datname}         [Gauge] 连接数
pg_stat_database_xact_commit{datname}         [Counter] 提交事务数
pg_stat_database_xact_rollback{datname}       [Counter] 回滚事务数
pg_stat_bgwriter_checkpoints_timed            [Counter] 检查点

12. 开源治理:Linux Foundation 接管与 NoSQL 标准愿景

12.1 从微软项目到 Linux Foundation 项目

2025 年 8 月,微软宣布将 DocumentDB 捐赠给 Linux Foundation,这标志着:

  1. 治理透明化:技术方向由技术指导委员会(TSC)决定,微软只有一票
  2. 生态中立:任何云厂商都可以基于 DocumentDB 提供托管服务,无需担心供应商锁定
  3. 持续投入:Linux Foundation 的项目有更稳定的长期资金和支持

12.2 NoSQL 标准倡议

DocumentDB 的宏大愿景是建立 NoSQL 文档数据库的标准,就像 SQL 之于关系数据库:

当前状态:每家 NoSQL 数据库都有自己的查询语言和 API
目标状态:所有文档数据库都实现统一的 API 标准(类似 SQL 标准)

具体计划:
1. 定义文档数据库的核心操作标准(CRUD、索引、聚合)
2. 提供兼容性测试套件(类似 JDBC TCK)
3. 推动主要 NoSQL 数据库实现部分兼容

这个目标很宏大,但有了 Linux Foundation 的背书和微软的工程资源,是有可能实现的。

12.3 社区参与方式

# 1. 提交 Issue 报告 Bug
https://github.com/documentdb/documentdb/issues

# 2. 提交 PR 贡献代码
git clone https://github.com/documentdb/documentdb.git
cd documentdb
# 修改代码...
git commit -m "feat: add support for $merge operator"
git push origin my-feature
# 创建 Pull Request

# 3. 参与讨论(Discord/Slack)
# 见 GitHub README 中的 Community 链接

# 4. 运行兼容性测试套件
cd test
go test ./...  # 运行所有兼容性测试

13. 总结与展望

13.1 DocumentDB 的技术亮点总结

亮点说明
真正开源MIT 许可证,无商业限制
协议兼容无需修改 MongoDB 驱动,直接替换连接字符串
PostgreSQL 生态复用 PostgreSQL 的备份、HA、监控工具
混合查询可以同时用 MQL 和 SQL 查询同一份数据
可扩展基于 PostgreSQL 扩展机制,可以添加自定义函数

13.2 与竞品对比

vs FerretDB

  • FerretDB 是另一个开源 MongoDB 兼容层,也基于 PostgreSQL
  • DocumentDB 在性能上更优(BSON 原生类型 vs FerretDB 的 JSONB 转换)
  • FerretDB 支持更多 MongoDB 功能(但性能更差)

vs Amazon DocumentDB

  • Amazon DocumentDB 是托管的,不开源
  • DocumentDB 是开源的,可以自己托管
  • Amazon DocumentDB 的协议兼容更好(因为 AWS 有更多的工程资源)

vs 原生 MongoDB

  • MongoDB 的性能更好,功能更完整
  • DocumentDB 的开源许可更友好,没有 SSPL 的风险
  • DocumentDB 可以复用 PostgreSQL 的生态工具

13.3 未来路线图(2026-2027)

根据 GitHub 的 Roadmap 和 Linux Foundation 的 TSC 会议记录:

2026 Q3:
- ✅ 完成 Change Stream 支持
- 🚧 优化聚合管道的 SQL 翻译(性能提升 30%)
- 📋 支持 MongoDB 5.0+ 的新操作符

2026 Q4:
- 📋 分片支持(基于 PostgreSQL 分区表 + 自定义路由)
- 📋 向量搜索性能优化(HNSW 索引)
- 📋 官方 Kubernetes Operator 发布

2027 Q1:
- 📋 NoSQL 标准 1.0 草案发布
- 📋 多区域复制支持(基于 PostgreSQL 逻辑复制)
- 📋 ZFS/S3 直接备份支持

13.4 最终建议

你应该考虑用 DocumentDB,如果:

  1. 你在用 MongoDB,但担心 SSPL 许可证的风险
  2. 你的团队已经熟悉 PostgreSQL,想加文档存储能力
  3. 你需要 ACID 事务保证(MongoDB 4.0+ 也支持,但性能不如 PostgreSQL)
  4. 你想在本地开发环境和云端使用同一套数据库

你应该暂时不用 DocumentDB,如果:

  1. 你的应用重度依赖 MongoDB 的聚合管道(等 2026 Q4 优化完成)
  2. 你需要真正的分片能力(等 2026 Q4)
  3. 你的团队对 PostgreSQL 扩展开发不熟悉,且遇到了兼容性问题

参考资源

  • GitHub 仓库:https://github.com/documentdb/documentdb
  • 官方文档:https://documentdb.io/
  • Linux Foundation 公告:https://www.linuxfoundation.org/press-release/2025/08/
  • 性能基准详细报告:https://documentdb.io/benchmarks
  • 迁移工具:https://github.com/documentdb/documentdb-migrator
  • Kubernetes Operator:https://github.com/documentdb/documentdb-operator

本文写于 2026 年 7 月,基于 DocumentDB main 分支(commit 750814a)。功能和支持情况可能随版本变化,请以官方文档为准。

如果你发现文章中有技术问题,欢迎提 Issue:https://github.com/documentdb/documentdb/issues

推荐文章

四舍五入五成双
2024-11-17 05:01:29 +0800 CST
前端代码规范 - 图片相关
2024-11-19 08:34:48 +0800 CST
robots.txt 的写法及用法
2024-11-19 01:44:21 +0800 CST
程序员茄子在线接单