聊聊KingbaseES V9的MongoDB兼容版:到底怎么个平替法?
最近一段时间,我一直在帮几个项目做数据库层面的国产化替换工作。大家原来用MongoDB用得其实挺顺手的。存JSON文档,结构灵活,开发起来快。但是现在的情况是,很多单位都有替换的要求。那换个什么呢?这是个问题。如果直接换成某个独立的文档数据库,往往又会面临安全认证过不去的情况。也就是在这个时候,我看到了KES出的这个KingbaseES V9 MongoDB兼容版。今天这篇文章,我就结合平时的实际经验,还有他们发出来的产品资料,跟大家仔细扒一扒这个东西到底是怎么实现的,能不能直接用在我们的项目里。
一、先搞清楚现在的多模数据处理到底遇到了什么麻烦
其实很多时候,我们并不是非要换数据库。老的架构用久了,问题确实会慢慢冒出来。特别是当业务越来越复杂的时候。
1.1 老架构的那些坑
大家回想一下自己公司的系统架构。往往是这个业务线用一套MySQL,那个业务线搞一个MongoDB,旁边可能还放着一个Redis。这就形成了一个个独立的系统。大家管这个叫“烟囱式”架构。这种架构最大的问题是什么呢?数据分散。你想要把关系数据和文档数据关联起来查一下,非常麻烦。往往仅仅只是拉通两个库的数据,就要写一堆同步脚本。数据对不上的情况经常发生。信息滞后,不一致。接着就是开发周期变长。每接一个新需求,可能就要引入新的技术栈。学习成本高不说,后面运维的人也头疼。
1.2 技术栈太多导致的问题
技术栈一旦多起来,最直接的感受就是人力成本变高了。招人的时候,得会这个又会那个。系统间的交互协作成本也是直线上升。有时候重复建设,重复投资的情况特别严重。每个库独立部署,资源利用率其实很低。那么怎么解决这些问题呢?思路其实很简单,就是把能合并的东西合并到一起。
二、KES V9整体架构是个啥情况
为了解决上面说的这些麻烦,KES V9这个版本里,其实做了一个很大的调整。他们搞了一个一体化架构。我画了个简单的图,大家看一眼。
2.1 一体化架构的思路
你看这个图里的结构。最上面是应用层。你可以用原来的MongoDB驱动连过来。也可以用KES自己的驱动连过来。到了网络层之后,往下走就是协议层。这里它开了两个端口,一个是27017,这是MongoDB默认的端口。另一个是54321,这是KES自己的端口。
再往下看,语法层这里放了各种解析器。有MongoDB-parser,也有Oracle-parser、PGSQL-parser。这些解析器把不同的语法解析完之后,统一交给协议调度去处理。最后落到存储层的时候,不管是文档数据、关系数据还是向量数据,全都放在一个库里面存着。
2.2 MongoDB兼容版在这个架构里的位置
那么这个MongoDB兼容版处在什么位置呢?其实就是图里MongoDB-parser加上27017端口这一条路。它并不是单独起了一个新的数据库进程。而是直接在KES的实例里面,加了一层协议的转换。这样做的好处是很明显的。你不需要再去维护一套独立的文档数据库了。技术栈直接收敛到了KES这一个产品上。对于企业层级里的应用来说,管理起来轻松了很多。
三、KES MongoDB兼容版的几个关键点
我看资料的时候,发现他们重点提了三个词。自主研发无风险、产品统一原生兼容、纵深防御更高安全。我给大家翻译成大白话。
3.1 为什么不单独搞个文档库而是做兼容版
现在有些厂商是单独拿一个开源的文档数据库去包装。但是这里面有个合规的风险。目前的安全名录里面,其实没有单独的“缓存库”或者“文档库”这个品类去进行测试和认证。你用了这类产品,后面验收的时候可能会扯皮。KES本身是拿到了最高安全认证的。它把文档处理做成内置能力,那你就没有二次改造的风险了。
再一个就是安全方面。原来用MongoDB,安全防护措施往往仅仅只是做个权限控制。但是KES这边,是从访问控制、身份鉴别,到传输安全、存储安全,再到事后的安全审计,是一套完整的机制。这点在政企客户那里是非常看重的。
3.2 原生协议到底是怎么兼容的
这是我最关心的一点。它说支持MongoDB原生协议兼容,支持零代码平替。底层到底是怎么搞的呢?
其实KES底层还是基于PostgreSQL内核做的。PostgreSQL本身就有很强的自定义类型能力。KES就是利用了这一点。它在底层建了一种类型来存BSON数据。
我们来看一段MongoDB的插入操作代码。
db.products.insertMany([...{item:"card", qty:15},...{item:"envelope", qty:20},...{item:"stamps", qty:30}...]);你在客户端敲下这段代码,通过27017端口发出去。KES接收到之后,它会把MongoDB的数据转为关系表的数据。也就是说,你在MongoDB里看到的collection,在KES底层其实就是一张表。文档就是表里的一行。那个_id字段,比如{ "$oid" : "6840285d64289defb9c1c18c" },会自动创建一个B-TREE索引。如果你执行db.products.createIndex({"item":1}),它底层其实是给item字段建了一个RUM索引。
这样处理的话,应用层只需要改一下连接串的IP和端口。代码“零”修改。这就是它说的全栈兼容的文档数据库平替。
四、具体能用到哪些命令和操作符
光说原理不行,平时干活靠的是具体的命令。我对照着资料里的清单,给大家捋一捋。
4.1 常用的CRUD和统计操作
大家平时用的最多的就是增删改查。从资料里的对比表来看,这些接口KES全支持。
比如插入数据,db.collection.insertOne和db.collection.insertMany都是支持的。查询文档的话,db.collection.find和db.collection.findOne也没问题。更新和删除的那些updateOne、deleteMany之类的,全都有。
统计操作也是一样。db.collection.count、db.collection.distinct、db.collection.dataSize这些平时用来查状态、算数量的命令,也都支持。
4.2 查询、更新操作符的支持情况
操作符不是单独的命令。它是写在查询条件里的。这个支持度怎么样呢?我拉了几个常用的看看。
对比查询操作符有32个,KES支持了31个,支持率96.88%。像$eq、$gt、$in、$lt这些对比的,全支持。逻辑操作符$and、$or、$not、$nor,全支持。元素判断的$exists、$type,也支持。求值的$mod、$regex、$expr、$jsonSchema,同样支持。
再看看更新操作符。这个是22个全支持,100%。什么$set改字段值,$inc加数字,$min、$max取极值,$unset删字段。数组操作的那些$push、$pull、$addToSet、$pop,也全都有。
投影操作符3个,100%支持。比如$slice限制返回数组元素的数量,这个很常用。
4.3 聚合管道的支持度
聚合管道这块稍微复杂一点。命令支持率是100%。聚合管道阶段有38个,支持了32个,支持率84.21%。聚合管道操作符有169个,支持了167个,支持率98.82%。
也就是说,你平时写的大部分聚合查询,直接拿过来跑是没问题的。比如$group、$match、$project这些阶段,以及里面的$sum、$avg这些操作符。
那么有哪些是不支持的呢?比如“查询计划缓存”相关的4个命令,支持率是0%。“角色管理”相关的10个命令,在MongoDB兼容接口这里也是0%。但是注意了,资料里也说了,KES本身是带角色管理功能的。只是它没有去兼容MongoDB那套角色管理的命令语法。你可以通过KES自己的管理工具去建角色。这个其实无伤大雅。
五、性能到底差多少
大家肯定要问,套了一层壳,性能会不会拉胯?资料里给了一组实测数据,我直接贴出来,大家自己看。
5.1 1万条数据量的情况
| 数据库 | 数据量 | INSERT(ms)全表数据 | UPDATE(ms)全表数据 | SELECT(ms)全表数据 | SELECT(ms)全表单个字段 | SELECT(ms)标量查询 | SELECT(ms)范围查询 |
|---|---|---|---|---|---|---|---|
| MongoDB | 1万条数据 | 100 | 35 | 24 | 10 | 4 | 4 |
| kingbaseES with nativeAPI | 1万条数据 | 144 | 52 | 38 | 20 | 6 | 11 |
5.2 10万条数据量的情况
| 数据库 | 数据量 | INSERT(ms)全表数据 | UPDATE(ms)全表数据 | SELECT(ms)全表数据 | SELECT(ms)全表单个字段 | SELECT(ms)标量查询 | SELECT(ms)范围查询 |
|---|---|---|---|---|---|---|---|
| MongoDB | 10万条数据 | 395 | 328 | 78 | 63 | 27 | 28 |
| kingbaseES with nativeAPI | 10万条数据 | 473 | 543 | 186 | 159 | 40 | 49 |
5.3 100万条数据量的情况
| 数据库 | 数据量 | INSERT(ms)全表数据 | UPDATE(ms)全表数据 | SELECT(ms)全表数据 | SELECT(ms)全表单个字段 | SELECT(ms)标量查询 | SELECT(ms)范围查询 |
|---|---|---|---|---|---|---|---|
| MongoDB | 100万条数据 | 2275 | 3083 | 2087 | 365 | 174 | 228 |
| kingbaseES with nativeAPI | 100万条数据 | 3498 | 6413 | 3320 | 1332 | 270 | 558 |
5.4 怎么看待这个性能差距
看完这三张表,结论很明显。KES的MongoDB兼容版在性能上,跟原生的MongoDB比,确实是有差距的。数据量越大,差距越明显。
比如在100万条数据的时候,全表UPDATE的操作,MongoDB是3083毫秒,KES是6413毫秒,差了一倍左右。标量查询也差了大概三四倍。
那这个情况能接受吗?我觉得要分场景看。如果你的业务是那种极高并发的、纯缓存性质的读写,可能确实会有压力。但是对于一般的企业层级里的应用来说,大部分表的数据量可能也就停留在十万级以内。在这个量级下,比如10万条数据,标量查询差了十几毫秒,范围查询差了二十毫秒。这个延迟在业务层面往往是感知不到的。
而且你要想到,你换来的是什么呢?换来的是不用维护两套数据库。换来的是通过了安全认证。换来的是可以在同一个库里用SQL直接关联你的文档数据和关系数据。这个账,不同项目得自己算。
六、真要从MongoDB迁过来,要怎么做
如果评估下来觉得可以搞,那下一步就是怎么迁了。这里不涉及数据迁移工具的讨论,单纯看怎么把KES实例配成一个能接MongoDB请求的状态。步骤其实不多,但是每一步都很关键。
6.1 初始化实例的时候要注意什么
第一步是初始化数据库。这里有一个坑要注意。执行initdb的时候,必须加上-m参数,指定为兼容pg模式。同时还要指定默认用户,一般是-U system。如果不加这个参数,后面再想改就麻烦了。
6.2 改配置项的那些事
初始化完之后,就要去改配置文件了。配置文件是kingbase.conf。你需要改下面这几个参数。
enable_protocol_compat=onextension_protocol_port=27017documentdb_core.bsonUseEJson=on我解释一下这几个参数是干嘛的。enable_protocol_compat=on,这个一看就知道,是把协议兼容的功能打开。extension_protocol_port=27017,这是指定兼容协议监听的端口。MongoDB默认就是27017,你写这个的话,应用那边基本就不用改连接端口了。documentdb_core.bsonUseEJson=on,这个是让BSON类型使用扩展JSON的格式。因为底层的PG对JSON处理有自己的方式,开这个能保证数据解析不出错。
除了这三个,还有一个很重要的。就是在shared_preload_libraries这一项的后面,要追加三个东西。
kdb_cron,kdb_documentdb_core,kdb_documentdb这是预加载的动态库。你必须把这三个写进去,数据库在启动的时候才会把MongoDB兼容的核心组件加载到内存里。改完这些,重启数据库服务。
6.3 建插件和连上去的步骤
重启完之后,就可以进数据库里建插件了。你用ksql工具连上去,连的是54321那个原生端口。
ksql –Usystem-p54321dbname进去之后,执行建插件的命令。
create extension documentdb cascade;这里有个cascade参数。意思是把它依赖的那些插件也一起建了。省得你一个一个去建。
接着,你要给system用户设个密码。因为MongoDB连接的时候需要认证。
alter user system with password'123456';做完这些,KingbaseES数据库就处于兼容mongodb模式了。这个时候,你拿出mongosh客户端,直接连就行。连接串是这样的。
mongosh"mongodb://system:123456@127.0.0.1:27017/dbname?maxPoolSize=1&directConnection=true&authMechanism=SCRAM-SHA-256"你看这个连接串,IP是127.0.0.1,端口是27017,认证机制是SCRAM-SHA-256。这跟连一个真正的MongoDB没有任何区别。你连上之后,敲db.collection.find(),就能把刚才建的表里的数据查出来。
总结
其实写到这里,大家应该对KES V9的MongoDB兼容版有个清晰的认识了。它不是一个重新造轮子的文档数据库。它是站在KES成熟的关系型数据库底座上,通过协议解析转换,硬生生抠出来的一套MongoDB兼容层。
这种做法的好处是稳。因为底层的存储、事务、备份恢复,全都是KES原来那套经过多年验证的东西。你不用去担心一个新的文档库在数据可靠性上出什么幺蛾子。
缺点也有。就是性能上面,毕竟多了一层转换,跟原生的比肯定有损耗。聚合管道和一些偏门的管理命令也没有做到100%覆盖。
但是回到我们最开始说的那个问题。很多项目现在要的是合规,要的是减少技术栈,要的是能过验收。在这个前提下,KES的MongoDB兼容版提供了一条非常直接的路径。你改个连接串,把应用跑起来,测试通过,这就完事了。对于一线干活的兄弟们来说,这其实就是一个很实在的平替方案。大家如果在项目里也遇到类似的需求,不妨拿个测试环境搭一下跑跑看,毕竟实践出真知嘛。