ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Apache Druid 相对误差分位数聚合:druid-ddsketch 扩展实战指南

Apache Druid 相对误差分位数聚合:druid-ddsketch 扩展实战指南 数据库OLAP大数据后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid6/druid点击查看免费下载导读本文面向在 Apache Druid 中需要分析长尾分布数据的开发者系统讲解druid-ddsketch扩展contrib 级扩展的核心用法如何使用ddSketch聚合器在摄入期或查询期构建 DDSketch 近似分位数草图并通过quantilesFromDDSketch/quantileFromDDSketch后聚合器一次性提取 p50、p75、p90、p99 等分位数。读完本文你将掌握该扩展的完整配置参数、内存与精度权衡、合并约束以及其底层实现原理可直接套用到网络延迟、响应耗时等指标监控场景中。一、为什么需要 DDSketch相对误差对长尾分布的意义druid-ddsketch模块基于 DataDog 开源的 sketches-java 库当前仓库中依赖版本为com.datadoghq:sketches-java:0.8.2见 extensions-contrib/ddsketch/pom.xml实现近似分位数查询的聚合器与后聚合器。与传统分位数草图的关键区别在于相对误差relative error保证如果真实分位数值是 100那么相对误差为 1% 的草图保证返回的分位数值介于 99 到 101 之间。也就是说误差与被估计值的大小成正比而不是一个固定绝对值。这种特性对**长尾分布long tail distribution**极其重要——例如网络延迟场景下p99 可能是几十毫秒而 p999 可能是几秒使用绝对误差会要么在小数值处过宽、要么在大数值处失去意义相对误差则让草图在整个量级范围内保持一致的精度保证。因此 DDSketch 最适合的典型场景就是精确描述网络延迟这类长尾分布的上部分位数。此外DDSketch 具备**快速、可完全合并fully-mergeable**的特性草图之间可以无损合并天然适配 Druid 分布式架构下 segment 间、节点间的合并计算。二、加载扩展使用该扩展前需要将druid-ddsketch加入扩展加载列表。在common.runtime.properties中配置druid.extensions.loadList具体加载机制可参考 扩展加载文档druid.extensions.loadList[druid-ddsketch, ...]扩展加载后由 DDSketchModule.java 负责向 Druid 注册三个 JSON 类型ddSketch聚合器、quantilesFromDDSketch与quantileFromDDSketch后聚合器以及 DDSketch 对象的序列化器同时注册复杂指标 SerdeComplexMetrics.registerSerde供 segment 读写使用。三、ddSketch聚合器聚合结果是一个 DDSketch它是所有草图无论来自原始数据还是从 segment 读取的并集当聚合直接作用于原始数值时最终化finalize返回的单个数字表示纳入统计的数据点总数——这一点在源码中体现为finalizeComputation直接返回((DDSketch) object).getCount()见 DDSketchAggregatorFactory.java。ddSketch聚合器既可以消费原始数值也可以合并已预聚合的草图{ type : ddSketch, name : output_name, fieldName : input_name, relativeError : double(0, 1), numBins: int }参数说明propertydescriptionrequired?type必须为 ddSketch是name计算结果输出名称的字符串是fieldName输入字段的名称可包含草图或原始数值是relativeError描述草图存储精度必须是 0 到 1 之间的数否默认 0.011% 误差numBins草图允许用来描述分布的总 bin 数量直接影响最大内存占用。可用的 bin 越多能准确覆盖的分位数范围越大。在 2% 相对精度下覆盖 1 毫秒到 1 分钟之间的取值只需 275 个 bin覆盖 1 纳秒到 1 天之间的取值需要 800 个 bin否默认 10003.1 默认策略collapsingLowestDenseddSketch聚合器默认使用collapsingLowestDense策略进行草图存储与合并这在 DDSketchAggregator.java 中通过DDSketches.collapsingLowestDense(effectiveRelativeError, effectiveNumBins)创建合并阶段的聚合组合器同样使用该策略见 DDSketchAggregatorFactory.java。该策略的含义是为了保证最大值以最高精度被表示草图会折叠并合并较小的数值——小值被折叠进相邻 bin 后会失去精度保证。换言之这套默认配置刻意保住了长尾分布中最关心的高分位数大数值精度代价是小数值区间的精度损失。如果你的业务更关心低分位数或小数值的精度需要自行评估该策略是否符合预期。3.2 合并约束与内存上界源码中DDSketchUtils.matchingAggregatorFactoryExists与getMergingFactory均对草图的可合并性做了约束只有relativeError以及numBins完全相同的草图才能合并。因此同一数据源上的摄入期聚合与查询期聚合必须使用一致的relativeError否则合并行为不受保证。关于内存numBins直接决定最大内存占用。getMaxIntermediateSize()给出了精确的上界公式见 DDSketchAggregatorFactory.javanumBins × 8 字节 × 2正、负两个 store 8 字节zeroCount 8 字节gamma 8 字节indexOffset 4 字节interpolationEnum 12 字节protoscope 描述符以默认numBins 1000计算单个草图的最大中间大小约为 16,040 字节约 15.7 KB。numBins越大能覆盖的量级跨度越宽内存也随之线性增长实践中需要结合自身数据的量级范围选择。3.3 底层实现数值与草图的统一接纳从实现看DDSketchAggregator.aggregate()见 DDSketchAggregator.java对输入做类型分派输入为Number调用histogram.accept(doubleValue)将原始数值直接插入草图输入为DDSketch调用histogram.mergeWith(sketch)合并既有草图其他类型抛出IAEExpected a number or an instance of DDSketch。这正是一个聚合器同时支持原始数据与预计算草图的机制所在。此外还提供了对应的有界内存缓冲实现DDSketchBufferAggregator用于 GroupBy 等需要 buffer 化聚合的场景以及combine/makeAggregateCombiner用于分布式查询中跨节点草图合并。3.4 序列化与存储草图的持久化基于 protobufDDSketchObjectStrategy通过DDSketchProtoBinding.toProto(...).toByteArray()将草图序列化为字节写入 segment读取时再从 protobuf 反序列化并重建CollapsingLowestDenseStore见 DDSketchObjectStrategy.javaDDSketchUtils.deserialize则同时兼容 Base64 字符串与字节数组两种形态DDSketchUtils.java。查询结果中 DDSketch 会被DDSketchJsonSerializer以二进制protobuf 字节形式写出参见 DDSketchJsonSerializer.java。四、后聚合器从草图计算分位数要计算近似分位数在ddSketch聚合器生成的草图上调用后聚合器即可quantilesFromDDSketch一次计算一组分位数quantileFromDDSketch计算单个分位数。4.1 quantilesFromDDSketch批量分位数{ type : quantilesFromDDSketch, name : output_name, field : reference to DDSketch, fractions : array of doubles in [0,1] }propertydescriptionrequired?type必须为 quantilesFromDDSketch是name计算结果输出名称的字符串是field一个已计算的 ddSketch是fractions要计算的分位数数组元素为 0 到 1 之间的 double是该后聚合器的返回类型为DOUBLE_ARRAY。实现上它遍历fractions数组对每个分位调用sketch.getValueAtQuantile(f)并组装为double[]返回若草图为空sketch null || sketch.getCount() 0则返回Double.NaN见 DDSketchToQuantilesPostAggregator.java。需要注意源码要求fractions数组长度至少为 1空数组会被Preconditions.checkArgument拒绝。4.2 quantileFromDDSketch单分位数{ type : quantileFromDDSketch, name : output_name, field : reference to DDsketch, fraction : double [0,1] }propertydescriptionrequired?type必须为 quantileFromDDSketch是name计算结果输出名称的字符串是field一个已计算的 ddSketch是fraction要计算的分位数0 到 1 之间的 double是该后聚合器的返回类型为DOUBLE内部逻辑与批量版本一致空草图返回Double.NaN否则返回sketch.getValueAtQuantile(fraction)见 DDSketchToQuantilePostAggregator.java。五、完整示例摄入期预聚合 查询期取分位数5.1 摄入期构建草图以下聚合器在摄入ingest阶段直接对原始列value构建草图{ type: ddSketch, name: sketch, fieldName: value, relativeError: 0.01, numBins: 1000 }摄入期构建草图的好处是查询时只需合并已存草图开销更小这正是 DDSketchAggregator.java 注释中It generally makes sense to use this aggregator during the ingestion time所建议的做法。5.2 查询期合并草图并计算分位数对预聚合的草图执行查询使用ddSketch聚合器做合并、再以quantilesFromDDSketch后聚合器提取分位数{ aggregations: [{ type: ddSketch, name: sketch, fieldName: sketch }], postAggregations: [ { type: quantilesFromDDSketch, name: quantiles, fractions: [0.5, 0.75, 0.9, 0.99], field: { type: fieldAccess, fieldName: sketch } }] }这里field使用fieldAccess后聚合器引用上一步ddSketch聚合的输出sketch。fractions中的 0.5、0.75、0.9、0.99 分别对应中位数、p75、p90 与 p99。5.3 查询期实时构建草图的写法如果原始数值未在摄入期预聚合也可以在查询期直接对数值列构建草图。仓库测试 DDSketchAggregatorTest.javabuildingSketchesAtQueryTime展示了这种用法其查询体为{ queryType: groupBy, dataSource: test_datasource, granularity: ALL, dimensions: [], aggregations: [ {type: ddSketch, name: sketch, fieldName: value, relativeError: 0.005, numBins: 2000} ], postAggregations: [ {type: quantilesFromDDSketch, name: quantiles, fractions: [0.99, 0.995, 0.999, 1], field: {type: fieldAccess, fieldName: sketch}} ], intervals: [2016-01-01T00:00:00.000Z/2016-01-31T00:00:00.000Z] }测试中断言查询得到的 p99、p99.5、p999 等分位数与精确值误差在 1% 以内直观验证了相对误差保证。需要留意的是查询期构建草图会比摄入期构建更慢、更耗资源适合低频分析或未预聚合的历史数据。六、测试与验证仓库中的行为证据仓库为druid-ddsketch提供了覆盖聚合器与后聚合器的单元测试可作为理解与验证行为的参考DDSketchAggregatorTest.java覆盖摄入期构建草图buildingSketchesAtIngestionTime对[0, 0.5, 1]三个分位做断言校验最小值、中位数与最大值与查询期构建草图两个端到端流程并验证聚合器 JSON 序列化/反序列化的等值性serializeDeserializeFactoryWithFieldName。DDSketchAggregatorFactoryTest.java验证ddSketch聚合器的结果类型签名——其输出为复杂类型ColumnType.ofComplex(ddSketch)即DDSketchAggregatorFactory.TYPE。七、使用注意事项合并前提仅当relativeError相同源码中同时校验numBins时草图才可合并摄入期与查询期的精度参数应保持一致。默认策略的取舍collapsingLowestDense优先保证大数值精度小数值区间在折叠后不再有精度保证若业务对低分位数敏感需谨慎评估。内存规划单个草图的中间大小上界约为numBins × 16 字节 常量默认 1000 bin 约 15.7 KB需按并发与数据规模评估内存占用。空草图行为当合并结果为 null 或 count 为 0 时两个后聚合器均返回Double.NaN前端消费结果时需做 NaN 处理。输出类型quantilesFromDDSketch返回 double 数组DOUBLE_ARRAYquantileFromDDSketch返回单个 double两者不可混用。finalize 语义ddSketch聚合器最终化返回的是数据点总数getCount()而不是草图本身草图对象需通过后聚合器在查询内消费。八、小结druid-ddsketch以相对误差保证为核心卖点为 Apache Druid 补齐了对网络延迟等长尾分布数据的高质量分位数分析能力摄入期用ddSketch聚合器以可控内存预聚合草图查询期通过quantilesFromDDSketch/quantileFromDDSketch高效提取任意组合的分位数。结合本仓库中 聚合器工厂、后聚合器 与 端到端测试 的源码级佐证读者可以放心将其纳入生产环境的延迟监控与容量评估体系。赞分享数据库OLAP大数据后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid6/druid点击查看免费下载相关推荐Apache Druid druid-stats 扩展方差与标准差聚合器完整指南Apache Druid druid stats 扩展方差与标准差聚合器完整指南 本篇技术指南讲解 Apache Druid 的 druid stats 扩展数据库OLAP大数据后端Apache Druid T-Digest Quantiles Sketch 扩展近似分位数聚合与实战指南Apache Druid T Digest Quantiles Sketch 扩展近似分位数聚合与实战指南 T Digest Quantiles Sketch数据库OLAP大数据后端Apache Druid momentsketch 扩展实战基于矩统计的近似分位数聚合与查询Apache Druid momentsketch 扩展实战基于矩统计的近似分位数聚合与查询 本指南讲解 Apache Druid 官方扩展 druid mo数据库OLAP大数据后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表