ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Apache Druid Router 服务全解析:查询路由、管理代理与 Avatica 连接均衡

2026/9/23 2:38:23 拓冰建站 浏览量
Apache Druid Router 服务全解析:查询路由、管理代理与 Avatica 连接均衡 Apache Druid Router 服务全解析查询路由、管理代理与 Avatica 连接均衡【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid导读Router 是 Apache Druid 集群中负责「查询分发」的边缘服务它位于客户端与 Broker 之间依据数据保留规则或自定义路由策略把查询请求分发到不同的 Broker 集合实现热/冷数据查询隔离同时它还承载着 Web 控制台与管理代理management proxy能力并负责 Avatica JDBC 请求的连接级均衡。读完本文你将掌握 Router 的启动方式、全部路由策略timeBoundary / priority / manual / JavaScript、管理代理的隐式与显式路由机制、Avatica 两种哈希均衡器的取舍以及一份可直接落地的生产环境配置模板。一、Router 在 Druid 集群中的定位Router 服务在 Druid 集群中承担两个核心职责在多个 Broker 服务之间分发查询。默认情况下Broker 依据预配置的数据保留规则来路由查询。例如最近一个月的数据被加载到hot集群中那么落在最近一个月时间范围内的查询会被路由到一组专用 Broker范围之外的查询则被路由到另一组 Broker。这种架构提供了查询隔离能力——重要数据的查询不会被次要数据的查询拖垮。承载 Web 控制台。Router 内嵌运行着 Web 控制台这是一个用于加载数据、管理 datasource 与 task、查看服务状态和 segment 信息的图形化界面。需要特别说明的是单从查询路由的角度看只有当 Druid 集群规模进入 TB 级之后你才真正需要引入 Router 服务。在中小规模集群中客户端直接连接 Broker 即可。源码佐证Router 运行时配置的默认值从 Router 运行时配置表见下文第四节可以看到Router 的路由行为完全由druid.router.*系列属性驱动例如默认 Broker 服务名druid.router.defaultBrokerServiceName的默认值为druid/broker默认策略列表为[{type:timeBoundary},{type:priority}]这些默认值直接决定了 Router 开箱即用时的行为。二、启动 Router 服务Router 是标准 Druid 服务进程启动入口与其它 Druid 服务一致org.apache.druid.cli.Main server router仓库自带的集群示例配置中examples/conf/druid/cluster/query/router/main.config 恰好就是这个启动命令而 examples/conf/druid/cluster/query/router/runtime.properties 给出了 Router 的典型运行时配置druid.servicedruid/router druid.plaintextPort8888 # HTTP proxy druid.router.http.numConnections50 druid.router.http.readTimeoutPT5M druid.router.http.numMaxThreads100 druid.server.http.numThreads100 # Service discovery druid.router.defaultBrokerServiceNamedruid/broker druid.router.coordinatorServiceNamedruid/coordinator # Management proxy to coordinator / overlord: required for unified web console. druid.router.managementProxy.enabledtrue可以看到示例中已经默认开启了管理代理druid.router.managementProxy.enabledtrue因为统一 Web 控制台依赖它访问 Coordinator 与 Overlord。相关文档入口配置项全表参见 Router 配置。调优指引参见 基础集群调优 中关于 Router 的小节。HTTP 端点Router 支持的 API 端点列表参见 Legacy metadata API reference。Router 运行时配置参数下表完整继承自 docs/configuration/index.md 的 Router 运行时配置小节并补充了说明Property说明默认值druid.router.defaultBrokerServiceName服务发现失败时连接到的默认 Brokerdruid/brokerdruid.router.tierToBrokerMap将某一 tier 的数据查询路由到对应 Broker。值为「tier 到 Broker 服务名」的有序 JSON mapBroker 的优先级由该顺序决定{_default_tier: defaultBrokerServiceName}druid.router.defaultRule所有 datasource 的默认规则_defaultdruid.router.pollPeriod轮询新规则的频率PT1Mdruid.router.sql.enable是否启用基于策略的 SQL 查询路由。为true时使用druid.router.strategies中定义的策略决定某条 SQL 查询对应的 Broker 服务为false时使用defaultBrokerServiceNamefalsedruid.router.strategies路由策略列表详见本文第三节「Router strategies」[{type:timeBoundary},{type:priority}]druid.router.avatica.balancer.type用于在 Broker 间均衡 Avatica 查询的连接均衡器实现详见本文第五节rendezvousHashdruid.router.managementProxy.enabled是否启用 Router 的管理代理功能详见本文第四节falsedruid.router.http.numConnectionsRouter 连接 Broker 进程的连接池大小。如果并发查询数超过该值且都需要访问同一进程多余的查询将排队20druid.router.http.eagerInitialization是否在初始化时立即建立从 Router 到 Broker 的 HTTP 连接。为true时初始化即创建numConnections个连接truedruid.router.http.readTimeout从 Broker 进程读取数据的超时时间PT15Mdruid.router.http.numMaxThreads处理 HTTP 请求与响应的最大工作线程数max(10, ((number of cores * 17) / 16 2) 30)druid.router.http.numRequestsQueued可排队到同一目标的最大请求数1024druid.router.http.requestBuffersize接收请求的内容缓冲区大小。这些缓冲区仅用于「请求体无法放入 header buffer」的活动连接8 * 1024其中tierToBrokerMap的顺序即优先级这一点非常关键排在 map 前面的 tier 对应高优先级 Broker后面的是低优先级 Broker这也是后续各策略中「最高/最低优先级 Broker」判定的依据。三、查询路由策略Router strategiesRouter 维护一个可配置的策略列表druid.router.strategies来决定把查询路由到哪一组 Broker。策略的顺序至关重要——因为一旦某个策略的条件被满足Broker 就会立刻被选定不再继续执行后面的策略。timeBoundary 策略{ type:timeBoundary }包含该策略意味着所有timeBoundary查询始终被路由到优先级最高的 Broker。timeBoundary 查询用于获取 datasource 的最早/最晚时间边界是一个轻量且高频的元数据查询固定走最高优先级 Broker 可以保证其始终获得最好的服务。priority 策略{ type:priority, minPriority:0, maxPriority:1 }优先级小于minPriority的查询 → 路由到最低优先级Broker优先级大于maxPriority的查询 → 路由到最高优先级BrokerminPriority默认0maxPriority默认1。按默认值理解Druid 查询的默认优先级是0因此当发送一条优先级为0的查询时它既不大于maxPriority也不小于minPriority会跳过 priority 选择逻辑继续交由后续策略或规则处理。manual 策略{ type: manual, defaultManualBrokerService: druid:broker-hot }manual 策略从查询上下文中读取参数brokerService并把查询路由到该参数指定的 Broker 服务。规则如下若查询上下文中没有有效的brokerService则回退使用字段defaultManualBrokerService前提是该值有效且非空「有效」的定义是该值必须出现在druid.router.tierToBrokerMap中该策略同时支持原生native查询和 SQL 查询。上面示例的效果当查询上下文中找不到有效的brokerService时查询被路由到 Brokerdruid:broker-hot。从源码看brokerService正是 Druid 查询上下文中的一个标准上下文键——QueryContexts.java 中定义了public static final String BROKER_SERVICE_NAME brokerService因此客户端可以在查询上下文中显式携带该参数由 Router 的 manual 策略读取并执行定向路由。JavaScript 策略允许通过 JavaScript 函数定义任意路由规则。函数接收「配置」和「待执行的查询」两个参数返回查询应被路由到的 tier返回null表示使用默认 tier。下面的示例函数会把「包含 3 个及以上聚合器aggregator的查询」发送到最低优先级 Broker{ type : javascript, function : function (config, query) { if (query.getAggregatorSpecs query.getAggregatorSpecs().size() 3) { var size config.getTierToBrokerMap().values().size(); if (size 0) { return config.getTierToBrokerMap().values().toArray()[size-1] } else { return config.getDefaultBrokerServiceName() } } else { return null } } }函数体内config.getTierToBrokerMap()返回的就是配置项druid.router.tierToBrokerMap对应的有序 mapconfig.getDefaultBrokerServiceName()对应druid.router.defaultBrokerServiceName。注意基于 JavaScript 的功能默认是关闭的。使用前请阅读 Druid 的 JavaScript 编程指南其中包含启用 JavaScript 功能的详细步骤与使用规范。SQL 查询的策略路由要启用「使用策略路由 SQL 查询」需要设置druid.router.sql.enabletrue。此时某条 SQL 查询对应的 Broker 服务仅通过配置的 Router 策略来解析如果所有策略都无法解析出 BrokerRouter 回退使用defaultBrokerServiceName这与原生native查询的行为略有不同原生查询的解析顺序是「先策略 → 再加载规则load rules→ 最后才是defaultBrokerServiceName」当druid.router.sql.enablefalse默认值时Router 直接使用defaultBrokerServiceName。同时要注意该开关的影响范围druid.router.sql.enable不影响 Avatica JDBC 请求也不影响原生查询Druid 始终按「策略 加载规则」的既有机制路由原生查询Druid 始终按connection ID路由 Avatica JDBC 请求详见下节。四、Router 作为管理代理management proxyRouter 可以配置为把请求转发给当前活跃的 Coordinator 或 Overlord 服务。这在搭建高可用集群时非常有用——当「非活跃 Coordinator/Overlord 通过 HTTP 重定向跳转到活跃实例」的机制无法正常工作时例如服务器位于负载均衡器之后或重定向中使用的 hostname 只能在集群内部解析管理代理就派上了用场。启用管理代理在 Router 的runtime.properties中设置druid.router.managementProxy.enabledtrue从源码看该开关对应 ManagementProxyConfig.java 中的enabled字段其默认值为false必须显式开启。管理代理的路由方式管理代理支持隐式路由和显式路由两种方式隐式路由Implicit routes目标服务可以根据原始请求路径、按照 Druid API 路径约定直接确定。Coordinator 的约定前缀是/druid/coordinator/*Overlord 的约定前缀是/druid/indexer/*。隐式路由非常方便——除了把请求发给 Router 而不是 Coordinator/Overlord 之外API 请求本身无需任何修改。绝大多数 Druid API 请求都可以走隐式路由。显式路由Explicit routes发给 Router 的请求带有一个指示目标服务的路径前缀Coordinator 的前缀是/proxy/coordinatorOverlord 的前缀是/proxy/overlord。这用于目标不明确的 API 调用——例如/statusAPI 在 Druid 的所有服务上都存在必须使用显式路由来指明代理目标。下表完整总结了两种路由方式原文档路由表Request RouteDestinationRewritten RouteExample/druid/coordinator/*Coordinator/druid/coordinator/*router:8888/druid/coordinator/v1/datasources→coordinator:8081/druid/coordinator/v1/datasources/druid/indexer/*Overlord/druid/indexer/*router:8888/druid/indexer/v1/task→overlord:8090/druid/indexer/v1/task/proxy/coordinator/*Coordinator/*router:8888/proxy/coordinator/status→coordinator:8081/status/proxy/overlord/*Overlord/*router:8888/proxy/overlord/druid/indexer/v1/isLeader→overlord:8090/druid/indexer/v1/isLeader观察 Rewritten Route 一列可以发现两者的本质区别隐式路由保持路径不变直接透传显式路由则会把/proxy/coordinator或/proxy/overlord前缀剥离掉再把剩余路径转发给目标服务。五、Avatica 查询连接均衡Avatica query balancingDruid 的 Broker 之间不共享连接状态因此同一 connection ID 的所有 Avatica JDBC 请求必须被路由到同一个 Broker。为此 Druid 提供了两个内置均衡器分别基于 connection ID 的 rendezvous hashing法团哈希与 consistent hashing一致性哈希来把请求分配给 Broker。多 Router 部署时的硬性要求当集群中有多个 Router 时所有 Router 必须使用完全相同的均衡器配置以保证它们做出相同的路由决策否则同一个连接可能被不同的 Router 分到不同 Broker。Rendezvous hash 均衡器该均衡器基于 Rendezvous Hashing法团哈希对 Avatica 请求的 connection ID 进行哈希以确定目标 Broker。启用方式druid.router.avatica.balancer.typerendezvousHash如果未设置druid.router.avatica.balancer相关属性Router 默认使用 rendezvous hash 均衡器——这一点与 AvaticaConnectionBalancer.java 中的defaultImpl RendezvousHashAvaticaConnectionBalancer.class相互印证该接口通过 Jackson 注解注册了rendezvousHash与consistentHash两种实现。从实现看RendezvousHasher.java 使用 Guava 的Hashing.murmur3_128()哈希函数对每个候选 Broker 节点 ID 与请求 key 拼接后计算组合哈希选取哈希值最大的节点作为目标。其核心优势是不需要锁因为算法本身是无状态的、纯函数式的。Consistent hash 均衡器该均衡器基于 Consistent Hashing一致性哈希对 Avatica 请求的 connection ID 进行哈希以确定目标 Broker。启用方式druid.router.avatica.balancer.typeconsistentHash这是一个非默认实现仅用于实验目的。根据官方说明的权衡缺点初始化时以及 Broker 集合发生变化时构建哈希环的设置时间更长优点在 5 个 Broker 的测试场景下Broker 分配速度比 rendezvous hasher 更快两个实现的基准测试分别位于ConsistentHasherBenchmark和RendezvousHasherBenchmark仓库中的对应文件为 ConsistentHasherBenchmark.java 与 RendezvousHasherBenchmark.javaconsistent hasher需要加锁而 rendezvous hasher 不需要。从实现看ConsistentHasher.java 使用REPLICATION_FACTOR 128通过测试确定为 5~10 个 Broker 时提供合理均衡的副本因子为每个 Broker 节点生成 128 个虚拟节点key-0到key-127哈希后放入Long2ObjectRBTreeMap构成哈希环查询时对目标哈希做tailMap查找找到顺时针第一个节点环尾则回绕到第一个节点。该类注释明确标注Not thread-safe与官方文档「consistent hasher 需要加锁」的说法一致。六、生产环境配置示例下面是一个完整的生产配置示例集群中有两个 tier——hot与_default_tier。hottier 的查询路由到broker-hot这组 Broker_default_tier的查询路由到broker-cold这组 Broker。一旦发生任何异常或网络问题查询回退到broker-cold这组 Broker因为defaultBrokerServiceName指向它。示例假设运行在 c3.2xlarge EC2 实例上且已存在一份公共的common.runtime.properties。JVM 设置-server -Xmx13g -Xms13g -XX:NewSize256m -XX:MaxNewSize256m -XX:UseConcMarkSweepGC -XX:PrintGCDetails -XX:PrintGCTimeStamps -XX:UseLargePages -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/mnt/galaxy/deploy/current/ -Duser.timezoneUTC -Dfile.encodingUTF-8 -Djava.io.tmpdir/mnt/tmp -Dcom.sun.management.jmxremote.port17071 -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse要点解读堆大小-Xmx13g/-Xms13g固定为 13 GB避免 JVM 动态扩容带来的停顿-XX:UseConcMarkSweepGC使用并发标记清除 GC配合大页UseLargePages降低 GC 停顿HeapDumpOnOutOfMemoryError在 OOM 时生成堆转储便于事后排查时区统一为 UTC、编码统一为 UTF-8避免跨时区/跨编码的脏数据JMX 远程端口17071用于监控采集。Runtime.propertiesdruid.host#{IP_ADDR}:8080 druid.plaintextPort8080 druid.servicedruid/router druid.router.defaultBrokerServiceNamedruid:broker-cold druid.router.coordinatorServiceNamedruid:coordinator druid.router.tierToBrokerMap{hot:druid:broker-hot,_default_tier:druid:broker-cold} druid.router.http.numConnections50 druid.router.http.readTimeoutPT5M # Number of threads used by the Router proxy http client druid.router.http.numMaxThreads100 druid.server.http.numThreads100要点解读druid.router.defaultBrokerServiceNamedruid:broker-cold所有无法匹配规则/策略的查询含异常回退都走broker-colddruid.router.tierToBrokerMap是有序 JSON maphot排在前面对应高优先级 Broker 组_default_tier排在后面对应低优先级 Broker 组——这与第二节中「map 顺序即优先级」的说明一致druid.router.coordinatorServiceName供管理代理定位 Coordinator 服务HTTP 代理连接池 50 个连接、读取超时 5 分钟、代理客户端最大线程数 100druid.server.http.numThreads100控制 Router 自身对外提供服务的线程数若需配合统一 Web 控制台使用还应在该文件中追加druid.router.managementProxy.enabledtrue参见 examples/conf/druid/cluster/query/router/runtime.properties 的官方示例做法。小结Router 的价值集中在三处按保留规则/策略做 tier 级查询隔离TB 级集群的必备组件、作为 Coordinator/Overlord 的管理代理突破负载均衡与内网 hostname 限制下的 HA 部署、对 Avatica JDBC 请求做连接级粘性均衡补偿 Broker 间不共享连接状态的限制。配置时把握三条主线即可druid.router.tierToBrokerMap的有序性决定优先级、druid.router.strategies的顺序决定策略命中先后、druid.router.avatica.balancer.type决定 JDBC 连接的粘性分配方式多 Router 部署时务必保持均衡器配置一致。【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考