
智能路由的设计目标是让用户对底层集群无感知。用户只提交查询意图和 SLA平台根据 SQL 指纹、历史执行画像、当前租户权限、数据源能力、集群健康状态和实时资源情况自动选择最合适的执行环境。路由层负责生成可解释的RouteDecisionLinkis 负责将决策落到 EngineConn 和具体计算引擎上。在执行失败时我会把业务任务和具体执行尝试分开通过状态机驱动重试和重新路由而不是简单地重复提交。这样既能保证任务语义不变又能根据最新资源状态选择新的集群或引擎。成功率验证最终通过 SLA 命中率、路由后成功率、重试恢复率、排队时间和资源利用率验证这套智能路由是否真正有效。总体来说路由层解决的是多引擎、多集群环境下的执行决策问题。它基于标准化查询意图、SQL 指纹、历史执行画像和实时资源状态先做权限、兼容性和配额过滤再根据 SLA、耗时和资源成本选择最终执行环境生成可解释的RouteDecision。这个决策通过标准化请求、标签和运行配置转发给 Linkis由 Linkis 完成 EngineConn 管理和实际执行。如果路由判断错误则在ExecutionAttempt层进行切换和恢复执行结果再反馈给画像系统持续优化后续路由。1、路由层要解决的问题和设计路由层要解决的核心问题是在多个计算引擎、多个集群和多个资源队列并存的情况下用户不需要指定 Spark、Trino 还是 JDBC平台能够根据查询特征和运行状态自动选择合适的执行环境并对路由结果负责。存在的意义业务和引擎耦合如果没有路由层自助查询平台就需要直接绑定具体引擎导致业务语义和基础设施耦合。基于当前情况动态选择资源平台统一考虑查询规模(元数据提供)、SLA成功率、租户配额你有没有权限、权限的资源够不够和集群负载。因此我会把路由层设计成一个独立的执行决策模块。它不负责真正提交任务只负责将标准化的查询请求转换为可解释的RouteDecision。路由层主要包含四个设计点。第一统一路由统一提交协议、自助查询平台先将用户的指标、维度、数据集、筛选条件和 SLA 转换成统一的SubmitRequest其中包含1、查询内容用户到底想执行什么。 QueryIntent SQL 或 LogicalQueryPlan 2、数据源信息查询涉及哪些数据哪些引擎具备执行能力。 DataSource QueryType 3、租户信息谁在执行以及他可以使用什么资源和数据。 Tenant User 4、历史的SLA能够给资源推荐 SLA ResourceHint路由层不直接依赖页面参数也不通过 SQL 文本简单猜测引擎而是基于结构化查询信息做决策。第二建立 SQL 指纹和执行画像路由层对 SQL 做规范化和参数化生成SQLFingerprint并记录该查询过去的执行画像过去在哪里执行engine 和 cluster 描述过去在哪里执行查询规模scanBytes 和 shuffleBytes 描述查询规模查询排队和执行时间queueTime 和 executeTime 描述性能执行成功率successRate 和 slaHitRate 描述稳定性使用的内存peakMemory 和 runtimeConfig 用于资源调优调度与重试failureReason 用于决定失败后是重试、切换集群还是直接返回错误。路由层基于这些历史画像再结合当前租户权限和集群状态生成最终的执行决策。这样路由决策就不只是静态规则而是可以利用历史执行结果判断这个 SQL 适合什么引擎 通常需要多少资源 在哪个集群执行更稳定 是否能够满足 SLA第三候选过滤和路由决策生成候选集群之后进行约束过滤硬约束权限、对应队列是否有权限、集群健康、配额是否够软约束历史成功率、预计执行时间、排队时间、集群负载等进行推荐集群执行。路由层先生成候选执行环境Trino / interactive-a Trino / interactive-b Spark / offline-a然后分两步决策。第一步是硬约束过滤权限是否满足 数据源是否兼容 SQL 方言是否支持 租户是否有队列权限 集群是否健康 租户配额是否足够第二步是软指标评分历史成功率 SLA 命中率 预计执行时间 当前排队时间 资源成本 集群负载最终形成engine: Trino cluster: interactive-a queue: tenant_a resource: small reason: - scan_size_below_threshold - historical_sla_hit_rate_high - cluster_healthy这里需要强调路由结果必须可解释。平台不仅要告诉执行哪个引擎还要保留为什么选择它便于故障排查、审计和后续优化。第四执行失败后的恢复路由是执行前的预估可能出现统计信息不准确、实际数据量变大或集群状态变化。因此要把业务任务和具体执行尝试分开Task 用户原始查询意图 ExecutionAttempt 一次具体的执行尝试如果 Trino 执行超时可以保留原始 Task并创建新的 Attempt 切换到 SparkAttempt 1Trino / interactive-a执行超时 Attempt 2Spark / offline-a重新执行不同失败采用不同策略SQL 语义错误直接失败不重试 EngineConn 创建失败Attempt 级重试 外部提交超时先查询 applicationId避免重复提交 资源不足调整资源或切换集群 集群不可用重新选择候选环境所以路由层的完整职责是识别查询特征 - 生成候选环境 - 做权限和资源过滤 - 选择引擎、集群、队列和资源 - 输出可解释的 RouteDecision - 在 Attempt 层支持失败恢复2、实际例子订单查询如何与 Linkis 结合假设用户在自助查询页面中选择指标订单金额 维度销售渠道 时间范围近 7 天 SLA10 秒自助查询平台先完成业务语义解析和权限校验生成标准请求{dataset:orders,queryType:aggregation,sql:SELECT channel, SUM(payment_amount) ...,tenant:tenant_a,user:user_1001,slaSeconds:10}路由层根据 SQL 指纹查询历史画像发现平均扫描量5 GB Trino 平均耗时12 秒 Spark 平均耗时90 秒 Trino SLA 命中率98%然后获取当前候选环境Trino / interactive-a健康排队 2 秒 Trino / interactive-b健康排队 40 秒 Spark / offline-a健康但属于离线队列经过权限、数据源兼容性、租户配额和集群健康度过滤后路由层选择engine: Trino cluster: interactive-a queue: tenant_a resource: small并生成RouteDecision路由层不会直接调用 Trino也不会自己创建连接而是把这个决策转换成 Linkis 的标准请求和标签engineType trino cluster interactive-a queue tenant_a runtimeConfig small然后提交给 LinkisRouteDecision - SubmitRequest / Labels - Linkis Orchestrator - EngineConnManager - Trino EngineConn - Trino ClusterLinkis 负责完成任务编排 EngineConn 复用或创建 资源和租户校验 查询提交 状态跟踪 日志获取 结果获取自助查询平台只需要依赖统一的任务和结果接口不需要感知底层是Trino Session Spark Application JDBC Statement如果执行过程中发现实际扫描量远大于预估Trino 执行超过 SLA路由层可以终止当前ExecutionAttempt 1然后重新生成一个执行决策engine: Spark cluster: offline-a queue: tenant_a resource: 4 cores / 8 GB再通过 Linkis 创建ExecutionAttempt 2原始任务仍然是同一个Task查询近 7 天订单金额执行结束后Linkis 返回任务状态、执行指标和结果引用路由层再将以下信息回写至 SQL 指纹画像用于持续优化实际引擎 实际集群 扫描量 排队时间 执行耗时 资源消耗 SLA 是否命中 失败原因最终形成自助查询 用户想查什么 路由层 选择什么引擎、集群和资源 Linkis 如何管理和提交任务 Trino / Spark 真正执行查询其他运行时间估算预计排队时间不是一个精确值而是基于实时队列状态和历史资源释放速度计算出的预测值。对于 Trino我会从 Resource Group 获取当前运行查询数、排队查询数、并发上限和查询优先级再结合最近一段时间的查询完成速率估算。例如当前查询排在第 5 位集群每秒平均完成 2.5 个查询那么预计排队约 2 秒。对于 Spark我会从 YARN 获取目标队列的可用 CPU、内存、Pending Application、前方任务资源需求和当前任务最低启动资源再结合历史资源释放速度计算。例如前方任务加当前任务共需要释放 32 个 vCore 和 128 GB 内存队列每秒释放 0.8 个 vCore 和 3.2 GB 内存那么预计资源等待约 40 秒再加上调度和 ApplicationMaster 启动开销预计排队约 45 秒。路由层最终比较的不是单独的排队时间而是预计端到端完成时间也就是排队时间、EngineConn 获取时间、执行时间和结果交付时间之和。任务真正启动后再用实际排队时间修正预测模型形成持续反馈闭环。SLA 计算Trino SLA 命中率 98%的意思是在统计范围内路由到 Trino 的同类查询中有 98% 在约定时间内完成了用户可用的结果交付。例如某类 SQL 的 SLA 是 10 秒最近 7 天共执行了 1000 次980 次在 10 秒内完成 20 次超过 10 秒或执行失败 SLA 命中率 980 / 1000 98%这里的“完成时间”最好按用户端到端体验计算SLA 耗时 排队时间 EngineConn 获取时间 执行时间 结果交付时间不能只计算 Trino 的 SQL 执行时间。比如 SQL 在 Trino 中执行了 6 秒但排队 5 秒、结果封装 2 秒总耗时 13 秒对于 10 秒 SLA 来说仍然没有命中。指标也不能只说“Trino 整体命中率 98%”必须带上统计维度SQL 指纹哪一类查询 集群哪个 Trino 集群 SLA 档位10 秒还是 30 秒 租户或资源组使用什么配额 统计窗口最近 7 天还是最近 30 天 样本量总共执行了多少次完整表达应该是最近 7 天该 SQL 指纹在trino-interactive-a集群执行了 1000 次其中980次在10秒内完成结果交付因此该候选环境的10秒 SLA 命中率是98%。路由时98%表示历史上 Trino 对这类查询具有较高的时效稳定性但它不能单独决定路由。还要结合样本量、当前排队时间、集群资源、查询扫描量和租户权限。例如Trino 历史 SLA 命中率98% 当前预计排队时间2 秒 预计扫描量5 GB 租户有权限资源充足可以优先路由到 Trino。但如果当前 Trino 集群已经严重拥堵即使历史命中率是 98%本次也可能选择备用 Trino 集群或 Spark。Trino SLA 命中率 98%表示在指定统计周期内同类 SQL 路由到指定 Trino 集群后有 98% 能在约定时间内完成端到端结果交付。这个指标反映的是历史时效稳定性路由时还需要结合当前集群负载、预计扫描量、租户权限和样本量一起判断。