MongoDB 在往年正式公布了新的 4.4 大版本,这次的公布蕴含泛滥的加强 Feature,能够称之为是一个维护性的版本,而且是一个用户期待已久的维护性版本,MongoDB 官网也把这次公布称为「User-Driven Engineering」,阐明新版本次要是针对用户呼声最高的一些痛点,重点进行了改良。
而阿里云作为 MongoDB 官网的全球战略合作伙伴,也行将全网独家上线 4.4 新版本,上面就由阿里云 MongoDB 团队的工程师针对一些用户关注度比拟高的 Feature,进行深度解读。
可用性和容错性加强
Mirrored Reads
在服务阿里云 MongoDB 客户的过程中,笔者察看到有很多的客户尽管购买的是三节点的正本集,然而理论在应用过程中读写都是在 Primary 节点,其中一个可见的 Secondary 并未承载任何的读流量。
那么在偶然的宕机切换之后,客户能显著的感触到业务的拜访提早会有抖动,通过一段时间后才会复原到之前的程度,抖动起因就在于,新选举出的主库之前从未提供过读服务,并不理解业务的拜访特色,没有针对性的对数据做缓存,所以在忽然提供服务后,读操作会呈现大量的「Cache Miss」,须要从磁盘从新加载数据,造成拜访提早回升。在大内存实例的状况下,这个问题更为显著。
在 4.4 中,MongoDB 针对上述问题实现了「Mirrored Reads」性能,即,主库会按肯定的比例把读流量复制到备库上执行,来帮忙备库预热缓存。这个执行是一个「Fire and Forgot」的行为,不会对主库的性能产生任何实质性的影响,然而备库负载会有肯定水平的回升。
流量复制的比例是可动静配置的,通过 mirrorReads 参数设置,默认复制 1% 的流量。
此外,能够通过 db.serverStatus({ mirroredReads: 1} )来查看 Mirrored Reads 相干的统计信息,
Resumable Initial Sync
在 4.4 之前的版本中,如果备库在做全量同步,呈现网络抖动而导致连贯闪断,那么备库是须要重头开始全量同步的,导致之前的工作全副徒劳,这个状况在数据量比拟大时,比方 TB 级别,更加让人解体。
而在 4.4 中,MongoDB 提供了,因网络异样导致全量同步中断状况下,从中断地位复原全量同步的能力。在尝试复原一段时间后,如果依然不胜利,那么会从新抉择一个同步源进行新的全量同步。这个尝试的超时工夫默认是 24 小时,能够通过 replication.initialSyncTransientErrorRetryPeriodSeconds 在过程启动时更改。
须要留神的是,对于全量同步过程中遇到的非网络异样导致的中断,依然须要从新发动全量同步。
Time-Based Oplog Retention
咱们晓得,MongoDB 中的 Oplog 汇合记录了所有的数据变更操作,除了用于复制,还可用于增量备份,数据迁徙,数据订阅等场景,是 MongoDB 数据生态的重要基础设施。
Oplog 是作为 Capped Collection 来实现的,尽管从 3.6 开始,MongoDB 反对通过 replSetResizeOplog 命令动静批改 Oplog 汇合的大小,然而大小往往并不能精确反映上游对 Oplog 增量数据的需要,思考如下场景,
• 打算在凌晨的 2 – 4 点对某个 Secondary 节点进行停机保护,应防止上游 Oplog 被清理而触发全量同步。
• 上游的数据订阅组件可能会因为一些异常情况而进行服务,然而最慢会在 3 个小时之内复原服务并持续进行增量拉取,也该当防止上游的增量缺失。
所以,在实在的利用场景下,很多时候是须要保留最近一个时间段内的 Oplog,这个时间段内产生多少的 Oplog 往往是很难确定的。
在 4.4 中,MongoDB 反对 storage.oplogMinRetentionHours 参数定义起码保留的 Oplog 时长,也能够通过 replSetResizeOplog 命令在线批改这个值,如下,
扩展性和性能加强
Hidden Indexes
Hidden Index 是阿里云 MongoDB 和 MongoDB 官网达成策略单干后共建的一个 Feature。咱们都晓得数据库保护太多的索引会导致写性能的降落,然而往往业务上的复杂性决定了运维 MongoDB 的同学不敢轻易的删除一个潜在的低效率索引,放心谬误的删除会带来业务性能的抖动,而重建索引往往代价也十分大。
Hidden Index 正是为了解决 DBA 同学面临的上述窘境,它反对通过 collMod 命令对现有的索引进行暗藏,保障后续的 Query 都不会利用到该索引,在察看一段时间后,确定业务没有异样,能够释怀的删除该索引。
须要留神的是,索引被暗藏之后只是对 MongoDB 的执行打算器不可见,并不会扭转索引自身的一些非凡行为,比方惟一键束缚,TTL 淘汰等。
索引在暗藏期间,如果新的写入,也是会被更新的,所以也能够通过勾销暗藏,很不便的让索引立即变的可用。
Refinable Shard Keys
当应用 MongoDB 分片集群时,置信大家都晓得抉择一个好的 Shard key 是如许的重要,因为它决定了分片集群在指定的 Workload 下是否有良好的扩展性。然而在理论应用 MongoDB 的过程中,即便咱们当时认真斟酌了要抉择的 Shard Key,也会因为 Workload 的变动而导致呈现 Jumbo Chunk,或者业务流量都打向繁多 Shard 的状况。
在 4.0 及之前的版本中,汇合选定的 Shard Key 及其对应的 Value 都是不能更改的,在 4.2 版本,尽管能够批改 Shard Key 的 Value,然而数据的跨 Shard 迁徙以及基于分布式事务的实现机制导致性能开销很大,而且并不能齐全解决 Jumbo Chunk 或拜访热点的问题。比方,当初有一个订单表,Shard Key 为 {customer_id:1},在业务初期每个客户不会有很多的订单,这样的 Shard Key 齐全能够满足需要,然而随着业务的倒退,某个大客户累积的订单越来越多,进而对这个客户订单的拜访成为某个繁多 Shard 的热点,因为订单和 customer_id 人造的关联关系,批改 customer_id 并不能改善拜访不均的状况。
针对上述相似场景,在 4.4 中,你能够通过 refineCollectionShardKey 命令给现有的 Shard Key 减少一个或多个 Suffix Field 来改善现有的文档在 Chunk 上的散布问题。比方,在下面形容的订单业务场景中,通过 refineCollectionShardKey 命令把 Shard key 更改为{customer_id:1, order_id:1},即可防止繁多 Shard 上的拜访热点问题。
须要理解的是,refineCollectionShardKey 命令性能开销非常低,只是更改 Config Server 上的元数据,不须要任何模式的数据迁徙(因为单纯的增加 Suffix 并不会扭转数据在现有 chunk 上的散布),数据的打散依然是在后续失常的 Chunk 主动决裂和迁徙的流程中逐渐进行的。此外,Shard Key 须要有对应的 Index 来撑持,所以 refineCollectionShardKey 要求提前创立新 Shard Key 对应的 Index。
因为并不是所有的文档都存在新增的 Suffix Field(s),所以在 4.4 中实际上隐含反对了「Missing Shard Key」的性能,即新插入的文档能够不蕴含指定的 Shard Key Field。然而,笔者不倡议这么做,很容易产生 Jumbo Chunk。
Compound Hashed Shard Keys
在 4.4 之前的版本中,只能指定单字段的哈希片键,起因是此时 MongoDB 不反对复合哈希索引,这样导致的后果是,很容易呈现汇合数据在分片上散布不均。
而在 4.4 中反对了复合哈希索引,即,能够在复合索引中指定单个哈希字段,地位不限,能够作为前缀,也能够作为后缀,进而也就提供了对复合哈希片键的反对,
有这个新性能之后,会带来很多益处,比方在如下两个场景下,
• 因为法律法规的要求,须要应用 MongoDB 的 zone sharding 性能,把数据尽量平均打散在某个地区的多个分片上。
• 汇合指定的片键的值是递增的,比方在上文中举的例子,{customer_id:1, order_id:1} 这个片键,如果 customer_id 是递增的,而业务也总是拜访最新的顾客的数据,导致的后果是大部分的流量总是拜访繁多分片。
在没有「复合哈希片键」反对的状况下,只能由业务对须要的字段提前计算哈希值,存储到文档中的某个非凡字段中,而后再通过「范畴分片」的形式指定这个事后计算出哈希值的非凡字段及其他字段作为片键来解决上述问题。
而在 4.4 中间接把须要的字段指定为为哈希的形式即可轻松解决上述问题,比方,对于上文形容的第二个问题场景,片键设置为 {customer_id:’hashed’, order_id:1} 即可,大大简化了业务逻辑的复杂性。
Hedged Reads
拜访提早的升高可能会带来间接的经济损失,Google 有一个钻研报告表明,如果网页的加载工夫超过 3 秒,用户的跳出率会减少 50%。所以,在 4.4 中 MongoDB 提供了 Hedged Reads 的性能,即在分片集群场景下,mongos 会把一个读申请同时发送到某个分片的两个正本集成员,而后抉择最快的返回后果回复客户端,来缩小业务上的 P95 和 P99 提早。
Hedged Reads 性能是作为 Read Preference 的一部分来提供的,所以能够是在 Operation 粒度上做配置,当 Read Preference 指定 nearest 时,默认启用 Hedged Reads 性能,当指定为 primary 时,不反对 Hedged Reads 性能,当指定为其余时,须要显示的指定 hedgeOptions,如下,
此外,Hedged Reads 也须要 mongos 开启反对,配置 readHedgingMode 参数为 on,默认 mongos 开启该性能反对。
升高复制提早
主备复制的提早对 MongoDB 的读写有十分大的影响,一方面,在一些特定的场景下,读写须要期待,备库须要及时的复制并利用主库的增量更新,读写能力持续,另一方面,更低的复制提早,也会带来备库读时更好的一致性体验。
Streaming Replication
在 4.4 之前的版本中,备库通过一直的轮询主库来获取增量更新操作。每次轮询时,备库被动给主库发送一个 getMore 命令读取其上的 Oplog 汇合,如果有数据,返回一个最大 16MB 的 Batch,如果没有数据,备库也会通过 awaitData 选项来管制备库无谓的 getMore 开销,同时可能在有新的增量更新时,第一工夫获取到对应的 Oplog。
拉取是由单个 OplogFetcher 线程来实现,每个 Batch 的获取都须要经验一个残缺的 RTT,在正本集网络情况不好的状况下,复制的性能就重大受限于网络提早。所以,在 4.4 中,增量的 Oplog 是一直的“流向”备库的,而不是依附备库被动轮询,相比于之前的形式,至多在 Oplog 获取上节俭了一半的 RTT。
当用户的写操作指定了“majority”writeConcern 的时候,写操作须要期待足够多的备库返回复制胜利的确认,MongoDB 外部的一个测试表明,在新的复制机制下,在高提早的网络环境中,能够均匀晋升 50% 的 majority 写性能。
另外一个场景是用户应用了 Causal Consistency,为了保障能够在备库读到本人的写操作(Read Your Write),同样强依赖备库对主库 Oplog 的及时复制。
Simultaneous Indexing
在 4.4 之前的版本中,索引创立须要在主库实现之后,才会复制到备库上执行。备库上的创立动作,在不同的版本中,因为创立机制和创立形式(前台、后盾)的不同,对备库 Oplog 的利用影响也大为不同。
然而,即便在 4.2 中,对立了前后台索引创立机制,应用了相当细粒度的加锁机制——只在索引创立的开始和完结阶段对汇合加独占锁,也会因为索引创立自身的性能开销(CPU、IO),导致复制提早,或者因为一些非凡操作,比方 collMod 命令批改汇合元信息,而导致 Oplog 的利用阻塞,甚至会因为主库历史 Oplog 被笼罩掉而进入 Recovering 状态。
在 4.4 中,主库和备库上的索引创立操作是同时进行的,能够大幅缩小因为上述情况所带来的主备提早,尽量保障即便在索引创立过程中,备库读也能够拜访到最新的数据。
此外,新的索引创立机制是在 majority 的具备投票权限的数据承载节点返回胜利后,索引才会真正失效。所以,也能够加重在读写拆散场景下,因为索引不同而导致的性能差别。
查问能力和易用性加强
传统的关系型数据库(RDBMS)广泛以 SQL 语言为接口,客户端能够在本地编写融入局部业务逻辑的简单 SQL 语句,来实现弱小的查问能力。MongoDB 作为一个新型的文档数据库系统,也有自定义的 MQL 语言,简单查问能力次要借助于 Aggregation Pipeline 来实现,虽弱于 RDBMS,但在最近的几个大版本中也在继续一直的打磨,最终的目标是使用户在享受到 MongoDB 灵活性和扩展性的同时,也能享受到丰盛的功能性。
Union
在多表联结查问能力上,4.4 之前只提供了一个 $lookup stage 用于实现相似于 SQL 中的「left outer join」性能,在 4.4 中新增的 $unionWith stage 又提供了相似 SQL 中的「union all」性能,用户把两个汇合中的数据聚合到一个后果集中,而后做指定的查问和过滤。区别于 $lookup stage 的是,$unionWith stage 反对分片汇合。当在 Aggregate Pipeline 中应用了多个 $unionWith stage 的时候,能够对多个汇合数据做聚合,应用形式如下,
能够在 pipeline 参数中指定不同的 stage,用于在对汇合数据聚合前,先进行肯定的过滤,应用起来非常灵活,上面举一个简略的例子,比方业务上对订单数据按表拆分存储到不同的汇合,第二季度有如下数据(演示目标),
当初假如业务上须要晓得,二季度不同产品的销量,在 4.4 之前,可能须要业务本人把数据都读出来,而后在利用层面做聚合能力解决这个问题,或者依赖某种数据仓库产品来做剖析,然而须要有某种数据的同步机制。
而在 4.4 中只须要如下一条 Aggregate 语句即可解决问题,
Custom Aggregation Expressions
4.4 之前的版本中能够通过 find 命令中的 $where operator 或者 MapReduce 性能来实现在 Server 端执行自定义的 JavaScript 脚本,进而提供更为简单的查问能力,然而这两个性能并没有做到和 Aggregation Pipeline 在应用上的对立。
所以,在 4.4 中,MongoDB 提供了两个新的 Aggregation Pipeline Operator,$accumulator 和 $function 用来取代 $where operator 和 MapReduce,借助于「Server Side JavaScript」来实现自定义的 Aggregation Expression,这样做到简单查问的性能接口都集中到 Aggregation Pipeline 中,欠缺接口统一性和用户体验的同时,也能够把 Aggregation Pipeline 自身的执行模型利用上,实现所谓「1+1 > 2」的成果。
$accumulator 和 MapReduce 性能有些类似,会先通过 init 函数定义一个初始的状态,而后对于每一个输出的文档,依据指定的 accumate 函数更新状态,而后会依据须要决定是否执行 merge 函数,比方,如果在分片汇合上应用了 $accumulator operator,那么最初须要把不同分片上执行实现的后果做 merge,最初,如果指定了 finalize 函数,在所有输出文档解决实现后,会依据该函数把状态转换为一个最终的输入。
$function 和 $where operator 在性能上基本一致,然而弱小之处是能够和其余的 Aggregation Pipeline Operator 配合应用,此外也能够在 find 命令中借助于 $expr operator 来应用 $function operator,等价于之前的 $where operator,MongoDB 官网在文档中也倡议优先应用 $function operator。
其余易用性加强
Some Other New Aggregation Operators and Expressions
除了上述的 $accumulator 和 $function operator,4.4 中还新增了其余多个 Aggregation Pipeline Operator,比方做字符串解决的,获取数组收尾元素的,还有用来获取文档或二进制串大小的操作符,具体见如下列表,
Connection Monitoring and Pooling
4.4 的 Driver 中减少了对客户端连接池的行为监控和自定义配置,通过规范的 API 来订阅和连接池相干的事件,包含连贯的敞开和关上,连接池的清理。也能够通过 API 来配置连接池的一些行为,比方,领有的最大 / 最小连接数,每个连贯的最大闲暇工夫,线程期待可用连贯时的超时工夫,具体能够参考 MongoDB 官网的设计文档。
Global Read and Write Concerns
在 4.4 之前的版本中,如果操作的执行没有显式指定 readConcern 或者 writeConcern,也会有默认行为,比方 readConcern 默认是 local,而 writeConcern 默认是 {w: 1}。然而,这个默认行为并不能够变更,如果用户想让所有的 insert 操作的 writeConcern 默认都是是 {w: majority},那么只能所有拜访 MongoDB 的代码都显式去指定该值。
在 4.4 中能够通过 setDefaultRWConcern 命令来配置全局默认的 readConcern 和 writeConcern,如下,
也能够通过 getDefaultRWConcern 命令获取以后默认的 readConcern 和 writeConcern。
此外,这次 MongoDB 做的更加贴心,在记录慢日志或诊断日志的时候,会记录以后操作的 readConcern 或者 writeConcern 设置的起源,二者雷同的起源定义有如下三种,
对于 writeConcern 来说,还有如下一种起源,
New MongoDB Shell (beta)
对于运维 MongoDB 的同学来说,应用最多的工具可能就是 mongo shell,4.4 提供了新版本的 mongo shell,减少了像代码高亮,命令主动补全,更加可读的错误信息等十分人性化的性能,不过,目前还是 beta 版本,很多命令还不反对,仅供尝鲜。
其余
这次的 4.4 公布,后面讲了次要是一个维护性的版本,所以除了上述解读,还有很多其余小的优化,像 $indexStats 优化,TCP Fast Open 反对优化建连,索引删除优化等等,还有一些绝对大的加强,像新的结构化日志 LogV2,新的平安机制反对等,这些可能不是用户最优先去关注的,在这里就不一一形容了,感兴趣的读者能够自行参考官网的 Release Notes。
原文链接
本文为阿里云原创内容,未经容许不得转载。