Druid批处理:大规模数据加载方案

Druid批处理:大规模数据加载方案

【免费下载链接】druid 【免费下载链接】druid 项目地址: https://gitcode.com/gh_mirrors/dr/druid

你是否在处理海量数据时遇到加载缓慢、资源占用过高的问题?是否需要一种既能保证数据完整性又能提升处理效率的解决方案?本文将详细介绍Apache Druid的批处理数据加载方案,帮助你快速掌握大规模数据的高效加载方法。读完本文后,你将了解Druid批处理的两种主要任务类型、并行索引的工作原理、配置方法以及实际操作流程,并能通过示例快速上手。

批处理任务类型

Apache Druid支持两种基于JSON的批处理索引任务,分别适用于不同的场景:

  • Parallel task indexing(index_parallel:可以同时运行多个索引任务,非常适合生产环境中的数据摄入任务。它能够充分利用集群资源,显著提高数据加载速度。
  • Simple task indexing(index:一次只能运行单个索引任务,适用于开发和测试环境。

本文主要介绍index_parallel任务的配置和使用,这是生产环境中推荐的批处理方案。有关批处理索引的更多相关信息,可以参考:

并行索引工作原理

index_parallel任务是一个多线程批处理索引任务,它仅依赖Druid自身资源,不依赖Hadoop等外部系统。其工作流程如下:

  1. 任务协调index_parallel任务作为协调任务协调整个索引过程,它会将输入数据分割并创建工作任务来处理各个数据部分。
  2. 任务调度:协调任务将工作任务提交给Overlord服务,Overlord在Middle Managers或Indexers上调度和运行这些工作任务。
  3. 结果汇报:每个工作任务成功处理分配的数据部分后,会向协调任务报告生成的段列表。
  4. 任务监控与重试:协调任务定期检查工作任务的状态,如果任务失败,会重试直到达到配置的重试次数上限。
  5. 段发布:当所有工作任务成功完成后,协调任务会一次性发布所有报告的段并完成数据摄入。

并行任务的详细行为因partitionsSpec的不同而有所差异,具体可参考partitionsSpec部分。

并行任务需要满足以下条件:

  • ioConfig中使用可分割的inputSource,具体支持的可分割输入格式可参考可分割输入源
  • tuningConfig中的maxNumConcurrentSubTasks大于1,否则任务将顺序运行。

数据加载界面

在Web控制台中,你可以通过Load Data UI来定义和提交摄入规范。以下是数据加载过程中的界面示例,展示了批处理数据加载的配置步骤:

批处理数据加载步骤1

批处理数据加载步骤2

批处理数据加载步骤3

批处理数据加载步骤4

批处理数据加载步骤5

批处理数据加载步骤6

批处理数据加载步骤7

提交索引任务

要运行基于JSON的批处理索引任务,可以通过以下两种方式:

使用Web控制台

通过Web控制台中的Load Data UI定义并提交摄入规范,这种方式直观易用,适合初学者。

使用API或脚本

  1. 根据示例和批处理索引参考主题定义JSON格式的摄入规范。
  2. 将摄入规范POST到Tasks API端点,即Overlord服务的/druid/indexer/v1/task接口。
  3. 或者,使用Druid提供的索引脚本bin/post-index-task

并行索引示例

以下是一个并行索引任务的配置示例,你可以根据自己的需求进行修改:

点击查看示例
{
  "type": "index_parallel",
  "spec": {
    "dataSchema": {
      "dataSource": "wikipedia_parallel_index_test",
      "timestampSpec": {
        "column": "timestamp"
      },
      "dimensionsSpec": {
        "dimensions": [
          "country",
          "page",
          "language",
          "user",
          "unpatrolled",
          "newPage",
          "robot",
          "anonymous",
          "namespace",
          "continent",
          "region",
          "city"
        ]
      },
      "metricsSpec": [
        {
          "type": "count",
          "name": "count"
        },
        {
          "type": "doubleSum",
          "name": "added",
          "fieldName": "added"
        },
        {
          "type": "doubleSum",
          "name": "deleted",
          "fieldName": "deleted"
        },
        {
          "type": "doubleSum",
          "name": "delta",
          "fieldName": "delta"
        }
      ],
      "granularitySpec": {
        "segmentGranularity": "DAY",
        "queryGranularity": "second",
        "intervals": [
          "2013-08-31/2013-09-02"
        ]
      }
    },
    "ioConfig": {
      "type": "index_parallel",
      "inputSource": {
        "type": "local",
        "baseDir": "examples/indexing/",
        "filter": "wikipedia_index_data*"
      },
      "inputFormat": {
        "type": "json"
      }
    },
    "tuningConfig": {
      "type": "index_parallel",
      "partitionsSpec": {
        "type": "single_dim",
        "partitionDimension": "country",
        "targetRowsPerSegment": 5000000
      },
      "maxNumConcurrentSubTasks": 2
    }
  }
}

并行索引配置

并行索引任务的配置主要包括以下几个部分:

主要配置 sections

属性描述是否必填
type任务类型,对于并行任务索引,设置为index_parallel
id任务ID,如果省略,Druid会使用任务类型、数据源名称、时间间隔和时间戳生成任务ID
spec定义data schemaIO configtuning config的摄入规范
context指定各种任务配置参数的上下文,详见任务上下文参数

dataSchema

该字段是必填项,它定义了Druid存储数据的方式,包括主时间戳列、维度、指标和任何转换。概述详见Ingestion Spec DataSchema

为索引并行定义granularitySpec时,如果知道数据的时间范围,建议显式定义intervals。这样可以更快地发现锁定失败,并且Druid不会意外替换某些行包含意外时间戳的数据。

ioConfig

ioConfig的属性如下表所示:

属性描述默认值是否必填
type任务类型,设置为index_parallel
inputFormatinputFormat,用于指定如何解析输入数据
appendToExisting创建段作为最新版本的额外分片,有效地追加到段集而不是替换它。这意味着可以将新段追加到任何数据源,无论其原始分区方案如何。必须对追加的段使用dynamic分区类型。如果指定了不同的分区类型,任务将失败并出错false
dropExisting如果为true,且appendToExistingfalse,并且granularitySpec包含interval,则摄入任务在发布新段时会替换所有完全包含在指定interval内的现有段。如果摄入失败,Druid不会更改任何现有段。在appendToExistingtruegranularitySpec中未指定interval的错误配置情况下,即使dropExistingtrue,Druid也不会替换任何段。警告:此功能仍处于实验阶段false

tuningConfig

tuningConfig是可选的,如果未指定,Druid会使用默认参数。其属性如下表所示:

属性描述默认值是否必填
type任务类型,设置为index_parallel
maxRowsInMemory确定Druid何时执行中间持久化到磁盘。通常不需要设置此值。根据数据的性质,如果行的字节数较短,例如,可能不希望在内存中存储一百万行,这时可以设置此值1000000
maxBytesInMemory用于确定Druid何时执行中间持久化到磁盘。通常Druid会在内部计算此值,无需设置。此值表示在持久化之前在堆内存中聚合的字节数,基于内存使用的粗略估计,而非实际使用情况。索引的最大堆内存使用量为maxBytesInMemory * (2 + maxPendingPersists)。注意,maxBytesInMemory还包括从中间持久化创建的工件的堆使用量。这意味着每次持久化后,直到下一次持久化的maxBytesInMemory量会减少。当所有中间持久化工件的字节总和超过maxBytesInMemory时,任务失败JVM最大内存的1/6
maxColumnsToMerge发布时合并段时,单个阶段合并的段数限制。此限制会影响要合并的一组段中存在的总列数。如果超过限制,段合并会分多个阶段进行。无论此设置如何,每个阶段至少合并2个段-1(无限制)
maxTotalRows已弃用,使用partitionsSpec代替。等待推送的段中的总行数,用于确定何时应进行中间推送20000000
numShards已弃用,使用partitionsSpec代替。使用hashed partitionsSpec时直接指定要创建的分片数。如果指定了此值并且在granularitySpec中指定了intervals,索引任务可以跳过通过数据确定间隔/分区的过程null
splitHintSpec用于控制每个第一阶段任务读取的数据量的提示。根据输入源的实现,Druid可能会忽略该提示,详见Split hint spec基于大小的拆分提示规范
partitionsSpec定义如何在每个timeChunk中分区数据,详见PartitionsSpec如果forceGuaranteedRollup = false,则为dynamic;如果forceGuaranteedRollup = true,则为hashedsingle_dim
indexSpec定义索引时使用的段存储格式选项,详见IndexSpecnull
indexSpecForIntermediatePersists定义索引时用于中间持久化临时段的段存储格式选项。可以使用此配置禁用中间段的维度/指标压缩,以减少最终合并所需的内存。但是,如果禁用中间段的压缩,在Druid将它们合并为最终发布的段之前,页面缓存的使用可能会增加,详见IndexSpecindexSpec相同
maxPendingPersists保持未开始的最大挂起持久化数。如果新的中间持久化超过此限制,摄入将阻塞,直到当前运行的持久化完成。索引的最大堆内存使用量与maxRowsInMemory * (2 + maxPendingPersists)成比例0(意味着一个持久化可以与摄入同时运行,没有可以排队的持久化)
forceGuaranteedRollup强制perfect rollup。完美的rollup可以优化生成段的总大小和查询时间,但会增加索引时间。如果为true,在granularitySpec中指定intervals,并对partitionsSpec使用hashedsingle_dim。不能将此标志与IOConfigappendToExisting结合使用,详见Segment pushing modesfalse
reportParseExceptions如果为true,Druid会抛出解析过程中遇到的异常并停止摄入;如果为false,Druid会跳过无法解析的行和字段false
pushTimeout等待推送段的毫秒数,必须 >= 0,0表示永远等待0
segmentWriteOutMediumFactory创建段时使用的段写出介质,详见SegmentWriteOutMediumFactory如果未指定,使用druid.peon.defaultSegmentWriteOutMediumFactory.type的值
maxNumConcurrentSubTasks可以同时并行运行的最大工作任务数。协调任务会生成工作任务,直到达到maxNumConcurrentSubTasks,而不管可用的任务槽数量。如果此值设置得太大,协调者可能会创建太多工作任务,从而阻碍其他摄入任务,详见Capacity planning1
maxRetry任务失败的最大重试次数3
maxNumSegmentsToMergeforceGuaranteedRollup为true时,合并阶段中单个任务可以同时合并的最大段数100
totalNumMergeTaskspartitionsSpec设置为hashedsingle_dim时,合并阶段中合并段的任务总数10
taskStatusCheckPeriodMs检查运行任务状态的轮询周期(毫秒)1000
chatHandlerTimeout工作任务中报告推送段的超时时间PT10S
chatHandlerNumRetries工作任务中报告推送段的重试次数5
awaitSegmentAvailabilityTimeoutMillis摄入完成后等待新索引的段可用于查询的毫秒数。如果<= 0,则不等待。如果> 0,任务会等待协调器指示新段可用于查询。如果超时,任务成功退出,但段未确认可用于查询Long否(默认=0)

Split Hint Spec

拆分提示规范用于帮助协调任务划分输入源,每个工作任务处理一个输入分区。可以控制第一阶段中每个工作任务读取的数据量。

Size-based Split Hint Spec

基于大小的拆分提示规范影响除HTTP输入源和SQL输入源之外的所有可拆分输入源。

属性描述默认值是否必填
type设置为maxSize
maxSplitSize单个子任务处理的输入文件的最大字节数。如果单个文件大于限制,Druid会在单个子任务中单独处理该文件。Druid不会跨任务拆分文件。即使多个文件的总大小小于maxSplitSize,一个子任务也不会处理超过maxNumFiles的文件。支持Human-readable format1GiB
maxNumFiles单个子任务处理的最大输入文件数。此限制可避免摄入规范过长时导致任务失败。序列化摄入规范的最大大小有两个已知限制:ZooKeeper中的最大ZNode大小(jute.maxbuffer)和MySQL中的最大数据包大小(max_allowed_packet)。当序列化摄入规范大小达到其中一个限制时,可能会导致摄入任务失败。即使文件总数小于maxNumFiles,一个子任务也不会处理超过maxSplitSize的数据1000
Segments Split Hint Spec

段拆分提示规范仅用于DruidInputSource

属性描述默认值是否必填
type设置为segments
maxInputSegmentBytesPerTask单个子任务处理的输入段的最大字节数。如果单个段大于此数量,Druid会在单个子任务中单独处理该段。Druid永远不会跨任务拆分输入段。即使段总数小于maxNumSegments,一个子任务也不会处理超过maxInputSegmentBytesPerTask的数据。支持Human-readable format1GiB
maxNumSegments单个子任务处理的最大输入段数。此限制可避免摄入规范过长时导致任务失败。序列化摄入规范的最大大小有两个已知限制:ZooKeeper中的最大ZNode大小(jute.maxbuffer)和MySQL中的最大数据包大小(max_allowed_packet)。当序列化摄入规范大小达到其中一个限制时,可能会导致摄入任务失败。即使段总数小于maxNumSegments,一个子任务也不会处理超过maxInputSegmentBytesPerTask的数据1000

partitionsSpec

Druid的主要分区是时间,可以在分区规范中定义二级分区方法。根据rollup方法选择适用的partitionsSpec类型。

对于完美rollup,可以使用:

  • hashed:基于每行指定维度的哈希值进行分区
  • single_dim:基于单个维度的值范围进行分区
  • range:基于多个维度的值范围进行分区

对于最佳rollup,使用dynamic

概述详见Partitioning

不同partitionsSpec类型的特点如下表所示:

PartitionsSpec摄入速度分区方法支持的rollup模式查询时的二级分区剪枝
dynamic最快基于段中行数的Dynamic partitioning最佳rollupN/A
hashed中等基于多个维度的hash-based partitioning,通过改善数据局部性可能减少数据源大小和查询延迟,详见Partitioning完美rollup代理可以使用分区信息提前剪枝段以加快查询速度。由于代理知道如何对partitionDimensions值进行哈希以定位段,因此给定包含所有partitionDimensions过滤器的查询,代理可以仅选择持有满足partitionDimensions过滤器的行的段进行查询处理。

注意,必须在摄入时设置partitionDimensions才能在查询时启用二级分区剪枝
single_dim较慢基于单个维度的range partitioning,通过改善数据局部性可能减少数据源大小和查询延迟,详见Partitioning完美rollup代理可以使用分区信息提前剪枝段以加快查询速度。由于代理知道每个段中partitionDimension值的范围,因此给定包含partitionDimension过滤器的查询,代理可以仅选择持有满足partitionDimension过滤器的行的段进行查询处理
Dynamic partitioning
属性描述默认值是否必填
type设置为dynamic
maxRowsPerSegment用于分片,确定每个段中的行数5000000
maxTotalRows等待推送的所有段的总行数,用于确定何时应进行中间段推送20000000

使用动态分区时,并行索引任务在单个阶段运行,生成多个工作任务(类型为single_phase_sub_task),每个任务创建段。

工作任务创建段的方式如下:

  • 每当当前段中的行数超过maxRowsPerSegment时。
  • 当所有时间块的所有段中的总行数达到maxTotalRows时。此时任务会将所有已创建的段推送到深度存储并创建新段。
Hash-based partitioning
属性描述默认值是否必填
type设置为hashed
numShards直接指定要创建的分片数。如果指定了此值并且在granularitySpec中指定了intervals,索引任务可以跳过通过数据确定间隔/分区的过程。此属性和targetRowsPerSegment不能同时设置
targetRowsPerSegment每个分区的目标行数。如果未指定numShards,并行任务会自动确定分区数,使得每个分区的行数接近目标,假设输入数据中的键分布均匀。如果numShardstargetRowsPerSegment均为null,则使用每个段500万行的目标null(如果numShardstargetRowsPerSegment均为null,则为5,000,000)
partitionDimensions要分区的维度,留空则选择所有维度null

总结与展望

本文详细介绍了Druid批处理数据加载方案,包括批处理任务类型、并行索引的工作原理、提交任务的方法、配置示例以及各主要配置项的说明。通过合理配置并行索引任务,可以高效地处理大规模数据加载,充分利用集群资源,提高数据处理速度。

在实际应用中,建议根据数据量、集群规模和业务需求选择合适的批处理任务类型和配置参数。对于生产环境,优先使用index_parallel任务,并根据数据特点调整partitionsSpecsplitHintSpec等参数以达到最佳性能。

未来,Druid可能会进一步优化批处理性能,提供更智能的分区策略和资源管理机制,帮助用户更轻松地处理海量数据。建议持续关注Druid的官方文档和更新日志,及时了解新功能和最佳实践。

如果你觉得本文对你有帮助,请点赞、收藏并关注,以便获取更多关于Druid的实用教程和最佳实践。下期我们将介绍Druid的实时数据摄入方案,敬请期待!

【免费下载链接】druid 【免费下载链接】druid 项目地址: https://gitcode.com/gh_mirrors/dr/druid

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值