正如发布MongoDB 5.0时承诺的更快发布频率,年度大版本MongoDB 6.0也于2022年正式跟广大数据库爱好者们见面了。目前阿里云MongoDB已经完成了对6.0版本的适配工作,大家可以直接在官网控制台进行购买和尝鲜体验!
该版本的主要功能特性包括:
总结来看,MongoDB 6.0的新功能旨在促进开发和运营,消除数据孤岛,并消除因不必要地使用额外第三方技术而带来的业务复杂性。
作为从5.0发布时面向时序数据的全新功能,时序集合标志着MongoDB这一OLTP型数据库希望能处理好更多AP型场景的决心,官方对时序集合的支持也一直保持着高速的更新&改进频率。比如为了支持更好分布数据而在5.1引入的分片(sharding)、为了改善存储空间占用而在5.2引入的列式压缩(columnar compression)以及为了支持部分数据点缺失情况下的时序分析而在5.3引入的密集化和间隙填充(densification and gap-filling)
另外,时序集合的索引方面也有增强。从6.0开始,为了提高读取性能,时序集合现在包括测量的二级和复合索引。时序数据也开始和空间维度进一步结合形成时空数据,时序结合开始支持地理位置索引(geo-indexing)。通过将地理信息附加到时间序列数据,开发人员可以更好地分析涉及举例和位置的场景。比如跟踪夏日冷链运输车的温度变化情况以及监测特定航线上的货运船燃料消耗等。
性能方面也有一些优化,主要针对的是查询以及排序场景。比如MongoDB可以更快返回时序数据中的最后一个数据点("last point" query),而不再需要扫描整个集合以后才得到想要的数据;通过在时间以及元数据字段上的聚簇索引(clustered index)以及二级索引(secondary index)能够更高效地完成排序操作。
作为支持CDC的核心功能之一,Change Stream迎来了自MongoDB 3.6发布以来的一次重大更新。有了Change Stream,业务可以更容易地实时获取数据库的变更,并基于此构建各种事件驱动型的应用或系统,不再需要依赖其他的数据同步中间件。
看新特性之前让我们先看下之前版本里有关Change Stream功能的更新历史:
在这次的MongoDB 6.0版本里。对Change Stream的更新包括:
在之前,客户端只能通过change events获取文档变更后的状态,现在也能支持获取变更前的状态了。这使得一些同时需要变更前&变更后的下游系统(用作校对或审计)能够充分利用数据库原生的能力而无需自行在业务层面耦合。更灵活的功能形态将大大扩展changeStream未来的使用场景。与此同时,支持更多的DDL操作也使得Change Stream的应用场景限制变得更少,不再会遇到经常中断后需要resume的情况。之前的使用场景中,分片集群需要mongos做merge,导致mongos成为整个changeStream的瓶颈点,性能也不够理想;这次从框架层面的优化以及部分场景下的stage下推带来的性能提升值得期待。
总而言之,这次大版本的功能升级也是对用户广泛诉求(SERVER-36941以及SERVER-46414)的积极响应,表明了MongoDB对数据库使用者体验上的关注。
数据安全正在肉眼可见地变得越来越重要。已有的传输加密或者静态加密手段没办法实现在使用过程中的加密,这使得更复杂的加密和更方便的查询看起来是背道相驰的事情。MongoDB 6.0推出的可查询加密可以允许用户从客户端加密敏感数据,将其作为完全随机的加密数据存储在数据库服务器端,并对加密数据直接进行丰富的查询。
从下面的示例中可以看到只有客户端能看到敏感信息的明文,在query到达server时会同时包含从KMS获取的加密秘钥,然后在server端以密文进行查询并返回,最后在客户端用驱动利用密钥解密后以明文呈现。
其特点&优势包括:
● 从客户端加密敏感数据,只有客户端拥有加密密钥。
● 数据在整个生命周期(传输、存储、使用、审计或备份)中都是加密的。
● 客户端可以直接对加密数据进行丰富的查询(等值匹配、范围、前后缀、子字符串等查询类型)。
● 强大的数据隐私保护能力,只有能访问客户端应用程序和加密密钥的授权用户才能看到明文数据。
● 更轻量化的应用程序开发,涉及敏感数据的开发者无需考虑太多安全、合规的事情,数据库直接提供综合加密解决方案。
● 降低敏感数据上云的安全顾虑。
值得一提的是,可查询加密功能依然是预览(Preview)版本,不建议直接在生产环境使用。社区版不支持客户端字段级加密(Client-Slide Field Level Encryption)的自动加密,可以使用显示加密(需要使用驱动的加密库lib)。
MongoDB的聚合功能允许用户处理多个文档并返回计算结果。通过将多个操作符组合到聚合管道中,用户可以构建出足够复杂的数据处理管道以提取数据并进行分析。MongoDB 6.0持续在聚合功能上深耕,带来了一些新的功能以及优化,包括:
新增了一些查询操作符的支持。比如$maxN、$topN、$minN、$bottomN、$lastN、$sortArrary等。主要目的是利用操作符算子将更多的计算从业务中下沉到数据库中,使得业务层更加轻量化。这些$xxxN可以看做对原本$min/$max/$last操作符的补充,用户可以视实际业务场景中需要返回一个或者多个结果来使用不同的操作符。以$maxN为例,其既可以被使用在数组中,也可以集成进聚合语句的管道中。
# 用作arrary中
db.scores.insertMany([
{ "playerId" : 1, "score" : [ 1, 2, 3 ] },
{ "playerId" : 2, "score" : [ 12, 90, 7, 89, 8 ] },
{ "playerId" : 3, "score" : [ null ] },
{ "playerId" : 4, "score" : [ ] }
{ "playerId" : 5, "score" : [ 1293, "2", 3489, 9 ]}
])
# 给每个文档增加新的字段,保留最大的2个分数
db.scores.aggregate([
{ $addFields: { maxScores: { $maxN: { n: 2, input: "$score" } } } }
])
# 用在聚合pipeline中
db.gamescores.insertMany([
{ playerId: "PlayerA", gameId: "G1", score: 31 },
{ playerId: "PlayerB", gameId: "G1", score: 33 },
{ playerId: "PlayerC", gameId: "G1", score: 99 },
{ playerId: "PlayerD", gameId: "G1", score: 1 },
{ playerId: "PlayerA", gameId: "G2", score: 10 },
{ playerId: "PlayerB", gameId: "G2", score: 14 },
{ playerId: "PlayerC", gameId: "G2", score: 66 },
{ playerId: "PlayerD", gameId: "G2", score: 80 }
])
# 找到单个游戏的3个高分
db.gamescores.aggregate( [
{$match : { gameId : "G1" }},
{
$group:
{
_id: "$gameId",
maxThreeScores:
{$maxN:{input: ["$score","$playerId"],n:3}}
}
}
] )
$maxN和$topN看起来有些重复,实则各有不同的使用场景。topN会返回排序后的结果,而maxN则并不依赖特定的排序规则。
$sortArrary则强化了数组内是若干子对象场景下的排序,用户可以指定任意一个子文档内的字段、嵌套字段或者复合字段来按需进行数组的排序。该操作符可以有效简化部分带数组排序的复合聚合查询。
db.engineers.insertOne(
{"team":
[
{"name": "pat","age": 30,"address": { "street": "12 Baker St", "city": "London" }},
{"name": "dallas","age": 36,"address": { "street": "12 Cowper St", "city": "Palo Alto" }},
{"name": "charlie","age": 42,"address": { "street": "12 French St", "city": "New Brunswick" }}
]
}
)
# 多种查询方式
db.engineers.aggregate( [
{ $project:{_id: 0,result:{$sortArray: { input: "$team", sortBy: { name: 1 } }}}}
] )
db.engineers.aggregate( [
{ $project:{_id: 0,result:{$sortArray: { input: "$team", sortBy: { age: -1, name: 1 } }}}}
] )
db.engineers.aggregate( [
{ $project:{_id: 0,result:{$sortArray: { input: "$team", sortBy: { "address.city": -1 }}}}
] )
更多细节请查阅相关查询操作符的官方文档。
初始化同步(initial sync)用于节点刚加入副本集时的数据同步阶段。这一阶段因性能差一直被诟病。在6.0官方通过支持基于文件拷贝的初始化同步模式,将同步的性能提升了4倍左右。不过目前仅企业版支持此功能。
水平伸缩方面,MongoDB 6.0在分片上做出了重大改进。将原本默认是64MB的chunk size调整成为了128MB,更大的数据块,意味着更少的数据迁移频率以及更低的网络及路由层开销。做出这样的调整应该也是观察到了广泛客户在分片集群上部署海量数据时遭遇到的chunk数量瓶颈及性能问题。为了避免一个全局参数过于武断,MongoDB 6.0也支持了configureCollectionBalancing命令,可以为不同的分片表设置不同的chunk size。比如数据规模特别大的分片表,将chunk size调整到256MB;数据规模相对较小但希望在shard上分布更均匀的表,将chunk size调整到64或32MB。
与此同时,该命令还允许对集合进行主动的碎片整理。相较于compact命令提供了更好的碎片整理服务,有效减少磁盘空间占用。
db.adminCommand(
{
configureCollectionBalancing: "<collection>",
chunkSize: <num>,
defragmentCollection: <bool>
}
)
下面的图里展示了整个MongoDB产品的安全功能矩阵。除了前面提到的全新特性:queryable enryption,本次发布的MongoDB 6.0也带来了其他安全性增强。
客户端字段级加密(CSFLE, client-side field-level encryption)自19年发布以来就被广泛应用于敏感数据的管理中,尤其是在将数据迁移到公有云的场景下。MongoDB6.0的CSFLE将支持任何符合KMIP(Key Management Interoperability Protocol)的密钥管理提供商。作为领先的行业标准,KMIP优化了加密对象(如加密密钥、证书等)的存储、操作和处理,使得整个流程更加规范化。这也标志着,除了基于keyfile的本地秘钥管理外,mongoDB也支持通过KMIP将自己与第三方秘钥管理设备集成,为用户提供更安全的保障。
此外,MongoDB 6.0允许对审计日志加密。审计日志中也可能包含了重要信息,可以被压缩和加密后写入磁盘,并且在审计日志的传播过程中依然保持加密。
此加密功能仅适用于使用WT引擎的企业版本,当然Atlas也是默认开启加密的。
无论是数据的同构同步(mongo-to-mongo)还是异构同步(others-to-mongo& mongo-to-others)都是mongoDB生态中的一部分,官方在mongoimport/mongoexport/mongodump/mongorestore的工具矩阵中一直没有很好得规划关于『数据同步』这一部分的生态位,因此MongoDB的数据同步也呈现出了百花齐放的形态,包括早期的connector、MongoShake、云服务提供商的DTS服务以及部分创业公司的商业化产品。
伴随着MongoDB 6.0的发布,官方的同步工具mongosync也终于面世。它能提供跨任何环境的两个 MongoDB 集群的连续、单向数据同步,无论是混合环境、Atlas、本地还是边缘环境。用户还可以实时控制和监控整个同步过程,按需启动、停止、恢复甚至反转同步。
集群内的数据同步由副本集和sharding完成,Cluster-to-Cluster Sync希望能解决集群间的同步问题,主要覆盖以下场景:
使用方式也与其他数据同步工具并无差异:1)准备好源和目标集群;2)部署mongosync;3)按需启动同步;4)全量同步完成后,增量数据也会同步;5)利用common endpoint来终止同步关系。
遗憾的是,Cluster-to-Cluster Sync仅与在MongoDB6.0以上版本运行的源和目标集群兼容。这也意味着广泛使用的其他低版本仍然要依赖之前的第三方同步工具来完成上面提到的数据迁移/同步场景。
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。