.NetCore框架Surging系列(一)介绍
.NetCore框架Surging系列(二)HTTP
.NetCore框架Surging系列(三)HTTP本地路由发现过程
.NetCore框架Surging系列(四)RPC客户端过程
.NetCore框架Surging系列(五)路由注册
Surging路由注册和发现的基本单位为API方法
,也就是说注册的是各个服务中的各个方法,网关和Rpc调用时通过路由地址找到对应方法和分配到相应的服务器,在Consul中以Key/Value形式保存。
Consulhttp://192.168.1.112:8500/ui/dc1/kv/services/serviceRoutes/
value内容为 接口地址信息 和 接口描述
{
"AddressDescriptors": [
{
"Value": "{\"Ip\":\"192.168.4.56\",\"Port\":30211,\"WanIp\":\"192.168.249.103\",\"WsPort\":30231,\"MqttPort\":97,\"HttpPort\":30221}"
}
],
"ServiceDescriptor": {
"Id": "BaseDataService.Application.IServices.IRoleService.CreateRole_input",
"Token": "ffdd4f2b98b14c32ade536f5aa4f36e8",
"RoutePath": "api/role/createrole",
"Metadatas": {
"WaitExecution": true,
"EnableAuthorization": true,
"DisableNetwork": false,
"Director": null,
"GroupName": "创建角色接口",
"Date": "2019-11-12",
"AuthType": "JWT"
}
}
}
注册过程
左侧是MapService,Run之后注册路由
声明MapServices
首先在Program中调用静态方法ServiceHostBuilderExtensions.UseServer
向IServiceHostBuilder中声明MapServices
,后面Host.Run起来之后执行。
public static class ServiceHostBuilderExtensions
{
public static IServiceHostBuilder UseServer(this IServiceHostBuilder hostBuilder, Action<SurgingServerOptions> options, bool isStartAsync = true)
{
var serverOptions = new SurgingServerOptions();
AppConfig.ServerOptions = serverOptions;
return hostBuilder.MapServices(mapper =>
{
BuildServiceEngine(mapper);
//... 其他代码省略
mapper.Resolve<IModuleProvider>().Initialize();
if (!AppConfig.ServerOptions.DisableServiceRegistration)
{
//注册Command
mapper.Resolve<IServiceCommandManager>().SetServiceCommandsAsync().Wait();
//注册路由
ConfigureRoute(mapper).Wait();
}
//... 其他代码省略
}
}
}
执行MapServices进行注册
HostRun起来后会一一调用MapService中的mapper方法,可以查看类ServiceHost
中方法Run()
以下是上一步提到的MapService中代码ConfigureRoute(mapper).Wait();
ServiceHostBuilderExtensions.ConfigureRoute
public static async Task ConfigureRoute(IContainer mapper)
{
if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.Tcp ||
AppConfig.ServerOptions.Protocol == CommunicationProtocol.None)
{
//... 其他代码省略
//调用注册方法
await routeProvider.RegisterRoutes(0);
}
}
获取本地路由
注册前获取本地路由,在之前《.NetCore框架Surging系列(三)HTTP本地路由发现过程》讲到了怎么获取本地路由。
DefaultServiceRouteProvider.RegisterRoutes
public async Task RegisterRoutes(decimal processorTime)
{
var addess = NetUtils.GetHostAddress();
addess.ProcessorTime = processorTime;
RpcContext.GetContext().SetAttachment("Host", addess);
//获取本地路由
var addressDescriptors = _serviceEntryManager.GetEntries().Select(i =>
{
i.Descriptor.Token = _serviceTokenGenerator.GetToken();
return new ServiceRoute
{
Address = new[] { addess },
ServiceDescriptor = i.Descriptor
};
}).ToList();
//调用路由管理 进入注册
await _serviceRouteManager.SetRoutesAsync(addressDescriptors);
}
注册路由
在注册路由的时候,需要将本地路由和Consul远程路由进行合并,增加新的、删除多余的。
ConsulServiceRouteManager.SetRoutesAsync
public override async Task SetRoutesAsync(IEnumerable<ServiceRoute> routes)
{
//锁
var locks = await CreateLock();
try
{
await _consulClientProvider.Check();
var hostAddr = NetUtils.GetHostAddress();
var serviceRoutes = await GetRoutes(routes.Select(p => $"{ _configInfo.RoutePath}{p.ServiceDescriptor.Id}"));
foreach (var route in routes)
{
var serviceRoute = serviceRoutes.Where(p => p.ServiceDescriptor.Id == route.ServiceDescriptor.Id).FirstOrDefault();
if (serviceRoute != null)
{
var addresses = serviceRoute.Address.Concat(
route.Address.Except(serviceRoute.Address)).ToList();
foreach (var address in route.Address)
{
addresses.Remove(addresses.Where(p => p.ToString() == address.ToString()).FirstOrDefault());
addresses.Add(address);
}
route.Address = addresses;
}
}
//删除多余路由
await RemoveExceptRoutesAsync(routes, hostAddr);
//注册
await base.SetRoutesAsync(routes);
}
finally
{
locks.ForEach(p => p.Release());
}
}
删除接口
private async Task RemoveExceptRoutesAsync(IEnumerable<ServiceRoute> routes, AddressModel hostAddr)
{
routes = routes.ToArray();
var clients = await _consulClientProvider.GetClients();
foreach (var client in clients)
{
if (_routes != null)
{
var oldRouteIds = _routes.Select(i => i.ServiceDescriptor.Id).ToArray();
var newRouteIds = routes.Select(i => i.ServiceDescriptor.Id).ToArray();
var deletedRouteIds = oldRouteIds.Except(newRouteIds).ToArray();
foreach (var deletedRouteId in deletedRouteIds)
{
var addresses = _routes.Where(p => p.ServiceDescriptor.Id == deletedRouteId).Select(p => p.Address).FirstOrDefault();
//删除路由
if (addresses.Contains(hostAddr))
await client.KV.Delete($"{_configInfo.RoutePath}{deletedRouteId}");
}
}
}
}
开始注册
protected override async Task SetRoutesAsync(IEnumerable<ServiceRouteDescriptor> routes)
{
var clients = await _consulClientProvider.GetClients();
foreach (var client in clients)
{
foreach (var serviceRoute in routes)
{
var nodeData = _serializer.Serialize(serviceRoute);
var keyValuePair = new KVPair($"{_configInfo.RoutePath}{serviceRoute.ServiceDescriptor.Id}") { Value = nodeData };
//就在这里 修改路由
await client.KV.Put(keyValuePair);
}
}
}
总结
以上就是整个路由注册过程的所有内容。
路由注册的单位 API方法,以Key/Value形式注册,Key为 namespace.class.method,value包含服务地址等相关信息,后续再分享路由发现,以后可能改为服务注册和服务发现…………