Skip to content
All notes

Dubbo Admin 泛化调用链路

记录 Dubbo Admin 从服务元数据和目标实例发起泛化调用的后端链路。

Dubbo Admin 泛化调用链路

[!abstract] 这次 PR 的核心不是单独新增 4 个接口,而是补齐 Dubbo Admin 的服务调试后端链路。它从 ServiceProviderMetadata 出发,把“方法语义”和“实例调用目标”汇合到 /service/generic/invoke。

项目背景

服务身份是 serviceName + version + group。方法和类型信息来自 ServiceProviderMetadata,用户选择 Instance,实际调用目标由对应的 RPCInstance 提供。实体关系见 Dubbo Admin 应用与实例模型。

2. PR 总览

这次 PR 在后端侧补齐了一条服务调试链路:先解析服务的方法和类型信息,再定位可选实例,最后把方法和实例汇合成一次真实的 Dubbo 泛化调用。

服务上下文
    |
    v
ServiceProviderMetadata
    |
    +----> 方法信息 -------------------+
    |                                 |
    +----> providerAppName -> Instance -> RPCInstance
                                      |
                                      v
                            /service/generic/invoke
                                      |
                                      v
                            rawResult + elapsedMs

3. 接口设计

GET /service/methods

输入:mesh + serviceName + version + group

处理:查询 ServiceProviderMetadata,提取 methods,并按 methodName + signature 去重。

输出:方法列表,核心是 methodName、parameterTypes 和 signature。

GET /service/method/detail

输入:服务上下文,再加上 methodName + signature。

处理:精确定位目标方法,提取参数、返回值以及关联类型定义。

输出:方法详情与类型图。

GET /service/provider-instances

输入:mesh + serviceName + version + group

处理:先从 ServiceProviderMetadata 提取 providerAppName,再按 app 查询 Instance。

输出:控制台实例列表。这里返回的是 Instance,不是直接暴露底层 RPC endpoint。

POST /service/generic/invoke

输入:方法、实例、参数、超时、attachments。

处理:方法解析、参数解码、实例映射、泛化调用。

输出:rawResult + elapsedMs。

4. 泛化调用链路设计

这是这次 PR 最核心的接口。它真正把“方法语义”和“实例目标”汇合成一次调用。

请求体
(mesh, serviceName, version, group,
 methodName, signature, instanceName,
 args, timeoutMs, attachments)
            |
            v
1. 请求校验
            |
            v
2. 解析服务方法
   ServiceProviderMetadata
            |
            v
3. 解码调用参数
   args -> parameterTypes
            |
            v
4. 解析目标实例
   Instance -> RPCInstance
            |
            v
5. 组合调用 target
   endpoint / protocol / serialization
            |
            v
6. 发起 Dubbo Generic Invoke
            |
            v
7. 返回
   rawResult + elapsedMs

请求输入

这个接口的输入可以分成四组:

  • 服务身份:mesh + serviceName + version + group
  • 方法身份:methodName + signature
  • 调用目标:instanceName
  • 调用参数:args + timeoutMs + attachments

也就是说,这个接口并不是“给一个服务名直接调”,而是要求调用语义和调用目标都明确。

方法语义解析

后端首先会按 mesh + serviceKey 查询 ServiceProviderMetadata,再根据 methodName + signature 精确定位目标方法。

这一步的作用是确认两件事:

  • 当前服务下,这个方法是否真实存在
  • 这个方法的参数类型到底是什么

参数解码

在定位到目标方法之后,后端会先校验参数个数是否和 parameterTypes 对齐,然后再按参数类型去解码前端传来的 JSON 参数。

这里的重点不是“能接收 JSON”,而是“把 JSON 转换成 Dubbo 泛化调用能接受的参数对象”。例如基础数值类型、字符类型、数组类型,都会按目标参数类型做显式转换,而不是原样透传。

调用目标解析

调用目标的解析分两步:

  1. 先按 mesh + instanceName 查询 Instance
  2. 再从 Instance 推导和查询对应的 RPCInstance

这一步很关键,因为控制台里给用户选的是 Instance,但真正可执行 RPC 调用的,是带有 endpoint、protocol、serialization 信息的 RPCInstance。

所以这条链路本质上是在做一层映射:

控制台实例 -> 注册中心实例 -> 真实调用目标

执行与返回

在拿到方法和目标实例之后,后端会进一步从 RPCInstance 中提取 endpoint、protocol、serialization,组合出候选 target,然后发起 Dubbo Generic Invoke。

执行前会设置 timeout,并把 attachments 放进调用上下文。执行后则会记录耗时,并把返回结果整理成前端更容易消费的 JSON 友好结构。

所以这个接口最终交付给前端的,并不是底层原始对象,而是:

  • rawResult
  • elapsedMs

这里可以用两句话概括整个 invoke 接口:

  • ServiceProviderMetadata 决定“调什么”
  • Instance -> RPCInstance 决定“对谁调”

5. 后续 TODO

删除没用的旧接口

现在服务调试相关能力已经有了一条更完整的主链路,后面可以继续清理历史残留接口,收敛 API 面,避免同类能力重复或分散。

给 invoke 设计 dubbo-go client 池

当前实现里每次调用都会新建 dubbo-go instance/client。后续可以设计一个 client 池,把创建和复用抽出来,减少重复初始化开销。