碎碎念[5] 吐槽 FerretDB

系列文章:

开篇废话

再不写点东西博客就长草了
这几天在和群友聊天吹水的时候吐槽了以 SSPL 许可证的奇妙项目,然后想起来了 MongoDB ,然后知道了 FerretDB 这种奇怪的东西。
这边有个更详细一点的介绍:

可以先看看。

总的来说就是 FerretDB 实际上不是个数据库,只是个兼容 MongoDB 协议的 Mapper 也就是转换层,后端可以接 PostgreSQL 亦或者 SQLite

当然对于原来的陈年 💩 山项目来说,什么都不动是最好的,这里只是想试试。

然后看到标题的你肯定知道,这次迁移尝试肯定是不尽人意的,这里就介绍下迁移过程以及坑,兼 MongoDB 如何 dump 以及 restore 的相关教程。

评价就是没活了不要乱动老项目。

安装 & 配置

这里我使用了 NixOS 其他发行版自行寻找教程,这里略过,直接参考官方文档即可:

https://docs.ferretdb.io/quickstart-guide/

postgresql

在 NixOS 配置是这样的,您使用其它发行版的话把 settings 部分理解成环境变量即可:

services.ferretdb = {
  enable = true;
  settings = {
    FERRETDB_LOG_LEVEL = "error";
    FERRETDB_HANDLER = "pg";
    FERRETDB_POSTGRESQL_URL = "postgres://ferretdb-empty@127.0.0.1:5432/ferretdb";
    FERRETDB_LISTEN_ADDR = "0.0.0.0:27017";
    DO_NOT_TRACK = "true";
    FERRETDB_DEBUG_ADDR = "-";
  };
};

这里第一个比较奇怪的点是看上去一定要有一个公开的数据库的样子?


参考官方鉴权部分:
https://docs.ferretdb.io/security/authentication/ 这里使用了 ferretdb-empty 为默认公开访问的

CREATE DATABASE 'ferretdb-empty';
CREATE USER ferretdb-empty WITH PASSWORD '';
GRANT ALL PRIVILEGES ON DATABASE ferretdb-empty TO ferretdb-empty;
CREATE DATABASE 'ferretdb';
CREATE USER ferretdb WITH PASSWORD '';
GRANT ALL PRIVILEGES ON DATABASE ferretdb TO ferretdb;

当然其他权限配置的话,比如 hda 文件就根据自己的情况修改了。

sqlite

最简配置为:

services.ferretdb.enable = true;

这样就使用 sqlite 后端,但还是有遥测,需要 DO_NOT_TRACK 参数去除此遥测。

导出导入

这里相对于官方少了一个章节,评估情况 我的评价是忽略此部分直接测就可以,有兴趣的话可以参考:
https://docs.ferretdb.io/migration/premigration-testing/

导出

这里使用 mongodump 导出,建议不要加 --gzip

mongodump

如果有认证:

mongorestore --uri='mongodb://user:pass@192.168.6.147:27017/

请注意这里需要 --url='' 用空格的话 MongoDB 系列工具应该都是不认的!(我在这里卡了好久)

导入

在这一步就感觉很翻车了,大概 70 万量级的数据导入了接近 30 分钟,还遇到了整个表导入失败的场景。

mongorestore --uri="FerretDB的 URL"

即可导入,导入后 psql 画风是这个样子的:

overview-1 单 json 结构可还行,我认为的画风应该至少把根节点平铺成对应结构才对。

overview-2 然后索引也有(不得不佩服 psql 的强大,就这样还能加索引)

htop 迁移过程中 cpu 占用参考,cpu 为 Ryzen 2600 + 6G RAM

NaN

这里碰到了 NaN 数据导致整个表都导入不进去的情况,如果有遇到整个表都导入不进去的情况,可以搜索一下是不是 NaN 导致的:
NaN data

我是报错日志从头看到尾找到了独特的错误然后猜测出来的,具体错误内容这里没有记录,一开始以为是 bigint 导致的(id 部分有 int 有 bigint 担心不能正确判断)

在这里可以看到官方已知不同情况:
https://docs.ferretdb.io/diff/

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.

也就是 +-Infinity 也不行(这个理论上是 psql 的限制,加了 NaN inf 后不是标准的 json 了)

翻车

导入数据格式和导入慢都是小事情,接下来才是让我还没开始用就弃坑的东西。
一开始是以为 mongodb 的 client 版本太低,升级到了 6.5.0 还是这个样子:

  MongoServerError: `aggregate` stage "$sample" is not implemented yet
      at Connection.sendCommand (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cmap/connection.js:281:27)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async Connection.command (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cmap/connection.js:304:26)
      at async Server.command (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/sdam/server.js:169:24)
      at async executeOperation (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/operations/execute_operation.js:126:16)
      at async AggregationCursor._initialize (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cursor/aggregation_cursor.js:46:26)
      at async [kInit] (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cursor/abstract_cursor.js:454:27)
      at async next (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cursor/abstract_cursor.js:514:13)
      at async [Symbol.asyncIterator] (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cursor/abstract_cursor.js:160:34)
      at async AggregationCursor.toArray (/xxx/node_modules/.pnpm/mongodb@6.5.0/node_modules/mongodb/lib/cursor/abstract_cursor.js:273:26)

也就是说到现在还是不支持 .aggregate 用法,这相当于 MongoDB 的精髓没有抄到的那种感觉,也就是不是 1:1 兼容,去搜索 issue 发现这个是 2022 年的东西,到现在都还没支持(2.0 版本的目标)
https://github.com/FerretDB/FerretDB/issues/1435 issue

其他增删改查看上去是没有问题的,但是看上去这么灵我已经不敢继续用了。

总结

上一次吐槽类似项目好像是 Caddy 这次又遇到了个奇奇怪怪的项目,这个也让我深刻理解了能用就不要动依赖了的精髓。
特别是近几年兴起的重写东西,稍微一不留神就是个更大的坑等着我们。
^ 因此本文的链接是和 caddy 一个系列的

最后就是至少学习了 psql 的基本权限相关的,大概不亏?