当前位置: 首页 > 科技观察

说说MongoDB时间序列集合

时间:2023-03-18 15:42:10 科技观察

名词解释桶:一组具有相同元数据且在有限区间内的测量值。桶集合:用于存储时间序列集合的底层分组桶的系统集合。复制、分片和索引都在桶级别完成。测量:具有特定时间序列的K-V集。meta-data:时间序列中很少随时间变化的K-V对,可以用来标识整个时间序列。时间序列:一段时间内的一系列测量。时间序列集合:表示可写非物化视图的集合类型,它允许存储和查询多个时间序列,每个时间序列可以有不同的元数据。MongoDB在5.0支持一个新的时间序列集合类型选项,用于存储时间序列数据。时间序列集合提供了一组简单的接口用于插入和查询测量值,而底层的实际数据以桶的形式存储在集合中。创建时间序列集合时,timeField字段是最少需要的配置项。metaField是另一个可以指定的可选元数据字段,用于对存储桶中的测量进行分组。MongoDB还通过提供expireAfterSeconds字段选项支持测量值的过期机制。mydb数据库中有一个名为mytscoll的时间序列集合,它由MongoDB内部目录中的视图和系统集合组成(用于存储集合或视图信息)。mydb.mytscoll是一个视图,在MongoDB的底层实现,将桶集合作为包含特定属性的原始集合:视图通过聚合中的$_internalUnpackBucket实现对桶中数据的扩展。该视图是可写的(仅支持插入)。此外,每个插入的文档都必须包含一个时间字段。查询视图时,会隐式扩展存储在bucket集合中的底层数据,然后返回原始的非bucket文档数据。系统集合的命名空间为mydb.system.buckets.mytscoll,用于存储实际数据。桶集合中的每个文档代表一组间隔时间序列数据。如果在创建timeseries集合的时候定义了metaField元数据字段,那么bucket中所有的measurementvalue都会有这个公共的metadata字段。除了时间范围之外,桶还限制了每个文档的数据总数和测量值的大小。BucketCollectionSchema{_id:<时间分量等于control.min.>的对象ID,control:{//<一些关于测量的统计信息,例如数据字段的最小/最大值>version:1,//存储桶模式的版本。当前固定为1,因为这是//时间序列集合的第一次迭代。min:{:<这个桶中第一次测量的时间,根据粒度向下舍入>,:<所有测量中'field0'的最小值>,:<'field1'的最大值'所有测量值>,...},max:{:<此存储桶中最后一次测量的时间>,:<所有测量值中“field0”的最大值>,:<所有测量中“field1”的最大值>,...},closed://可选,向数据库发出此文档将不会接收任何//额外测量值的信号。},meta:,data:{:{'0',,'1',<第二次测量时间>,...'':<第n次测量时间>,},:{'0',<第一次测量'field0'的值>,'1',<第一次测量中'field0'的值>,...},:{'0',<第一次测量中'field1'的值>,'1',<第一次测量中'field1'的值measurement>,...},...}}索引以确保时间序列集合查询可以受益于索引扫描而不是全表扫描,timeseriescollec化允许按时间、元数据和元数据的子属性创建索引。从MongoDB5.2开始,时间序列集合也允许在测量值上创建索引。用户使用createIndex命令提供的索引规范将转换为基础存储桶集合的架构。timeseries集合与底层buckets集合的索引映射转换关系详见timeseries_index_schema_conversion_functions.h。对于v5.2及以上版本最新支持的索引类型,时间序列集合会将用户的原始索引定义存储到索引定义上的转换后的索引定义中。当底层桶集合的索引映射到时间序列集合的索引时,将返回用户的原始索引定义。创建索引时,可以使用listIndexes命令或$indexStats聚合计划对其进行检查。listIndexes和$indexStats应用于时间序列集合。执行时,它们会在内部将底层桶集合的索引转换为时间序列格式的索引并返回。例如,当我们在元数据字段中定义了mm的时间序列集合上执行listIndexes命令时,底层桶集合的{meta:1}索引将以{mm:1}格式返回。时间序列集合也支持dropIndex和collMod(hidden:,expireAfterSeconds:)。时间字段支持的索引类型:单字段索引复合索引哈希索引通配符索引稀疏索引多键索引排序索引元数据字段和元数据子字段支持的索引类型:支持所有时间字段支持的索引类型v5.2及以上版本支持二维索引v5.2及以上版本支持2dsphere索引v5.2及以上版本支持Partial索引仅在v5.2及以上版本中,测量值字段支持的索引类型:单字段索引组合索引2dspherepartConditionalIndexesUnsupportedindextypeson`时间序列集合,包括唯一索引和文本索引。BucketCatalog为了保证高效的bucket(分组)操作,我们在BucketCatalog中维护了一组打开的bucket,你可以在bucket_catalog.h中找到。在更高的层次上,我们尝试将并发写入者的写入操作分组为可以一起提交的批次,以减少对底层文档的写入次数。编写器将其输入批次中的每个文档插入到BucketCatalog中,然后BucketCatalog返回一个BucketCatalog::WriteBatch处理程序。完成上述插入后,编写器将检查每个写入批次。如果没有其他writer要求提交该批次,那么它将要求权利,并提交其批次。否则,作者稍后将提交处理。检查完所有批次后,作者将等待其他作者提交剩余的每个批次。在内部,BucketCatalog为每个存储桶文档维护一组更新操作。提交批处理时,它将这些插入转换为桶的列格式,并确保更新任何控制字段(例如control.min和control.max)。在不通过BucketCatalog更新存储桶文档时,编写器需要为相关文档或命名空间调用BucketCatalog::clear,以便它可以更新其内部状态并避免写入任何可能损坏存储桶的内容。格式化数据。这通常由OP观察者处理,但可能需要在其他地方调用。桶可以通过手动设置选项control.closed标志来关闭,或者在许多情况下由BucketCatalog自动关闭。如果BucketCatalog使用的内存超过给定阈值(由服务器参数timeseriesIdleBucketExpiryMemoryUsageThreshold控制),它将开始关闭空闲桶。如果一个桶是打开的并且没有任何未决的未提交测量,则认为它是空闲的。BucketCatalog还会在以下条件下关闭存储桶:如果它的测量数量超过最大阈值(timeseriesBucketMaxCount);如果它的数据大小过大(timeseriesBucketMaxSize);或者,如果新的测量会导致存储桶跨越其最旧和最新时间??戳之间的允许间隔(目前硬编码为一小时)。如果传入的测量原则上与已经到达给定桶的指标不兼容,则该桶将被关闭,同时可以使用numBucketsClosedDueToSchemaChange指标对其进行跟踪。第一次提交给定桶的写入批次时,会生成一个新的完整文档。在后续的批量提交中,我们只执行更新操作,而不是生成新的完整文档(因此称为“经典”更新),并直接创建DocDiff(“delta”或v2更新)。粒度时间序列集合的粒度选项可以在创建集合时设置为秒、分钟或小时。稍后,您可以通过colMod操作将此选项从秒修改为分钟或从分钟修改为小时。目前不支持其他转换修改。该参数旨在表示给定时间序列测量之间的粗略时间间隔,也用于调整其他内部参数对分组的影响。单个桶允许的最大时间跨度由粒度选项控制。对于秒,最大时间跨度设置为1小时,对于分钟为24小时,对于小时为30天。当通过BucketCatalog打开一个新的bucket时,_id中的timestamp相当于control.min.的值,是根据granularity选项从第一个插入bucket的测量数据开始向下舍入得到的。对于秒,它将向下舍入到最近的分钟,对于分钟,它将向下舍入到最近的小时,对于小时,它将向下舍入到最近的日期。对于闰秒和日历中的其他不规则情况,这种舍入可能并不完美,通常通过对自纪元以来的秒数进行基本模数来完成,假设每分钟60秒,每小时60分钟,以及24小时一天。update和deletetimeseries集合支持delete语句满足如下限制:只有支持metaField属性的查询语句才支持批量操作同时更新满足上面同样的条件,并遵循:只支持metaField对应的属性值的update操作指定更新操作更新文档(而不是替换文档或更新管道操作)不支持upsert:true操作。这些更新和删除执行将转换为底层桶集合的相应更新或删除操作。特别是,对于查询和更新文档,我们将集合的metaField替换为实际的字段元。(参见Bucket集合规范)例如,对于使用metaField:"tag"创建的时间序列集合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"}}.然后可以像正常更新操作一样执行此转换后的更新语句。上述转换过程同样适用于删除操作。参考资料MongoDB博客:时序数据与MongoDB:第2部分-Schema设计最佳实践作者简介:黄黄目前就职于上海德比软件,主要从事基础设施方面的业务流程设计和研发,日常中经常使用MongoDB工作。在提高自己外语能力的同时,也希望能为社会做点小小的贡献。