概述
在 silky 框架中,执行器(Executor) 是服务条目(ServiceEntry)被调用时的核心调度组件。它负责判断当前请求应由本地实例处理,还是通过 RPC 远程调用转发到其他服务实例。
执行器体系由以下核心组件构成:
| 组件 | 接口 | 默认实现 | 职责 |
|---|---|---|---|
| 统一执行入口 | IExecutor | DefaultExecutor | 根据 ServiceEntry/ServiceEntryDescriptor 分发执行 |
| 本地执行器 | ILocalExecutor | DefaultLocalExecutor | 解析实现类实例,构建本地调用器并执行 |
| 远程执行器 | IRemoteExecutor | DefaultRemoteExecutor | 构建 RPC 调用消息,选择策略并转发到远程 |
IExecutor —— 统一执行入口
IExecutor 是最顶层的调度接口,它将执行请求分发到合适的执行路径:
public class DefaultExecutor : IExecutor
{
// 已有 ServiceEntry(含 IsLocal 标记)时:
// 直接调用 serviceEntry.Executor 委托(本地执行)
public async Task<object> Execute(ServiceEntry serviceEntry, object[] parameters, string serviceKey = null)
{
return await serviceEntry.Executor(serviceKey, parameters).ConfigureAwait(false);
}
// 只有 ServiceEntryDescriptor(无实现类,一定是远程)时:
// 转发到 IRemoteExecutor
public async Task<object> Execute(ServiceEntryDescriptor serviceEntryDescriptor,
IDictionary<ParameterFrom, object> parameters, string serviceKey)
{
var remoteExecutor = EngineContext.Current.Resolve<IRemoteExecutor>();
return await remoteExecutor.Execute(serviceEntryDescriptor, parameters, serviceKey).ConfigureAwait(false);
}
}
关键设计点:
- 当调用方持有完整的
ServiceEntry对象时,框架已在构建ServiceEntry.Executor委托时做好了本地/远程分支。ServiceEntry.Executor内部判断IsLocal,若为本地则走本地执行,否则走远程执行。 - 当调用方只持有
ServiceEntryDescriptor(如使用IInvokeTemplate发起调用时),因为没有本地实现,一定走远程执行。
ServiceEntry.Executor —— 本地/远程决策委托
ServiceEntry 在构造时会创建一个 Executor 委托,该委托封装了本地/远程的选择逻辑:
// ServiceEntry 构造器内部
Executor = CreateExecutor();
private Func<string, object[], Task<object>> CreateExecutor()
{
return IsLocal
? CreateLocalExecutor() // 本地:走 ILocalExecutor
: CreateRemoteExecutor(); // 远程:走 IRemoteExecutor
}
IsLocal 的判断规则是:在应用启动扫描应用服务时,如果当前程序集中存在该接口的实现类(非抽象),则 IsLocal = true;否则该服务只是其他微服务的代理,IsLocal = false。
本地执行路径
当 IsLocal = true 时,ServiceEntry.Executor 最终调用 ILocalExecutor.Execute():
ServiceEntry.Executor (IsLocal=true)
│
▼
DefaultLocalExecutor.Execute()
│ 解析实现类实例(按 serviceKey 区分多实现)
│
▼
IServerLocalInvokerFactory.CreateInvoker()
│ 构建 LocalInvoker(含服务端过滤器链)
│
▼
LocalInvoker.InvokeAsync()
│ 运行服务端过滤器管道 → 调用业务方法
│
▼
返回结果
详见 本地执行器与服务端过滤器。
远程执行路径
当 IsLocal = false 时,ServiceEntry.Executor 最终调用 IRemoteExecutor.Execute():
ServiceEntry.Executor (IsLocal=false)
│
▼
DefaultRemoteExecutor.Execute()
│ 构建 RemoteInvokeMessage
│ 根据分流策略确定 hashKey
│
▼
IInvokePolicyBuilder.Build()
│ 组合:超时策略 + 熔断策略 + Fallback 策略(Polly WrapAsync)
│
▼
policy.ExecuteAsync()
│ 在策略保护下执行 IRemoteCaller.InvokeAsync()
│
▼
DefaultRemoteCaller.InvokeAsync()
│ 查找目标端点 → 选择负载均衡策略 → 获取 TransportClient → 执行 RPC
│
▼
返回结果
详见 远程执行器与 RPC 调用。
HTTP 请求的完整分发路径
当一个外部 HTTP 请求进入网关或含有 HTTP 模块的微服务时,从路由匹配到执行的完整路径如下:
外部 HTTP 请求
│
▼
ASP.NET Core 路由中间件(UseRouting)
│ 按 HTTP 方法 + Path 匹配服务条目
│
▼
SilkyRpcEndpointHandler(Endpoint 处理器)
│ 从 HttpContext 中解析 ServiceEntry
│ 解析请求参数(Path Param / Query / Body / Form)
│
▼
serviceEntry.Executor(serviceKey, parameters)
│ IsLocal → 本地执行
│ !IsLocal → 远程 RPC 调用
│
▼
WrapperResponseMiddleware
│ 将返回值包装为统一结构 { data, statusCode }
│
▼
HTTP Response
RPC 调用收到请求后的分发路径
当一个 RPC 请求从网络层到达服务端时:
DotNetty Channel 接收到 TCP 数据包
│
▼
Codec 解码(TransportMessage 反序列化)
│
▼
DefaultServerMessageReceivedHandler.Handle()
│ 根据 ServiceEntryId 查找本地 ServiceEntry
│ 解析 RPC 参数(ParameterResolver)
│
▼
serviceEntry.Executor(serviceKey, parameters)
│ IsLocal=true(RPC 端口只接受本地服务的请求)
│
▼
LocalInvoker(服务端过滤器管道 → 业务方法)
│
▼
RemoteResultMessage → 编码 → 写回 Channel
详见 RPC 服务端消息处理。
