关于mongodb:技术干货-MongoDB时间序列集合

名词解释Glossary

bucket:带有雷同的元数据且在一段有限度的间 隔区间内的测量值组。

bucket collection :用于存储时序型汇合的底层的分组桶的零碎汇合。复制、分片和索引都是在桶级别上实现的。

measurement:带有特定工夫序列的K-V汇合。

meta-data:时序序列里很少随工夫变动的K-V对,同时能够用于辨认整个时序序列。

time-series:一段距离内的一系列测量值。

time-series collection:一种示意可写的非物化的视图的汇合类型,它容许存储和查问多个工夫序列,每个序列能够有不同的元数据。

MongoDB 在5.0中反对了新的timeseries collection类型的选项,该类型用于存储时序型数据。timeseries collection提供了一组用于插入和查问测量值的简略接口,同时底层理论的数据是存储在以bucket模式的汇合中。

在创立timeseries collection时,timeField字段是最小必备的配置项。metaField是另一个可选的、可被指定的元数据字段,它是用于在bucket中对测量值分组的根据。MongoDB通过提供expireAfterSeconds字段选项,也反对了对测量值的过期机制。

在mydb数据库中有个以mytscoll 命名的timeseries collection,该汇合在MongoDB外部的catelog(用于存储汇合或视图的信息)里是由一个视图和一个零碎汇合组成的。

mydb.mytscoll 是个视图,它在MongoDB底层是用bucket collection作为蕴含特定属性的原始汇合实现的:

该视图就是通过aggregation里的$_internalUnpackBucket来实现开展bucket里数据的。

该视图是可写的(仅反对插入)。同时每个被插入的文档必须蕴含工夫字段。

在查问视图时,它会隐式地开展底层在bucket collection中存储的数据,而后返回原始的非bucket模式的文档数据。

该零碎汇合的命名空间是mydb.system.buckets.mytscoll,它是用来存储理论数据的。

每一个在bucket collection里的文档,都示意了一组区间距离的时序型数据。

如果在创立timeseries collection时,定义了metaField元数据字段,那么所有在bucket里的测量值都会有这个通用的元数据字段。

除了工夫范畴,bucket还限度了每个文档数据的总条数以及测量值的大小。

Bucket Collection Schema

{
    _id: <Object ID with time component equal to control.min.<time field>>,
    control: {
        // <Some statistics on the measurements such min/max values of data fields>
        version: 1,  // Version of bucket schema. Currently fixed at 1 since this is the
                     // first iteration of time-series collections.
        min: {
            <time field>: <time of first measurement in this bucket, rounded down based on granularity>,
            <field0>: <minimum value of 'field0' across all measurements>,
            <field1>: <maximum value of 'field1' across all measurements>,
            ...
        },
        max: {
            <time field>: <time of last measurement in this bucket>,
            <field0>: <maximum value of 'field0' across all measurements>,
            <field1>: <maximum value of 'field1' across all measurements>,
            ...
        },
        closed: <bool> // Optional, signals the database that this document will not receive any
                       // additional measurements.
    },
    meta: <meta-data field (if specified at creation) value common to all measurements in this bucket>,
    data: {
        <time field>: {
            '0', <time of first measurement>,
            '1', <time of second measurement>,
            ...
            '<n-1>': <time of n-th measurement>,
        },
        <field0>: {
            '0', <value of 'field0' in first measurement>,
            '1', <value of 'field0' in first measurement>,
            ...
        },
        <field1>: {
            '0', <value of 'field1' in first measurement>,
            '1', <value of 'field1' in first measurement>,
            ...
        },
        ...
    }
}

索引indexes

为了保障timeseries collection的查问能够受害于索引扫描而不是全表扫描,timeseries collection容许索引能够被创立在工夫上,元数据上以及元数据的子属性上。从MongoDB5.2开始,在timeseries collection也容许索引被创立在测量值上。用户应用createIndex命令提供的索引标准被转换为底层buckets collection的模式。

timeseries collection与底层的buckets collection之间的索引映射转换关系细节,你能够参考timeseries_index_schema_conversion_functions.h.

在v5.2及以上版本的最新反对的索引类型,timeseries collection会存储用户原始的索引定义到变换后的索引定义上。当从底层的bucket collection的索引映射到timeseries collections的索引时,会返回用户原始的索引定义。

当索引被创立后,能够通过listIndexes命令或$indexStats聚合打算来查看。listIndexes 和$indexStats是作用于timeseries collections的,执行时,它们会在外部将底层的bucket collection的索引转化成timeseries格局的索引,并返回。比方,当咱们在元数据字段中定义有mm的timeseries collection上执行listIndexes命令时,底层的bucket collection的{meta:1}索引,将会以{mm:1}格局返回。

dropIndex 和collMod (hidden: <bool>, expireAfterSeconds: <num>) 也同样反对在timeseries collection上。

工夫字段上反对的索引类型:

单字段索引

组合索引

哈希索引

通配符索引

稠密索引

多键索引

带排序的索引

元数据字段和元数据子字段反对的索引类型:

反对所有工夫字段上反对的索引类型

v5.2及以上版本反对2d 索引

v5.2及以上版本反对2dsphere 索引

v5.2及以上版本反对 Partial索引

仅在v5.2及以上版本,测量值字段反对的索引类型:

单字段索引

组合索引

2dsphere

局部条件索引

`timeseries collections 上不反对的索引类型,包含 惟一索引以及文本索引。

桶目录Catalog

为了保障高效地桶(分组)操作,咱们在BucketCatalog里保护了一组开启的桶,你能够在bucket_catalog.h找到。在更高的级别,咱们尝试着把并发写程序的写操作分组合并为能够一起提交地批处理,以缩小对底层文档的写次数。写程序会插入它的输出批处理里的每一个文档到BucketCatalog,而后BucketCatalog会返回一个BucketCatalog::WriteBatch的处理器。一旦实现下面那些插入操作后,写程序就会查看每个写批处理。如果没有其余的写程序曾经对批处理申明提交的权力,那么它会申明权力,并会提交它的批处理。否则,写程序将会稍后再提交解决。当它查看完所有的批处理,写程序将会期待其余的写程序提交每个剩下的批处理。

在外部,BucketCatalog保护一组对每个bucket 文档的更新操作。当批处理被提交时,它会将这些插入转换到成buckets的列格局,并确保任何control字段的更新(例如control.min 和 control.max)。

当bucket文档在没有通过BucketCatalog的状况下被更新时,写程序就须要为有问题的文档或命名空间去调用BucketCatalog::clear ,这样它就能够更新它的外部状态,防止写入任何可能毁坏bucket 格局的数据。这通常由OP观察者解决,但可能须要通过其余中央去调用。

bucket既能够通过手动设置选项control.closed 标识来敞开,也能够在许多场景下通过 BucketCatalog 主动敞开。如果BucketCatalog应用了超出给定的阈值(可通过服务器参数timeseriesIdleBucketExpiryMemoryUsageThreshold管制)的更多内存,此时它将会开始去敞开闲暇的bucket。如果bucket是开启的且它没有任何未处于期待中未提交的测量值时,那么它就会被视为闲暇的bucket。在上面这些场下 BucketCatalog 也会敞开bucket: 如果它领有超过最大阈值(timeseriesBucketMaxCount)的测量值数据的数量;如果它领有过大的数据量大小(timeseriesBucketMaxSize);又或者一个新的测量值数据是否是会导致bucket在其最旧的工夫戳和最新的工夫戳之间跨度比容许的距离更长的工夫(以后硬编码为一小时)。如果传入的测量值在原理上与曾经达到给定bucket的度量不兼容,该bucket将被敞开,同时能够应用numBucketsClosedDueToSchemaChange度量进行跟踪。

在第一次提交给定bucket的写批处理时,就会生成新的残缺的文档。后续的批处理提交中,咱们只执行更新操作,不再生成新的残缺的文档(因而称为‘经典’更新),是间接创立DocDiff(“delta”或者v2的更新)。

粒度Granularity

timeseries collection的granularity 选项在汇合创立的时候,能够被设置成seconds,minutes或者hours。前期可通过colMod操作来批改这个选项从seconds到minutes或者从minutes到hours,除此之外的转化批改目前都是不反对的。该参数想要示意在已给定的时序型测量数据之间的粗略的工夫距离,同时也用于调节其余外部参数对分组的影响。

单个bucket被容许的最大时间跨度,是由granularity选项管制,对于seconds,最大的时间跨度被设置成1小时,对于minutes就是24小时,对于hours就是30天。

当通过BucketCatalog开启新的bucket时,_id里的工夫戳就是等同于control.min.<time field>的值,该值是从第一个插入bucket的测量数据中依据granularity选项来向下近似舍入而失去的。对于seconds,它将向下舍入到最靠近的分钟,对于minutes,将向下舍入到最靠近的小时,对于hours,它将向下舍入到最靠近的日期。在闰秒和日历中的其余不规则状况下,这种舍入可能并不完满,并且通常通过对自纪元以来的秒数进行根本模运算来实现,假如每分钟 60 秒,每小时 60 分钟,以及每天 24 小时。

更新和删除
timeseries collection 反对合乎以下限度的删除语句:

仅反对metaField的属性的查问语句

反对批量操作

同时更新满足下面同样的条件,另外遵循:

仅反对metaField对应的属性值

更新操作指定一个带有更新运算符表达式的更新文档(而不是替换文档或者更新的pipeline操作)

不反对upsert:true 操作

这些更新与删除的执行都会被转换成绝对应的底层的bucket collection的更新或删除操作。特地是,对于查问和更新文档,咱们会应用真正的字段meta 替换汇合的metaField。(参见 Bucket 汇合标准)

例如,对于一个应用 metaField: “tag”创立的timeseries汇合db.ts,思考一个对这个汇合的更新操作,其查问语句是{“tag.tag.a”: “a”} ,同时更新文档语句是 {$set: {“tag.tag.a”: “A”}, $rename: {“tag.tag.b”: “tag.tag.c”}}。这个更新操作在 db.system.buckets.ts上会被转换成,查问语句是{“meta.tag.a”: “a”},更新语句是 {$set: {“meta.tag.a”: “A”}, $rename: {“meta.tag.b”: “meta.tag.c”}}。而后这个转换后的更新语句就能够像一般的更新操作一样执行。下面这些转换流程也实用于删除操作。

参考文献References

MongoDB Blog: Time Series Data and MongoDB: Part 2 – Schema Design Best Practices

对于作者:黄璜

目前就任于上海DerbySoft,次要从事基础架构中业务流程设计及研发的工作,平时工作中MongoDB应用的较多。
在晋升本人外文的能力的同时,也心愿为社区做出渺小的奉献。

社区招募

为了让社区组委会成员和志愿者敌人们灵便参加,同时咱们为想要深度参加社区建设的搭档们开设了“招募通道”,如果您想要在社区外面结交气味相投的技术搭档,想要通过在社区积淀有价值的干货内容,想要一个展现本人的舞台,晋升本身的技术影响力,即刻退出社区奉献队伍~ 点击链接提交申请:
http://mongoingmongoing.mikec…

【腾讯云】云产品限时秒杀,爆款1核2G云服务器,首年50元

阿里云限时活动-2核2G-5M带宽-60G SSD-1000G月流量 ,特惠价99元/年(原价1234.2元/年,可以直接买3年),速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据