跳过正文
  1. PostgreSQL大法师/

FerretDB:假扮成MongoDB的PG

·2180 字·5 分钟· ·
PostgreSQL PG生态 MongoDB 扩展
冯若航
作者
冯若航
Pigsty 创始人, @Vonng
目录

MongoDB 曾经是一项令人惊叹的技术,让开发者能够抛开关系型数据库的“模式束缚”,快速构建应用程序。然而随着时间推移,MongoDB 放弃了它的开源本质,这使得许多开源项目和早期商业项目无法使用它。

大多数 MongoDB 用户其实并不需要 MongoDB 提供的高级功能,但他们确实需要一个易于使用的开源文档数据库解决方案。PostgreSQL 的 JSON 功能支持已经足够完善了:二进制存储 JSONB,GIN 任意字段索引 ,各种 JSON 处理函数,JSON PATH 和 JSON Schema,PG早已是一个功能完备,性能强大的文档数据库了。但是提供替代的功能,和直接仿真还是不一样的。

为了填补这个空白,FerretDB 应运而生,旨在提供一个真正开源MongoDB 替代。这是一个非常有趣的项目,之前的名字叫 “MangoDB”,因为有碰瓷 “MongoDB” 的嫌疑(芒果DB vs 蒙古DB),所以在 1.0 版本改成了现在的名字 FerretDB。FerretDB 可以为使用 MongoDB 驱动的应用提供一个丝滑迁移到 PostgreSQL 的过渡方案。

它的功能就是让 PostgreSQL 假扮成 MongoDB。它是一个为 PG 提供 MongoDB Wire Protocol 支持的协议转换中间件/Proxy。上次做过这种事的插件是 AWS 的 Babelfish,让 PostgreSQL 兼容 SQL Service 的线缆协议假扮成 Microsoft SQL Server。

FerretDB 作为一个选装组件,对丰富 PostgreSQL 生态大有裨益。Pigsty 在 1.x 中就提供了基于 Docker 的 FerretDB 模板,在 v2.3 中更是提供了原生部署支持。目前,Pigsty 社区已经与 FerretDB 社区成为了合作伙伴,后续将进行深度的合作与适配支持。

本文简单介绍了 FerretDB 的安装、部署与使用。


配置
#

在部署 Mongo (FerretDB) 集群前,你需要先在配置清单中使用相关参数定义好它。下面的例子将默认的单节点 pg-meta 集群的 meta 数据库作为 FerretDB 的底层存储:

ferret:
  hosts: { 10.10.10.10: { mongo_seq: 1 } }
  vars:
    mongo_cluster: ferret
    mongo_pgurl: 'postgres://dbuser_meta:DBUser.Meta@10.10.10.10:5432/meta'

这里 mongo_clustermongo_seq 属于不可或缺的身份参数,对于 FerretDB 来说,还有一个必须提供的参数是 mongo_pgurl,指定了底层 PG 的位置。

您可以使用 服务 来接入高可用的 PostgreSQL 集群,并部署多个 FerretDB 实例副本并绑定 L2 VIP 以实现 FerretDB 层本身的高可用。

ferret-ha:
  hosts:
    10.10.10.45: { mongo_seq: 1 }
    10.10.10.46: { mongo_seq: 2 }
    10.10.10.47: { mongo_seq: 3 }
  vars:
    mongo_cluster: ferret
    mongo_pgurl: 'postgres://test:test@10.10.10.3:5436/test'
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.99
    vip_interface: eth1

管理
#

创建Mongo集群
#

在配置清单中定义好MONGO集群后,您可以使用以下命令完成安装。

./mongo.yml -l ferret   # 在 ferret 分组上安装“MongoDB/FerretDB”

因为 FerretDB 使用了 PostgreSQL 作为底层存储,所以重复运行此剧本通常并无大碍。

移除Mongo集群
#

要移除 Mongo/FerretDB 集群,运行 mongo.yml剧本的子任务:mongo_purge,并使用 mongo_purge 命令行参数即可:

./mongo.yml -e mongo_purge=true -t mongo_purge

安装MongoSH
#

您可以使用 MongoSH 作为客户端工具访问 FerretDB 集群

cat > /etc/yum.repos.d/mongo.repo <<EOF
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/6.0/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
EOF
yum install -y mongodb-mongosh

当然,您也可以直接安装 mongosh 的 RPM 包:

rpm -ivh https://mirrors.tuna.tsinghua.edu.cn/mongodb/yum/el7/RPMS/mongodb-mongosh-1.9.1.x86_64.rpm

连接到FerretDB
#

你可以使用 MongoDB 连接串,用任何语言的 MongoDB 驱动访问 FerretDB,这里以上面安装的 mongosh 命令行工具为例:

mongosh 'mongodb://dbuser_meta:DBUser.Meta@10.10.10.10:27017?authMechanism=PLAIN'mongosh 'mongodb://test:test@10.10.10.11:27017/test?authMechanism=PLAIN'

Pigsty 管理的 PostgreSQL 集群默认使用 scram-sha-256 作为默认的认证方式,因此,您必须使用 PLAIN 认证方式连接至 FerretDB。参阅 FerretDB:认证[17] 获取详细信息。

你也可以使用其他 PostgreSQL 用户来访问 FerretDB,只要在连接串中指定即可:

mongosh 'mongodb://dbuser_dba:DBUser.DBA@10.10.10.10:27017?authMechanism=PLAIN'

快速上手
#

你可以连接到 FerretDB 并假装它是一个 MongoDB 集群。

$ mongosh 'mongodb://dbuser_meta:DBUser.Meta@10.10.10.10:27017?authMechanism=PLAIN'

MongoDB 的命令会被翻译为SQL命令,在底下的 PostgreSQL 中执行:

use test                            # CREATE SCHEMA test;
db.dropDatabase()                   # DROP SCHEMA test;
db.createCollection('posts')        # CREATE TABLE posts(_data JSONB,...)
db.posts.insert({                   # INSERT INTO posts VALUES(...);
    title: 'Post One',body: 'Body of post one',category: 'News',tags: ['news', 'events'],
    user: {name: 'John Doe',status: 'author'},date: Date()}
)
db.posts.find().limit(2).pretty()   # SELECT * FROM posts LIMIT 2;
db.posts.createIndex({ title: 1 })  # CREATE INDEX ON posts(_data->>'title');

如果你不是很熟悉 MongoDB,这里有一个快速上手教程,同样适用于 FerretDB: Perform CRUD Operations with MongoDB Shell[18]

如果你希望生成一些样例负载,可以使用 mongosh 执行以下的简易测试剧本:

cat > benchmark.js <<'EOF'
const coll = "testColl";
const numDocs = 10000;

for (let i = 0; i < numDocs; i++) {  // insert
  db.getCollection(coll).insert({ num: i, name: "MongoDB Benchmark Test" });
}

for (let i = 0; i < numDocs; i++) {  // select
  db.getCollection(coll).find({ num: i });
}

for (let i = 0; i < numDocs; i++) {  // update
  db.getCollection(coll).update({ num: i }, { $set: { name: "Updated" } });
}

for (let i = 0; i < numDocs; i++) {  // delete
  db.getCollection(coll).deleteOne({ num: i });
}
EOF

mongosh 'mongodb://dbuser_meta:DBUser.Meta@10.10.10.10:27017?authMechanism=PLAIN' benchmark.js

你可以查阅 FerretDB 支持的 MongoDB命令,同时还有一些已知的区别,对于基本的使用来说,通常不是什么大问题。

  1. FerretDB uses the same protocol error names and codes, but the exact error messages may be different in some cases.
  2. FerretDB does not support NUL (\0) characters in strings.
  3. FerretDB does not support nested arrays.
  4. FerretDB converts -0 (negative zero) to 0 (positive zero).
  5. Document restrictions:
    • document keys must not contain . sign;
    • document keys must not start with $ sign;
    • document fields of double type must not contain Infinity, -Infinity, or NaN values.
  6. When insert command is called, insert documents must not have duplicate keys.
  7. Update command restrictions:
    • update operations producing Infinity, -Infinity, or NaN are not supported.
  8. Database and collection names restrictions:
    • name cannot start with the reserved prefix _ferretdb_;
    • database name must not include non-latin letters;
    • collection name must be valid UTF-8 characters;
  9. FerretDB offers the same validation rules for the scale parameter in both the collStats and dbStats commands. If an invalid scale value is provided in the dbStats command, the same error codes will be triggered as with the collStats command.

剧本
#

Pigsty 提供了一个内置的剧本: mongo.yml,用于在节点上安装 FerretDB 集群。

mongo.yml
#

该剧本由以下子任务组成:

  • mongo_check :检查 mongo 身份参数•mongo_dbsu :创建操作系统用户 mongod•mongo_install :安装 mongo/ferretdb RPM包•mongo_purge :清理现有 mongo/ferretdb 集群(默认不执行)•mongo_config :配置 mongo/ferretdb
  • mongo_cert :签发 mongo/ferretdb SSL证书
  • mongo_launch :启动 mongo/ferretdb 服务•mongo_register:将 mongo/ferretdb 注册到 Prometheus 监控中

监控
#

MONGO 模块提供了一个简单的监控面板:Mongo Overview

Mongo Overview
#

Mongo Overview: Mongo/FerretDB 集群概览

这个监控面板提供了关于 FerretDB 的基本监控指标,因为 FerretDB 底层使用了 PostgreSQL,所以更多的监控指标,还请参考 PostgreSQL 本身的监控。


参数
#

MONGO[24] 模块中提供了9个相关的配置参数,如下表所示:

参数类型级别注释
mongo_seqintImongo 实例号,必选身份参数
mongo_clusterstringCmongo 集群名,必选身份参数
mongo_pgurlpgurlC/Imongo/ferretdb 底层使用的 PGURL 连接串,必选
mongo_ssl_enabledboolCmongo/ferretdb 是否启用SSL?默认为 false
mongo_listenipCmongo 监听地址,默认留控则监听所有地址
mongo_portportCmongo 服务端口,默认使用 27017
mongo_ssl_portportCmongo TLS 监听端口,默认使用 27018
mongo_exporter_portportCmongo exporter 端口,默认使用 9216
mongo_extra_varsstringCMONGO 服务器额外环境变量,默认为空白字符串

相关文章

向量是新的 JSON
·5126 字·11 分钟
PostgreSQL 向量数据库 扩展
以向量为代表的功能将成为构建应用时的关键要素,正如历史上的JSON一样。而PostgreSQL再一次站在时代风口浪尖引领数据库潮流,在向量扩展的加持下稳拿AI时代的高速增长。
PostgreSQL:最成功的数据库
·8127 字·17 分钟
PostgreSQL PG生态
数据库终局已现,PostgreSQL 称王。PG在SF2023开发者调研中拿下大满贯,占住了 Linux 之于服务器操作系统的生态位。本文便来说一说,为什么 PostgreSQL 是最成功的数据库。
AI大模型与向量库 PGVector
·3658 字·8 分钟
PostgreSQL PG开发 扩展 向量
本文聚焦被 AI 炒火了的向量数据库,介绍了AI嵌入与向量存储检索的基本原理,并用一个具体的知识库检索案例来串联介绍向量数据库插件 PGVECTOR 的功能、性能、获取与应用。
TimescaleDB 快速上手
·9250 字·19 分钟
PostgreSQL PG管理 扩展
TimescaleDB是PostgreSQL的一个扩展插件,提供时序数据库的一些功能。
PostgreSQL 到底有多强?
·4779 字·10 分钟
PostgreSQL PG生态 性能
用性能数据说话,为什么PostgreSQL是世界上最先进的开源关系型数据库,暨世界上最成功的数据库。MySQL 和 PgSQL 性能谁好?分布式数据库到底怎么样?
为什么PostgreSQL是最成功的数据库?
·7148 字·15 分钟
PostgreSQL PG生态
数据库的用户是开发者,而开发者的意愿、喜好、选择又如何?总览 StackOverflow 过去六年的调研结果,不难看出在2022年,PostgreSQL 已经同时在这三项上登顶夺冠,成了字面意义上 “最成功的数据库”: