ARTICLE DETAIL

资讯详情

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

Apache Druid Coordinator 服务深度解析:段管理、负载均衡与自动压缩机制

Apache Druid Coordinator 服务深度解析:段管理、负载均衡与自动压缩机制 Apache Druid Coordinator 服务深度解析段管理、负载均衡与自动压缩机制【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druidCoordinator 是 Apache Druid 集群中负责数据拓扑的核心控制服务它周期性评估集群状态决定哪些段Segment应该在哪些 Historical 节点上加载、复制、卸载或迁移并驱动自动压缩与元数据清理。本文以 docs/design/coordinator.md 为主线结合仓库源码与配置文档系统讲解 Coordinator 的运行机制、全部核心配置项、自动压缩策略与常见问题帮助读者掌握 Druid 集群数据分布的自愈与优化原理。Coordinator 在集群中的定位与核心职责在 Druid 的多服务架构中Coordinator 是一个管理型服务它不参与任何查询路径。它的全部职责集中在一个领域段的加载、卸载、复制与平衡。具体来说Coordinator 会根据配置向 Historical 服务发出加载或卸载段的指令负责加载新段、淘汰过期段确保每个段按照配置的复制因子replication factor被加载到多个不同的 Historical 节点上在 Historical 节点之间迁移balancing段使各节点负载尽量均匀。从源码结构看Coordinator 的核心实现集中在 server/src/main/java/org/apache/druid/server/coordinator/DruidCoordinator.java它维护了集群当前状态的内存视图并周期性驱动各类 Coordinator Duty 执行具体动作。Coordinator 与 ZooKeeper、元数据库的关系与 Broker、Historical 服务类似Coordinator 也会连接到ZooKeeper 集群以获取当前集群状态信息。除此之外Coordinator 还维护着一个到元数据库的连接从中读取两类关键信息已使用used段的元数据——即集群中应该被加载的段集合加载规则loading rules——决定各数据源段在哪个层级tier加载、复制多少份、保留多久。Coordinator 正是以元数据库中的 used 段 规则为期望状态以ZooKeeper 中 Historical 实际服务的段为当前状态两者对比后产生具体的协调动作。向 Historical 下发指令的方式Load Queue值得强调的一个设计细节是Coordinator 从不直接与 Historical 服务通信。当它决定把某个段分配给某个 Historical 时它只是在目标 Historical 的load queue 路径ZooKeeper 节点下创建一段临时信息。Historical 服务一旦在 ZooKeeper 上看到这个请求就会自行加载该段并开始对外服务。这种解耦设计让 Historical 完全感知不到 Coordinator 的存在也让段的分发具备异步、可重试的特性。周期性运行机制与段分配策略Coordinator 以周期任务的方式运转两次运行之间的间隔是可配置参数见下文druid.coordinator.period。每次运行前Coordinator 会先评估集群的当前状态再决定需要执行的动作。在段分配上有一个重要规则在任意层级tier内Historical 服务先按容量排序容量最小的服务器拥有最高优先级未被分配的段总是优先分配给容量最小的服务器。这样做的目的是在分配阶段就维持各服务器之间的负载均衡。Coordinator 配置详解Coordinator 的配置分为静态配置写在common.runtime.properties中需要重启生效与动态配置通过 API 或 Web 控制台在线调整无需重启两大类。完整配置表见 docs/configuration/index.md#coordinator。静态配置核心项配置项说明默认值druid.coordinator.periodCoordinator 的运行周期。Coordinator 在内存中维护世界当前状态周期性地对比used段集合与正在服务的段决定是否需要调整数据拓扑PT60Sdruid.coordinator.period.indexingPeriod向索引服务Indexing Service提交 compact/merge/conversion 任务的频率建议长于druid.manager.segments.pollDurationPT1800S30 分钟druid.coordinator.startDelay启动延迟。Coordinator 的运行建立在已获得最新世界状态的假设之上但当前 ZooKeeper 交互代码无法保证这一点该延迟用于给 Coordinator 足够时间加载完整状态PT300Sdruid.coordinator.load.timeoutCoordinator 把段分配给 Historical 服务的超时时间PT15Mdruid.coordinator.balancer.strategy负载均衡策略。cachingCost在逻辑上等价于cost但在大集群上 CPU 效率更高diskNormalized按服务器磁盘使用率加权存在分布不均的已知问题random随机分布costdruid.coordinator.balancer.cachingCost.awaitInitialization是否在创建cachingCost策略前等待段视图初始化。仅当balancer.strategy为cachingCost时生效为false时若视图未初始化则回退到cost策略falsedruid.coordinator.loadqueuepeon.http.repeatDelay管理各服务器加载/卸载队列的 load queue peon 的启动与重复延迟毫秒1 分钟druid.coordinator.loadqueuepeon.http.batchSize单次 HTTP 请求中批量处理的段加载/卸载请求数必须小于 Historical 上的druid.segmentCache.numLoadingThreads1druid.coordinator.asOverlord.enabled是否让 Coordinator 同时扮演 Overlord从而简化集群部署无需独立 Overlord 节点。开启后 Overlord 控制台位于http://coordinator-host:port/console.htmlfalsedruid.coordinator.asOverlord.overlordServiceasOverlord.enabledtrue时必填必须与独立 Overlord 的druid.service及 Middle Manager 的druid.selectors.indexing.serviceName保持一致无此外还有一组与元数据清理kill相关的静态配置控制 Coordinator 是否周期性提交 kill 任务以永久删除未使用段、过期 supervisor、audit 日志、规则、数据源元数据等例如druid.coordinator.kill.on是否提交 kill 任务永久删除未使用段从元数据库与深度存储中删除默认truedruid.coordinator.kill.period提交 kill 任务的频率必须大于等于druid.coordinator.period.indexingPerioddruid.coordinator.kill.durationToRetain未使用段的段区间结束时间早于now - durationToRetain才允许被 kill作用于段区间而非标记时间默认P90Ddruid.coordinator.kill.bufferPeriod段被标记为 unused 后必须经过的缓冲期防止误删默认P30Ddruid.coordinator.kill.maxSegments每个 kill 任务最多删除的未使用段数量默认100druid.coordinator.kill.pendingSegments.on是否清理元数据存储pendingSegments表中的旧条目默认true。动态配置核心项动态配置可通过 Web 控制台推荐或 Coordinator 动态配置 API 在线调整详见 docs/configuration/index.md#dynamic-configuration。属性说明默认值millisToWaitBeforeDeletingCoordinator 成为 leader 后需等待多久才能开始在元数据存储中把被遮蔽段标记为 unused90000015 分钟maxSegmentsToMove单个层级在任意时刻最多可迁移的段数量100replicantLifetime段在 Historical 加载队列中最多可等待多少个 Coordinator 运行周期超出则触发告警15replicationThrottleLimit单个 Coordinator 运行周期内可分配给某个层级的段副本总数防止 Historical 因加载过多副本而过载500balancerComputeThreads段均衡时计算迁移代价的线程池大小段很多时可适当调大num_cores / 2maxSegmentsInNodeLoadingQueue单台服务器加载队列中允许的最大段数量500useRoundRobinSegmentAssignment是否以轮询方式向 Historical 分配段。开启时可加速分配均衡工作留给 balancer 延迟完成truedecommissioningNodes待退役的 Historical 服务器列表。Coordinator 不再向它们分配新段并以maxSegmentsToMove指定的速率把段迁走无pauseCoordination是否暂停全部协调工作同时保持 API 可用。适用于深度存储维护等需要临时冻结数据拓扑的场景falsereplicateAfterLoadTimeout对因druid.coordinator.load.timeout超时而加载失败的段是否进行额外复制falseSmart Segment Loading 模式smartSegmentLoading默认true是动态配置中的一个自动调优开关开启后Druid 会根据集群当前状态自动计算上表中的多个属性此时你不应再手动提供这些属性的值因为 Coordinator 会忽略你提供的值。被接管计算的属性及计算规则包括属性计算值说明useRoundRobinSegmentAssignmenttrue加速段分配maxSegmentsInNodeLoadingQueue0取消加载队列大小限制replicationThrottleLimitused 段的 5%最小 100防止 Historical 短暂消失时产生激进的复制replicantLifetime60按 1 分钟周期估算允许段在加载队列中等待约 1 小时maxSegmentsToMoveused 段的 2%最小 100、最大 1000保证集群持续有段在迁移以维持均衡同时限制运行时间balancerComputeThreadsnum_cores / 2保证均衡计算有足够线程又不至于占满资源只有当你想显式控制上述某个属性时才应关闭smartSegmentLoading。启动方式与 HTTP 端点Coordinator 通过 Druid 的统一命令行入口启动org.apache.druid.cli.Main server coordinator启动后Coordinator 会暴露一组 HTTP 端点包括协调器状态、规则、段信息、负载均衡状态、压缩配置管理、动态配置读写等。完整端点列表见 Service status API 参考其中与本文主题直接相关的还包括自动压缩配置 API查看与更新各数据源的自动压缩配置动态配置 API在线读写上文所述的动态配置。关于 Coordinator 的部署容量与调优建议可参考 基础集群调优。规则与段生命周期管理段的自动加载与淘汰由**规则Rules**驱动。规则决定了某个数据源的段在什么时间段、在哪个层级tier加载、保留多久以及被淘汰后的去向。完整规则体系见 Rule Configuration。清理被遮蔽段Overshadowed Segments每次运行时Coordinator 都会比较元数据库中的 used 段集合与集群中 Historical 节点正在服务的段集合并向 Historical 发送请求卸载不再使用的段或已从元数据库移除的段。关键机制是遮蔽overshadowing当一个段的数据已被更新版本更高 version的段替换时旧段即为被遮蔽段。这些被遮蔽段会在下一次协调周期中被标记为 unused并在随后的 Coordinator 运行中被从 Historical 节点卸载。细节millisToWaitBeforeDeleting规定了 Coordinator 成为 leader 后必须等待多久才能开始标记被遮蔽段为 unused这是为了防止 leader 切换初期状态尚未完全同步时误删数据。清理非遮蔽的 Eternity Tombstone 段每次运行时Coordinator 还会为每个数据源识别并清理不再需要的eternity tombstone 段即覆盖全时间范围边界的墓碑段用于标记某区间数据已删除。一个段只有同时满足以下所有条件才会被清理是墓碑段tombstone且区间起点为-INF或终点为INF例如区间为-146136543-09-08T08:23:32.096Z/2000-01-01、2020-01-01/146140482-04-24T15:36:27.903Z或-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z不与任何被遮蔽段重叠拥有 0 个核心分区core partitions。段可用性缺失节点的恢复机制如果某个 Historical 服务重启或暂时不可用Coordinator 会发现该服务消失并把该服务承载的所有段视为已丢失。在足够长的时间后这些段可能被重新分配到集群中的其他 Historical 服务上。但被丢弃的段不会立刻被遗忘Coordinator 内部有一个过渡数据结构记录所有被丢弃的段及其关联的生命周期lifetime。生命周期表示一个时间窗口在此窗口内 Coordinator不会重新分配被丢弃的段。因此如果某个 Historical 服务在短时间内恢复上线它会直接从本地缓存继续服务这些段而不会出现段被重新分配、造成集群内重复加载或抖动的情况。该机制对应的动态配置是replicantLifetime段在加载队列中的最大等待周期数与replicationThrottleLimit单周期内可分配的最大副本数它们共同防止节点抖动时触发过度复制风暴。负载均衡Balancing Segment Load为了确保段在集群各 Historical 服务间均匀分布Coordinator 每次运行时都会执行以下流程统计每个 Historical 服务当前服务的所有段的总大小针对集群中的每一个层级tier找出利用率最高的服务和利用率最低的服务计算两者的利用率百分比差异若差异超过某个阈值则将一定数量的段从高利用率服务迁移到低利用率服务每次运行时单次迁移的段数量有可配置上限maxSegmentsToMove默认100待迁移段是随机选取的并且只有在迁移后计算出的高低利用率百分比差异确实下降时才会执行迁移——避免无效迁移。从源码结构看均衡逻辑由一组可插拔的BalancerStrategy实现位于 server/src/main/java/org/apache/druid/server/coordinator/balancer包括CostBalancerStrategy默认的基于代价的均衡策略CachingCostBalancerStrategycachingCost代价逻辑与cost等价但更省 CPUDiskNormalizedCostBalancerStrategydiskNormalized按磁盘使用率加权有分布不均的已知问题RandomBalancerStrategyrandom随机分布。策略选择通过静态配置druid.coordinator.balancer.strategy完成。自动压缩Automatic CompactionCoordinator 管理着 Druid 的自动压缩系统。每次运行时Coordinator 都会通过合并小段或拆分大段来执行压缩。当段大小未优化时查询性能会下降因此自动压缩是段优化的重要手段相关原理与收益详见 Segment size optimization。自动压缩的完整执行流程为Coordinator 根据段搜索策略找出需要压缩的段找到后为这些段提交一个 compact 任务最多可同时运行的压缩任务数为min(sum of worker capacity * slotRatio, maxSlots)即使min(sum of worker capacity * slotRatio, maxSlots) 0只要某个数据源启用了压缩也始终会提交至少一个压缩任务。自动压缩的启用与配置方式有两种通过 自动压缩配置 API 或通过 自动压缩动态配置 在线修改均无需重启 Coordinator。压缩任务失败的常见原因压缩任务可能因以下原因失败压缩任务的输入段在任务启动前被移除或被遮蔽——该压缩任务会立即失败更高优先级的任务获取了与压缩任务区间重叠的时间块锁time chunk lock——压缩任务会失败。默认情况下实时任务realtime的优先级高于压缩任务如果两者区间重叠实时任务会撤销压缩任务的锁并导致其终止。压缩任务失败后Coordinator 会在下一次运行时重新检查失败任务区间内的段并再次提交压缩任务形成检查-失败-重试的自愈闭环。将压缩 Duty 独立成组运行默认情况下Compacting Segments Coordinator Duty 会自动启用并作为Indexing Service Duties 组的一部分运行。但也可以通过配置把它放到独立的 duty 组中单独运行从而在不影响其他 Indexing Service Duties 运行周期的前提下单独调整压缩 Duty 的运行周期druid.coordinator.dutyGroups[SOME_GROUP_NAME] druid.coordinator.SOME_GROUP_NAME.duties[compactSegments] druid.coordinator.SOME_GROUP_NAME.periodPERIOD_TO_RUN_COMPACTING_SEGMENTS_DUTY从源码看这一机制建立在可插拔的CoordinatorCustomDuty扩展点上见 server/src/main/java/org/apache/druid/server/coordinator/duty/CoordinatorCustomDuty.javacompactSegments是JsonSubTypes中注册的内置 duty 类型。同一组内的所有 duty 共享相同的运行周期druid.coordinator.GROUP_NAME.period每个组由单个线程顺序执行。如果你想注册自己的自定义 duty可以参考 开发文档自定义可插拔 Coordinator Duty。自动压缩中的段搜索策略Segment Search Policy每次 Coordinator 运行时默认策略会从最新到最旧地查找各时间块time chunk并检查这些时间块中的段是否需要压缩。一个段集合需要压缩需要同时满足以下两个条件该时间块中段的总大小小于等于配置的inputSegmentSizeBytes这些段从未被压缩过或者自上次压缩以来压缩规格已更新例如maxTotalRows或indexSpec发生了变化。从源码看该策略的实现位于 server/src/main/java/org/apache/druid/server/coordinator/compact/NewestSegmentFirstPolicy.java其createIterator通过PriorityBasedCompactionSegmentIterator按intervalsByStartThenEnd的逆序即最新时间块优先迭代候选段。搜索策略示例假设有两个数据源foo和bar段分布如下foofoo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSIONfoo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION_1foo_2017-09-01T00:00:00.000Z_2017-10-01T00:00:00.000Z_VERSIONbarbar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSIONbar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSION_1假设每个段都是 10 MB 且尚未压缩则该策略会首先返回foo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION和foo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION_1这两个段一起压缩因为2017-11-01T00:00:00.000Z/2017-12-01T00:00:00.000Z是最新的时间块如果 Coordinator 有足够的压缩任务槽位会继续搜索并返回bar数据源2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSION与对应_1段最后即使2017-09-01T00:00:00.000Z/2017-10-01T00:00:00.000Z时间块中只有一个段foo_2017-09-01...VERSION它也会被选中压缩。skipOffsetFromLatest避开与实时任务的冲突搜索起点可以通过skipOffsetFromLatest调整。设置后策略会忽略落在最新段的结束时间 - skipOffsetFromLatest之后的时间块中的段。这样做的目的是避免压缩任务与实时任务冲突默认情况下实时任务优先级高于压缩任务如果两者区间重叠实时任务会撤销压缩任务的锁导致压缩任务终止。因此官方强烈建议为实时数据源设置skipOffsetFromLatest。例如Kafka、Kinesis 流式摄取经常处理迟到数据若不设置该参数压缩任务与实时任务的频繁冲突可能导致自动压缩停滞设置为skipOffsetFromLatest: P30D则意味着跳过最新段结束时间之前 30 天内的段。更详细的说明见 自动压缩中的数据冲突规避。已知限制当前策略无法处理同一区间内存在大量小段、且这些小段总大小超过inputSegmentSizeBytes的情况——遇到这类段它会直接跳过。自动压缩动态配置要点自动压缩的核心配置项通过动态配置 API 设置包括属性说明默认值dataSource要压缩的数据源名称必填taskPriority压缩任务优先级25inputSegmentSizeBytes每个压缩任务处理的最大段总字节数。由于时间块必须整体处理若某时间块段总大小超过该值则该时间块不执行压缩100,000,000,000,000100TBskipOffsetFromLatest搜索待压缩段的偏移量ISO 8601 格式实时数据源强烈建议设置P1DtuningConfig压缩任务的调优配置支持index_parallel任务 tuningConfig 的子集无granularitySpec/dimensionsSpec/transformSpec/metricsSpec/ioConfig自定义压缩后的段粒度、维度、过滤、指标与 IO 配置无一个最简配置示例{ dataSource: wikiticker, granularitySpec : { segmentGranularity : none } }FAQCoordinator 的常见疑问1. 客户端会直接联系 Coordinator 服务吗不会。Coordinator 完全不参与查询链路。Historical 服务从不直接联系 CoordinatorCoordinator 通过 ZooKeeper 告知 Historical 加载/卸载数据而 Historical 完全感知不到 Coordinator 的存在Broker 也从不联系 CoordinatorBroker 对数据拓扑的理解完全基于 Historical 通过 ZooKeeper 暴露的元数据同样感知不到 Coordinator。2. Coordinator 的启动顺序重要吗不重要。如果 Coordinator 没有启动集群不会加载任何新段也不会淘汰过期段但集群的查询与摄取功能不受影响。Coordinator 可以在任意时间启动并在可配置的延迟druid.coordinator.startDelay之后开始运行协调任务。这也意味着如果运行中的集群所有 Coordinator 全部宕机集群仍然可以继续正常工作只是数据拓扑不会发生任何变化——这正是 Coordinator 被设计为非查询路径服务所赋予的容错特性。小结Coordinator 是 Druid 数据层的大脑它通过周期性对比期望状态元数据库中的 used 段与规则和实际状态Historical 通过 ZooKeeper 上报的服务段驱动段的加载、复制、卸载与均衡并托管自动压缩与元数据清理。理解它的周期性运行机制、静态/动态双层配置体系、段可用性恢复的 lifetime 机制、基于代价的均衡策略以及最新优先的压缩段搜索策略是运维好 Druid 集群数据拓扑的基础。更多进阶内容可继续阅读 Rule Configuration、自动压缩 与 段大小优化。【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表