# Silky服务主机的概念
在Silky微服务框架中,主机用于托管微服务应用,在微服务主机启动时,最重要的任务就是构建服务提供者,并将服务提供者主机的信息以元数据的形式注册到 服务注册,集群中的每个微服务应用可以通过 心跳 或是 订阅 的方式从服务注册中心获取整个微服务集群最新的元数据信息。
在Silky框架中,我们通过 Server (opens new window) 来定义Silky主机(也就是服务提供者)。一个微服务提供者的主要属性如下表所示:
属性名 | 名称 | 备注 |
---|---|---|
HostName | 微服务主机名称 | 等于应用程序的启动程序集的名称 |
Endpoints | 微服务提供者所有的终结点 | 在构建支持不同协议的服务时,动态的添加该服务主机的终结点 |
Services | 微服务提供者所有的服务描述符 |
在服务注册过程中,并不能直接注册Server
的信息,所以我们定义了 服务主机描述符 ,通过服务主机描述符
ServerDescriptor (opens new window) 来描述Silky主机信息,并通过其将主机的信息注册到服务注册中心,服务主机Server
与服务主机描述符ServerDescriptor
可以相互转化。
# 创建Silky服务主机
Silky服务主机的解析由默认主机服务提供者DefaultServerProvider
负责创建和维护;
public class DefaultServerProvider : IServerProvider
{
public ILogger<DefaultServerProvider> Logger { get; set; }
private readonly IServer _server;
private readonly IServiceManager _serviceManager;
private readonly ISerializer _serializer;
public DefaultServerProvider(IServiceManager serviceManager,
ISerializer serializer)
{
_serviceManager = serviceManager;
_serializer = serializer;
Logger = EngineContext.Current.Resolve<ILogger<DefaultServerProvider>>();
_server = new Server(EngineContext.Current.HostName);
}
public void AddRpcServices()
{
var rpcEndpoint = EndpointHelper.GetLocalRpcEndpoint();
_server.Endpoints.Add(rpcEndpoint);
var rpcServices = _serviceManager.GetLocalService(ServiceProtocol.Rpc);
foreach (var rpcService in rpcServices)
{
_server.Services.Add(rpcService.ServiceDescriptor);
}
}
public void AddHttpServices()
{
var webEndpoint = RpcEndpointHelper.GetLocalWebEndpoint();
if (webEndpoint == null)
{
throw new SilkyException("Failed to obtain http service rpcEndpoint");
}
_server.Endpoints.Add(webEndpoint);
}
public void AddWsServices()
{
var wsEndpoint = RpcEndpointHelper.GetWsEndpoint();
_server.Endpoints.Add(wsEndpoint);
var wsServices = _serviceManager.GetLocalService(ServiceProtocol.Ws);
foreach (var wsService in wsServices)
{
_server.Services.Add(wsService.ServiceDescriptor);
}
}
public IServer GetServer()
{
Logger.LogDebug("server endpoints:" + _serializer.Serialize(_server.Endpoints.Select(p => p.ToString())));
if (_server.HasHttpProtocolServiceEntry() && !_server.Endpoints.Any(p =>
p.ServiceProtocol == ServiceProtocol.Http || p.ServiceProtocol == ServiceProtocol.Https))
{
throw new SilkyException(
"A server that supports file upload and download or ActionResult must be built through the http protocol host",
StatusCode.ServerError);
}
return _server;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
从上面的代码我们可以看出:
由Server主机提供者的构造器创建
Server
主机;Server主机提供者的构造器中注入服务管理器
IServiceManager
,由此,我们也可以得知:在应用启动时获取主机提供者的时候,实现了服务和服务条目的解析;主机服务提供者
DefaultServerProvider
提供三个核心的方法AddRpcServices()
、AddHttpServices()
、AddWsServices()
; 在应用启动时,在指定的时刻查找指定协议的服务和相应的服务终结点;
3.1 由web主机 (opens new window)创建的Silky微服务应用,映射Silky路由的时候,调用AddHttpServices()
方法,在应用启动成功时,添加该微服务应用的Http终结点;
public static class SilkyEndpointRouteBuilderExtensions
{
public static ServiceEntryEndpointConventionBuilder MapSilkyRpcServices(this IEndpointRouteBuilder endpoints)
{
if (endpoints == null)
{
throw new ArgumentNullException(nameof(endpoints));
}
var hostApplicationLifetime = endpoints.ServiceProvider.GetRequiredService<IHostApplicationLifetime>();
// 在应用启动后注册RegisterSilkyWebServer()方法
hostApplicationLifetime.ApplicationStarted.Register(async () =>
{
// 注册支持Web服务的Silky微服务
await RegisterSilkyWebServer(endpoints.ServiceProvider);
});
return GetOrCreateServiceEntryDataSource(endpoints).DefaultBuilder;
}
private static async Task RegisterSilkyWebServer(IServiceProvider serviceProvider)
{
// 获取主机服务提供者实例
var serverRegisterProvider =
serviceProvider.GetRequiredService<IServerProvider>();
serverRegisterProvider.AddHttpServices();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DefaultServerProvider : IServerProvider
{
public void AddHttpServices()
{
// 获取 http 终结点
var webEndpoint = RpcEndpointHelper.GetLocalWebEndpoint();
if (webEndpoint == null) // 获取失败则抛出异常
{
throw new SilkyException("Failed to obtain http service rpcEndpoint");
}
// 将http 终结点添加的服务提供者的终结点列表中
_server.Endpoints.Add(webEndpoint);
}
// 其他代码略...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
从上述代码我们可以看到,只有使用web主机构建(托管)应用的主机,在服务启动过程中才会有将http终结点添加到silky服务提供者的终结点列表中;Silky服务内部之间的通信是由dotnetty实现rpc框架,http终结点的用途是提供了对服务外部访问的入口;
备注
如果是由Web主机 (opens new window) 托管的Silky应用,那么在在此时才会首次获取DefaultServerProvider
的实例,也就是在此时才会进行服务与服务条目的解析;
3.2 在模块DotNettyTcpModule
初始化任务的过程中,从Ioc容器中获取到消息监听者DotNettyTcpServerMessageListener
实例后,完成监听任务后,添加支持RPC
协议的服务;
[DependsOn(typeof(RpcModule), typeof(DotNettyModule))]
public class DotNettyTcpModule : SilkyModule
{
// 其他代码略...
public override async Task Initialize(ApplicationContext applicationContext)
{
//获取消息监听者实例
var messageListener =
applicationContext.ServiceProvider.GetRequiredService<DotNettyTcpServerMessageListener>();
// 完成消息监听任务
await messageListener.Listen();
// 获取silky主机服务提供者实例
var serverProvider =
applicationContext.ServiceProvider.GetRequiredService<IServerProvider>();
// 添加支持TCP协议的服务
serverProvider.AddRpcServices();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
通过上面的代码我们看到,只有在完成服务端消息监听任务之后,Silky服务主机才会完成添加支持RPC协议的服务,支持RPC的服务就是前文所述的应用服务;Silky微服务之间的通信主要是由dotnetty实现的RPC框架完成的。
public class DefaultServerProvider : IServerProvider
{
public void AddRpcServices()
{
var rpcEndpoint = EndpointHelper.GetLocalRpcEndpoint();
_server.Endpoints.Add(rpcEndpoint);
var rpcServices = _serviceManager.GetLocalService(ServiceProtocol.Rpc);
foreach (var rpcService in rpcServices)
{
_server.Services.Add(rpcService.ServiceDescriptor);
}
}
// 其他代码略...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
备注
如果是由通用主机 (opens new window) 托管的Silky应用,那么在在此时才会首次获取DefaultServerProvider
的实例,也就是在此时才会进行服务与服务条目的解析;
3.3 在模块WebSocketModule
初始化任务的过程中,查找到所有支持WebSocket
的服务,并通过WebSocketServerBootstrap
的实例完成创建ws服务,这些服务将会提供WebSocket
服务,任务完成后,将通过Silky主机服务提供者DefaultServerProvider
的实例添加对ws服务
;
[DependsOn(typeof(RpcModule))]
public class WebSocketModule : SilkyModule
{
// 其他代码略...
public override async Task Initialize(ApplicationContext applicationContext)
{
var typeFinder = applicationContext.ServiceProvider.GetRequiredService<ITypeFinder>();
var webSocketServices = GetWebSocketServices(typeFinder);
var webSocketServerBootstrap =
applicationContext.ServiceProvider.GetRequiredService<WebSocketServerBootstrap>();
webSocketServerBootstrap.Initialize(webSocketServices);
var serverProvider =
applicationContext.ServiceProvider.GetRequiredService<IServerProvider>();
serverProvider.AddWsServices();
}
private (Type, string)[] GetWebSocketServices(ITypeFinder typeFinder)
{
var wsServicesTypes = ServiceHelper.FindServiceLocalWsTypes(typeFinder);
return wsServicesTypes.Select(p => (p, WebSocketResolverHelper.ParseWsPath(p))).ToArray();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class DefaultServerProvider : IServerProvider
{
public void AddWsServices()
{
var wsEndpoint = RpcEndpointHelper.GetWsEndpoint();
_server.Endpoints.Add(wsEndpoint);
var wsServices = _serviceManager.GetLocalService(ServiceProtocol.Ws);
foreach (var wsService in wsServices)
{
_server.Services.Add(wsService.ServiceDescriptor);
}
}
// 其他代码略...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
websocket服务是如何解析,如何创建支持websocket的服务这个我们将会在之后的文档中介绍;
备注
只有依赖了
WebSocketModule
模块的Silky应用,才支持提供WebSocket
服务,提供WebSocket
服务必须要求继承Silky.WebSocket.WsAppServiceBase
;silky框架的websocket是通过网关实现代理的,通过代理再与具体的Silky应用服务提供者进行连接;
websocket服务是由框架websocket-sharp-core (opens new window)提供的;
websocket服务提供的方法也会被解析为服务条目,也可以与其他微服务实例实现RPC通信;
← 服务与服务条目的解析 终结点与路由 →