深度解读 MongoDB 最全面的增强版本 4.4 新特性

简介:随着计算和数据上云的趋势愈发明显,传统数据库“步履蹒跚”,云数据库将是未来。本次直播,阿里云将隆重发布2款全新升级产品——云数据库 MongoDB 4.4 和MongoDB 专属集群版。为您全面解读这两款产品的最新特性,帮助您更好地迁移上云c E b 8 D & @ h

MongoDB 在今年正式发布了新的 4.4 大版本,这次的发布包含众多的增强 Feature,可以称之为是一个维护性的版本,而且T & A . g是一个用户期待, 3 X g已久的维护性版本,MongoDB 官方也把这次发布称为「User-Driven Engineering」,说明新版本主要是针对用户呼声最高的一些痛点,重点进行了改进。

深度解读 MongoDB 最全面的增强版本 4.4 新特性

而阿里云| $ ? 8 U A q =作为 MongoDB 官方的全球战略合作伙伴,也即将全网独家上线 4.4` _ ` 新版本,下面就由阿里云 MoO 0 . 8 w I K / yngoDB 团队的工程师针对一u m $些用户关注度, L H = 1 ? f比较高的 Feature ,2 A = :进行深度解读e W } = h

可用性和容I @ q ^ 4错性增强

Mirrored Reads

在服务[ $ h } f阿里云 MongoDB 客户的过程中,笔者观察到有很多的客户虽然购买的是三节点的副本集,但是实际在使用过程中读写都是在 Primary 节点,其中一个可见的 Secondary 并未承载任何的读流量。

那么在偶尔的宕机切换之后? P : q V ~ | n,客户能明显的感受到业务的访问延迟会有抖动,经过一段时间后才会恢复到之前的水平,抖动原因就在于,新选举出的主库之前从未提供过读服务,并不了解C C m U t业务的访问特征,没有针对性的对数据做缓存,所以在突Y ! m q - R ] K然提供服务后,读操作会出现大量的「Cache Miss」,需要从磁盘重新加载数据,造成访问延迟上升。在大内存实例的情况下,这个问题更为明显。

在 4.4 中,MongoDB 针对上述问题实现了「Mirrored Reads」功能,即,主库会按一定的比例把读S ] [ ! o L g流量复制到备库上执行,来帮助备库预热缓存。这个执行是一个「Fire and Forgot」的行为,不会对主库的性能产生任何实质性的影响,但是备库负载会有一定程度的上升。

流量复制的比例是可动态配置的,通过 mirrorc 0 ~ p f * m aReads 参数设置,默认复制 1% 的流量。

深度解读 MongoDB 最全面的增强版本 4.4 新特性

此外,可以通过db.serverStatus( { mirroredReads: 1 } )来查看 Mir^ % T W 8 @rored Reads 相关的统* i J I % ~ m Y计信息,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

Resuma& 2 Lble Initial Sync

在 4.4 之前的版本中,如果备库在做全量同步,出现网络抖动而导致连接闪断,那么备库是需要重头开始全量* c ^ Z T 8同步的,导致之前的工作全部白费,这个情况在数据量A ) o 4 F d比较大时,比如 TB 级别,更加让人崩溃。

而在 4.4 中,Mo^ 8 x ~ :ngoDB 提供了,因网络异常导致I M p B m g Q全量同步中断情况下,从中断位置恢复全量同步的能力。在尝试恢复一段时间后,如果仍然不成功,那么会重新选择m , N R E p d _一个同步源进行新的全量同步。这个尝试的超时时间默认是 24 小时,可以通过 replicatioq ~ Z 3 U # = M Zn.initialSyncTransientErrorRetryPeriodSeconds 在进程启动时更改。

需要注意的是,对于全量同+ 5 E步过程中遇到的非网络异常导致的中断,仍然需要重新发起全量同步。

Time-Based Opl6 a { R $ Pog Retention

我们知道,MongoDB 中的M & A j { % _ Oplog 集合记录了所有的数据变更操作,除了用于复制,还可用于增量备份,数据迁移,数据订阅等场景,是 MongoDB 数据生态的重要基础设施。

Oplog 是作为 Capped Collection 来实现的,虽然从 3.6 开U X F始,MongoDB 支持通过 replSetResizeOplog 命令动态修改 Oplog 集合的大小,但是大小往往并不能准确反映下游对 Oplog 增量数据的需求,考虑如下场景,

• 计划在凌晨的 2 - 4 点对某, c ~ m O w 0个 Secondary 节点进行停机维护,应避免上游 Oplog 被清理而触发全量同步。

• 下游的数据订阅组件可q ~ I ^ 能会因为一些异常情况而停止服务,但是最慢会在 3 个小时之内恢复服务并继续进行增量拉取,也应当避免上游的增量缺失。

所以,在真实的应用场景] r 5 A 下,很多时| j R # 5候是需要保留最近一个时间段内的 Oplog,这个时间段内产生多少的 Oplog 往往是很难确定的。

在 4.4 中,MongoD@ ; r ; ~B 支持 storage.oplogMinRetentionHours 参数定义最少保留的 Oplog 时长,也可以通过 replSetResizeOplog 命令在线修改这个值,如下,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

扩展性和性能增强

H, : V 9 fidden Indexes

Hidden Index 是阿里云 MongoDB 和 Mo/ z ^ S 1 y I $ gngoDB 官方达成战略合作后共建的一个 Feature。我们都知道数据库维护太多的索引会导致写性能的下降,但是往往业务上的复杂性决定了运维 MX % , ? qongoDB 的同学不敢轻易的删除一个潜在的低效率索引,担心错误的删除会带来业务性能的5 _ I抖动,而重建索引往往代价也非常大。

Hidden Index 正是为了解决 DBA 同学面临的上述困境,它支持通过 collMod 命令对现有的索引进行隐藏,保证后续的 Query 都不会利用到该索引,在观察一段时间后,确定业务没有异常,可以放心的删除该索引。

深度解读 MongoDB 最全面的增强版本 4.4 新特性

需要注意的是,索引被隐藏之后只是对 Mong! k #oDB 的执行计划器不可见,并不会改变索引N { s V本身的一些特殊行为,比如唯一键约束,TTL 淘汰等。

索引在隐藏期间,如果新的写入,也是会被更新的,所以也可以通过取消隐藏,很方便的让索引立刻变的可用。

RefinablP ( Ae Shard Keys] 0 S d

当使用 MongoDB 分片集群时,相信大家都知道选择一个好的 Shard key 是多么的重要,因为它决定了分片集群在指定的 Workload 下是否有良好的扩展性。但是在实际使用f A ] I j | Q T 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 完全可以满足需求,但是^ P u随着业务的发展,某个R t B *大客户累积的订单越来+ W q q越多,进而对这个客户订单的访问成为某个单一 Shard 的热点,由于订单和customer_id天然的关联关系,修改customer_i8 ) u D ` Z u md并不能改善访问不均的情 ? & E z H Q E S况。

针对上述类似场景w } z z,在 4.4 中,你可以通过 refineCollectionShardKey 命令给现有的 Shard Key 增加一个或多个 Suffix Field 来改善现有的文档在 Chunk 上的分布N l { f 2 t z |问题。比如,在上面描述的订单业务场景中,通过refineCollectionShardKey命令把 Shy 0 z 8 f A Aard key 更改为{customer_id:1, order_id:1},即可避免单一 Shard 上的访问热点问题。

需要了解的是,refineCollectionShardKey 命令性能开销非常低,只是更改 Config Server 上的元数据,不需要任何形式的数据迁移(因为单纯的添加 Suffix 并不会改变数据在0 Z l现有chunk 上的分布),数据的打散仍然是在后续正常的 Chunk 自动分裂和迁移的流程中逐步进行的。此外,Shard Key 需z X U ? y要有对应的 Index 来支撑,所以refineCollectionShardKey 要求提前创建新 Shard Key 对应的 Index。

因为并不是所有的文档都存在新增的 Suffixa i % N Field(s),所以在 4.4 中实际上( U 3 [ K隐含支持了「Missing Shard Key」的功能,即新插入的文档可以不包含指定的 Shard Key Field。但是,笔者不建议这么做,很容易产生 Jumbo Chx { 9 7 ( (unk。

Compound Hashed Shard Keys

在 4.4 之前的版本中,只能指定单字段的哈希片键,原因是此时 MongoDB 不支持复合哈希索引,这样导致的结果是,很容易出现集合数据在分片上分布不均。

而在 4.4 中支持了复合哈希索引,` p f o即,可以在复合索引中指定单个哈希字段,位置不限,可以作为前缀,也可以作为后缀,进而也就提供了对复合哈希片键的支持,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

有这个新功能之后,会带来很T r _多好处,比如在如下两个场景下,

• 因为法律法规的要求,需要使用 MongoDB 的 zone sharding 功能,把数据尽量均匀f [ D y M G U 0 i打散在某个地域的多个分片上。

• 集合指定的片键的值是递增的,比如在上文中举的例子,{customer_id:1, order_id:1}v 1 Z Y 7 { 9N f s # A N ] 3个片键,如果customer_id 是递增的,而业务也总是访问最新的顾客的数据,导致的结果是大部分的流量总是访问单一分片。

在没有「复合哈希片键」支持的情况下,只能由业务对需要的字段提前计算哈希值,存储到文档中的某个特殊字段中,然后再通过「范围分片」的方式指定这个预先计b X h , , $ D算出哈希值的特殊字段及其他字段作为片键来解决上述问题。

而在_ ~ $ : 7 n 4.4 中直接把需要的字段指定为为哈希的方式即可: L Y轻松解决上述问题,比如,对于上文描述的第m n k M L & =二个问题场景,片键设置为 {customer_id:'ha7 h 9 I ^ 9shed', order_id:1} 即可,大大简化了业务逻辑的复杂性。

Hedged Reads

访问延迟的升高可能会带来直接的经济损失,Google 有一个研究报告表明,如果网页的加载时间超过 3 秒,用户的跳出R z d 3率会增加 50%。所以,在 4.4 中 Mongo. u # T N _ #DB 提供了 Hedged R_ 8 Z | & Veads 的功能,即在分片集群场景下,mongos 会把一个: S n Z s F 读请求同时发送到某个分片的两个副本集成员,然后选择最快的返回结果回复客? ; + 0 & $ 8 x户端,来减少业务上的 P95 和 P99 延迟。

Hedged Reads 功能是作为 Read Preference 的一部分来提供的, 所以可以是在 Operation 粒度上J % ) ; q A做配置,当 Rez a Z y 5 T Nad Pru A | q 4 h ~eference 指定 nearest 时,默认启用 Hedged Reads 功能,当指定为 primary 时,g X i不支持 Hedged Reads 功能,当指定为其他时,需要显示的指定 hedgeOptions,| 7 4 a [ G i W 7如下,; * Y e - V _ X n

深度解读 MongoDB 最全面的增强版本 4.4 新特性

此外,Hedged Reads 也需要 mongos 开启支持 , b 4 = F & X,配置 readHedginP 5 pgMode 参数为 on,默认 mongos 开启该功能支持。

深度解读 MongoDB 最全面的增强版本 4.4 新特性

降低复制延迟

主备复制的延迟对 MongoDB 的读写有非常大的影响,一` G i ! } G方面,在一些特定的场景下,读写需要等待,备库需要及时的复制并应用主库的增量更新,读写才能继续,另一方面,更低的复制延迟,也会带来备库读时更好的一致性体验。

Streaming Replication

在 4.4 之前的版本中,备库通过不断的轮询主库来获取增量更新操作。每次轮询时,备库主动给主库发送一个 getMore 命令读取其上的 Oplog 集合,如果有数据,返回一个最大 16MB 的 Batch,如果没有数据,备库也会通过 awaitData! S ; ~ g R 选项来控制备库无谓的 getMore 开销,同时能够在有新的增量更新时,第一时间^ ] , +获取到对应的 Oplog。

拉取是由单个 OplogFetcher 线程来完成,每W + ) ` z o D (个 Batch 的获取都需要经历一个完整的 RTT,在副L , x 0 . V w ]本集网络状况不好的情况下,复制的性能就严重受限于网络延迟。所以,在 4.4 中,增量的 Oplod @ B ` kg 是不断的“流向”备库的,而不是依靠备库主动轮询,相比于之前的方式,至少在 Oplog 获取上节省了一半的 RTT。

当用户的写操作指定了 “majority” writeCo# ? pncern 的时候,写操作需要等待足够多的备库返回复制成功的确认,MongoDB 内部的一个测试表明,在v &新的复制机制下,在高延迟的网络环境中,可以平均提升 50% 的 majority 写性能。

另外一个场t i ? d } e景是用户使用了Causal Consistency,为了保证可以在备库读到自己的写操作(Read Your Writ{ Q 6e),同样强依赖备库对主库 Oplog 的及时复制。

Simultaneous Indexing

在 4.4 之前的版本中,索引创建需要. a J c n j B在主库完成之后,才会复制到备库e _ t 8 x 6上执行。备库上的创建动作,在不同的版本中,因为创建机制和创建方式(前台、后台)的不同,对备库 Oplu P P Iog 的应用影响也大为不同。

但是,即使在 4.2 中,统一了前后台索引创建机制,使用了相当细粒度的加锁机制——只在索引创建的开始和结束阶段对集合加独占锁,也会因为索引创建本身的性能开销y x 6 s q(CPU、IO),导致复制延迟,或者因为一些特殊操作,比如 collMod 命令修改集合元信息,而导致 Oplog 的应用阻塞,甚至会因为主库r J V Y G J D ]历史 Oplog 被覆盖掉而进入 Recovering 状态。

在 4.4 中,主库r N [ 9^ 6 [ `备库上的索引创建操作是同时进行的,可以大幅减少因为上述情况所带来的主备延迟,尽量保证即使在索引创建过程中,备库读也可以访问到最新的数据。

此外,新的索引创建机制是在 majority 的具备投票权限的r d j数据承载节点返回成功后,索引才会真正生效。所以,也可以减轻在读写分离场景下,因为索引不同而导致/ F O q t y的性能差异。

查询能力和易用性增强

传统的关系Z R k t 5 Q @型数据库(RDBMS)普遍以 SQL 语言为接口,客户端可以在本地编写融入部分业务逻辑的复杂 SK } yQL 语句,来实现| T C c h T X强大的查询能力。MongoDB 作为一个新型的文档数据库系统,( r O y 也有自定义的 MQL 语言,复杂查询能力主要借助于 Aggregation Pipeline 来实现,虽弱于 RDB_ _ c _ {MS,但在最近的几个大版本中也在持续不断的打磨,最终的目的是使用户在享受到 MongoDB 灵活性和扩展性的同时,也能享受到丰富的功能性。

Union

在多表联合查询能力上,` a # k @ v F4.4 之前只提供了一个 $lookup stage 用于实现类似于 So T . R _ o oQL 中的「left outeX / ] Hr join」功能,在 4.4 中新增的 $unionWith stage 又提供了类似 SQL 中的「univ K ( a w 3 Zon all」功能,用户把两个集合中的数据聚合到一个结果集中,然后做指定的查C P B o s m询和过滤。区别于 $lookup stage 的是,$unionW, L 6 3 7 r ? Z ]ith stage 支持分片集合。当在 Aggregate Pipeline 中使用了多个 $unionWith stage 的时候,可以对多个! U 8 3 &集合数据做聚合,使用方式如下,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

可以在 pipeline 参数中指定不同的 stage,{ ; d % r用于e { T [ 8 W O t在对集合数据聚合前,先进行一定的过滤I Z W C ` # ; 1,使用起来非常灵活,下面举一个简单的例子,比如业务上对订单数据按表拆分存储到不同的集合,第二季度有如下数据(演示目的),

深度解读 MongoDB 最全面的增强版本 4.4 新特性

现在假设业务上需要知= e m ~ W道,二季度不同产品的销量,在 4.4 之前,可能需要业务自己把数据都读出来,然后在应用层面做聚合才能解决这个问题,或者1 q s - Y P o K依赖某种c A a ~ 2数据仓Q 7 n % f库产品来做6 1 W e [ q分析,但是需要有某种数据的同步机制。

而在 4.4 中只需要如下一条 Aggregate 语句即可解决问题,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

Custom Aggregation ExpressionsD u i

4.4 之前的版本中可以通过 find 命令中的 $where operator 或者 MapReduce 功能来实现在 Server 端执行自定义的 JavaScript 脚本,进而P e k u | =提供更为复杂的查询能力,但是这两个功能并没有做到和 Aggregation Pipeline 在使用, 1 C M A上的统一。

所以,在 4.4 中,MongoDB 提L B p E [ o v供了两个新的 Aggregation Pipeline Operator,$accumulp | v Q I j -ator 和 $function 用来取代 $w` F {here operator 和 MapReduce,借助于「Server Side JavaScript」来实现自定义的 Aggregation Expression,这样做到复杂查询的功能接口都集中到 Aggregation Pipeline 中,完善Z q |接口统一性和用户体验的同时m $ e M ^ 8 y,也可以把Agx _ # v s g }gregation Pipeline 本身的执行模型利用上,实现所谓 「1+1 > 2」 的: ) m K . ! 效果。

$acch U . yumulator 和 MapReduce 功能有些相似W [ 7 O ? 9 S [,会先通过init 函数定义一个初始的状态,然后` 9 e + J e对于每一个输入的文档,根据指定的 accumate 函数更新状态,然后会根据需要决定是否执行 merge 函数,比如,如果在分片集合上使用了 $accumulator opq 0 kerator,那么最后需要把不同分片上执行完成的结果做 merge,最后,如果指Z S X 0 ` ]定了 finalize 函数,在所有输入文档处理完成后,会根据该函数把状态转换为一个最终的输出。Z f ) # I

$function 和 $where o- F Y f w N 6 H *perator 在功能上基本一致,但是x 7 l 6 D强大之处是可以和其他的 Aggregation Pipeline Operator 配合使用,此外也可以在 find 命令中借助于 $expr operator 来使用 $function operator,等T N $ t h ` p价于之前的 $where operator,Mo( & @ X J 7 3 D %ngoDB 官方在文档中也建议优先使用 $function operator。

其他易用性增强

Some Oe h } ) { qther New Aggregation Operators and Expressions

除了上述的 $accumulator 和 $function operator,4.4 中还新增了其他多个 Aggrega| $ 9 H F * Etion Pipeline OpC 7 s Z $ | t = +erator,比如做字符串处理的,获取数组收尾元素的,还有用来获取文档或二进制串大小的操作符,具体见如下列表,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

Connection Monitoring and Pooling

4.4 的 Driver 中增加了对客户端连接池的行为监控和自定义配置x { _ _ d 4,通过标N % V Y准的 API 来订阅和连接池相关的事件,包括连接的关闭和打开,连接池的清理。也可以通过 API 来配置连接池的一些行为,比如,拥有的最大/最小连接数,每个连接的最大空闲时间,线程等待可用连接时的超时时间,具体可以参考 MongoDB 官方的设计文档。

Global Read and Write! } 3 C E . $ Concerns

在 4.4 之前的版本中,如果操作的执行没有显式指定 readConcern 或者 writeC_ X 9 D { q Roncern,也会有默认行为,比如readConcern 默认是 local,而 writeConcern 默认是 {w: 1}。但是,这个默d s t i A * ?认行为并不可以变更,如果用户想让所有的4 L L M X o insert 操作的 writeConcern 默认都是是 {w: majo} X ; / w q Erity},那么只能所有访问 MongoDB 的代码都显式去指定该值。

在 4.4 中可以通过 setDefaultRWConcern 命令来配置全局默认的 readConcern 和 writeConcern,如下,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

也可以通过 getDefaultRWConcern 命令获取当前默认的readConcerK } # Dn 和 writeConcern。

此外,这次 MongoDB 做的更加贴心,在记录慢日志或诊断日志的时候,会记录当前操作的 readConcer6 Y in 或者 writeConcern 设置的来源,二者相同的来源定义有如下k # c d三种,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

对于 writeConcern 来说2 j u -,还有如下一种来源,

深度解读 MongoDB 最全面的增强版本 4.4 新特性

New MongoDB Shell (beta)

对于运维 MongoDB 的同学来说,使用最多的工具可能就是 mongo shell,4.4 提供了新版本的 mongo shell,增加了像代& R y码高亮,命令自动补全j Y ;,更加可读的错误信息等非常人性化的功能,不过,目前还] X Q是 beta 版本,很多命令还不支持,仅供尝鲜。o y + W

深度解读 MongoDB 最全面的增强版本 4.4 新特性

其他

这次的 4.4 发布,前面讲了主要是一个维护性的版本,所以除y 2 ? 3 E n J o C了上述解读Y [ r,还有很多其他小的优化,像 $indexStats 优化,TCP Fast Op, ! o 4 } A Jen 支持优化建连,索 k h引删u o ?除优化等等,还有一些~ M - h 7 j b u T相对大的增强,像新的结构化日志LogV2,新的安9 F G p . m 7 ~ f全机制支持等,这些可能不是用户最& l ! i s B优先去关注的,在这里就不^ y ; u } 3 V W一一描述了,感兴! m x _趣的读者可以自行参考官方的 Relek 3 M - !ase Notes。

作者:小攻云攻略

本文为阿里云原创内容,未经允许不得转载