.net5+nacos+ocelot 配置中心和服务发现实现
相關文章:手動造輪子——為Ocelot集成Nacos注冊中心
出處:https://www.cnblogs.com/buruainiaaaa/p/14121176.html
作者:唐@?
最近一段時間 因公司業務需要,需要使用.net5做一套微服務的接口,使用nacos 做注冊中心和配置中心,ocelot做網關。
因為ocelot 支持的是consol和eureka,如果使用nacos做服務發現,需要自己集成,以此記錄下
Nacos 支持基于 DNS 和基于 RPC 的服務發現(可以作為注冊中心)、動態配置服務(可以做配置中心)、動態 DNS 服務。官網地址:https://nacos.io/en-us/
ocelot 相信大家都比較熟悉,官網:https://ocelot.readthedocs.io/en/latest/index.html
?環境安裝:
nacos參考地址:https://blog.csdn.net/ooyhao/article/details/102744904
基于.net版本的nacos ?sdk:nacos-sdk-csharp-unofficial.AspNetCore ?(此處有坑 :Nacos.AspNetCore 已經停止更新,代碼已遷移,服務注冊會有問題)
SDK源碼地址:https://github.com/nacos-group/nacos-sdk-csharp
配置中心:
1.在nacos添加配置
?
? ? 2.在.net 項目中 配置文件中 添加相關配置
1 "nacos": {2 "ServerAddresses": [ "http://127.0.0.1:8849/" ],3 "DefaultTimeOut": 30000,4 "Namespace": "",5 "ListenInterval": 30000,6 "ServiceName": "ServiceName","RegisterEnabled": true,7 "Weight": 108 },9 "nacosData": { 10 "DataId": "nacosConfig", 11 "Group": "Pro" 12 }3.在Startup.cs添加nacos? sdk的DI注冊
1 services.AddNacos(Configuration);?4.創建AppConfig類,定義構造函數:(從DI中獲取INacosConfigClient對象)
public AppConfig(IServiceCollection _services, IConfiguration _configuration){services = _services;configuration = _configuration;var serviceProvider = services.BuildServiceProvider();_configClient = serviceProvider.GetService<INacosConfigClient>();}5.添加LoadConfig方法,加載配置中心的配置
代碼說明:pKey入參 為配置文件中的key(nacosData),responseJson為配置中心的完整配置字符串,可以是json,可以是key=value模式,根據字符串格式,轉為Dictionary中,放入靜態私有對象中
/// <summary>/// 加載nacos配置中心/// </summary>/// <param name="pKey"></param>private async Task LoadConfig(string pKey){try{GetConfigRequest configRequest = configuration.GetSection(pKey).Get<GetConfigRequest>();if (configRequest == null || string.IsNullOrEmpty(configRequest.DataId)){return;}var responseJson = await _configClient.GetConfigAsync(configRequest);Console.WriteLine(responseJson);if (string.IsNullOrEmpty(responseJson)){return;}var dic = LoadDictionary(responseJson);if (pKey == commonNacosKey){commonConfig = dic;}else{dicConfig = dic;}}catch (Exception ex){throw ex;}}6.添加監聽:
ps:
AddListenerRequest對象為nacos sdk的監聽請求對象,通過INacosConfigClient對象的AddListenerAsync方法,可以添加對nacos dataid=nacosConfig 的監聽,監聽的時間間隔設置可以為:ListenInterval 1 /// <summary>2 /// 監控3 /// </summary>4 private void ListenerConfig()5 {6 AddListenerRequest request = configuration.GetSection("nacosData").Get<AddListenerRequest>();7 request.Callbacks = new List<Action<string>>() {8 x=>{9 var dic = LoadDictionary(x); 10 foreach (var item in dicConfig.Keys) 11 { 12 if (dic.Keys.Any(p=>p==item)) 13 { 14 if (dic[item] != dicConfig[item]) 15 { 16 dicConfig[item]=dic[item].Trim(); 17 } 18 }else 19 { 20 dicConfig.Remove(item); 21 } 22 } 23 foreach (var item in dic.Keys) 24 { 25 if (!dicConfig.Keys.Any(p=>p==item)){ 26 dicConfig.Add(item,dic[item]); 27 } 28 } 29 } 30 }; 31 var serviceProvider = services.BuildServiceProvider(); 32 INacosConfigClient _configClient = serviceProvider.GetService<INacosConfigClient>(); 33 _configClient.AddListenerAsync(request); 34 }7.添加自動注入:
ps:如果需要在同一個項目中,獲取多個配置,需要AppConfig對象的單列模式,這一點 自己注意下
public static IServiceCollection AddLoadConfig(this IServiceCollection _services, IConfiguration _configuration){var config = new AppConfig(_services, _configuration);config.Load();return _services;}?/******************************************************* 配置中心? end *************************************************************/
服務注冊:
基于上面的配置信息 在自動注入中添加如下代碼即可
services.AddNacosAspNetCore(conf);啟動之后 在nacos中,就可以看到此服務? 如果在nacos 看到多個實列 或者 端口號和項目啟動的端口號不一致,最好添加IP和port。
/***************************************************************服務注冊? end***********************************************************************/
基于ocelot 的服務發現:
新建網關項目,添加ocelot和 nacos sdk 的nuget依賴
查看ocelot的官方文檔就會發現,如果 能夠取到nacos 中 服務的名稱和服務里邊可用實列的ip和port,然后把這些信息放入ocelot里邊的, 就可以通過ocelot訪問到這些服務接口
然后在通過自定義監聽器,就可以實現想要的效果
通過上面的配置中心的配置方式,在nacos中 添加 ocelot 的模板配置
{"Routes": [{"DownstreamHostAndPorts": [{"Host": "localhost","Port": 5000}],"DownstreamPathTemplate": "/{url}","DownstreamScheme": "http","UpstreamHttpMethod": ["GET", "POST", "DELETE", "PUT"],"UpstreamPathTemplate": "/OrderServer/{url}","LoadBalancerOptions": {"Type": "RoundRobin"}}, {"DownstreamHostAndPorts": [{"Host": "localhost","Port": 5000}],"DownstreamPathTemplate": "/{url}","DownstreamScheme": "http","UpstreamHttpMethod": ["GET", "POST", "DELETE", "PUT"],"UpstreamPathTemplate": "/ProductServer/{url}"}],"ServiceDiscoveryProvider": {},"GlobalConfiguration": {} }關于ocelot的Startup.cs的相關配置? 這里就不贅述了,網上有很多。
這里的關鍵是,從nacos中拉取服務列表,然后根據ocelot的配置模板,生成需要的ocelot的配置信息,然后放入ocelot中
獲取nacos中所有的服務列表?
ps:通過INacosNamingClient對象的ListServicesAsync方法,獲取nacos 的服務
/// <summary>/// 獲取所有服務/// </summary>/// <param name="serviceProvider"></param>/// <param name="_servicesRequest"></param>/// <returns></returns>private async Task<List<ListInstancesResult>> GetServerListener(IServiceProvider serviceProvider, object _servicesRequest){ListServicesRequest request = (ListServicesRequest)_servicesRequest;try{var _namingClient = serviceProvider.GetService<INacosNamingClient>();var res = await _namingClient.ListServicesAsync(request);List<ListInstancesResult> resultList = new List<ListInstancesResult>();if (res.Count > 0){List<Task<ListInstancesResult >> taskList = new List<Task<ListInstancesResult>>();foreach (var item in res.Doms){var taskItem = GetListInstancesResult(_namingClient,item);taskList.Add(taskItem);}Task.WaitAll(taskList.ToArray());foreach (var item in taskList){resultList.Add(item.Result);}}return resultList;}catch (Exception ex){LoggerLocal.Error(ex.Message, ex);return new List<ListInstancesResult>();}}?將nacos的服務和配置中心的ocelot模板轉換為ocelot的配置對象
/// <summary>/// nacos中的服務 轉為ocelot對象的路由/// </summary>/// <param name="fileConfiguration"></param>/// <param name="listInstancesResults"></param>/// <returns></returns>private FileConfiguration InstancesResultToFileConfiguration(FileConfigurationTemplate fileConfiguration, List<ListInstancesResult> listInstancesResults) {if (fileConfiguration.RouteTemplate == null || fileConfiguration.RouteTemplate.Count == 0){throw new Exception("路由不能為空");}var result = new FileConfiguration() {GlobalConfiguration = fileConfiguration.GlobalConfiguration,Aggregates = fileConfiguration.Aggregates,DynamicRoutes = fileConfiguration.DynamicRoutes,Routes = new List<FileRoute>()};nacosServerModelList.ServerInfo = new List<ServerInfo>();var routeList = fileConfiguration.RouteTemplate;var defaultRoute = fileConfiguration.RouteTemplate.Find(p=>p.RoutesTemplateName=="common");fileConfiguration.Routes = new List<FileRoute>();foreach (var item in listInstancesResults){var routeTemp = routeList.Find(p => p.ServiceName.ToLower() == item.Dom.ToLower());if (routeTemp == null){routeTemp = defaultRoute;}var newRouteTmp = CopyTo(routeTemp);newRouteTmp.UpstreamPathTemplate = "/" + item.Dom + "/{url}";newRouteTmp.DownstreamPathTemplate = "/{url}";newRouteTmp.DownstreamHostAndPorts = new List<FileHostAndPort>();if (item.Hosts.Count > 0){foreach (var host in item.Hosts){newRouteTmp.DownstreamHostAndPorts.Add(new FileHostAndPort(){Host = host.Ip,Port = host.Port,});}}if (newRouteTmp.DownstreamHostAndPorts.Count > 0){result.Routes.Add(newRouteTmp);nacosServerModelList.ServerInfo.Add(new ServerInfo() { Name = item.Dom });}}UpdSwaggerUrlAction(serviceProvider, nacosServerModelList);return result;}private FileRoute CopyTo(RouteTemplate s){var result = new FileRoute() { AddClaimsToRequest=s.AddClaimsToRequest,DangerousAcceptAnyServerCertificateValidator=s.DangerousAcceptAnyServerCertificateValidator,DelegatingHandlers=s.DelegatingHandlers,DownstreamHeaderTransform=s.DownstreamHeaderTransform,DownstreamHostAndPorts=s.DownstreamHostAndPorts,DownstreamHttpMethod=s.DownstreamHttpMethod,DownstreamHttpVersion=s.DownstreamHttpVersion,DownstreamPathTemplate=s.DownstreamPathTemplate,SecurityOptions=s.SecurityOptions,DownstreamScheme=s.DownstreamScheme,ChangeDownstreamPathTemplate=s.ChangeDownstreamPathTemplate,AddHeadersToRequest=s.AddHeadersToRequest,AddQueriesToRequest=s.AddQueriesToRequest,AuthenticationOptions=s.AuthenticationOptions,FileCacheOptions=s.FileCacheOptions,HttpHandlerOptions=s.HttpHandlerOptions,Key=s.Key,LoadBalancerOptions=s.LoadBalancerOptions,Priority=s.Priority,QoSOptions=s.QoSOptions,RateLimitOptions=s.RateLimitOptions,RequestIdKey=s.RequestIdKey,RouteClaimsRequirement=s.RouteClaimsRequirement,RouteIsCaseSensitive=s.RouteIsCaseSensitive,ServiceName=s.ServiceName,ServiceNamespace=s.ServiceNamespace,Timeout=s.Timeout,UpstreamHeaderTransform=s.UpstreamHeaderTransform,UpstreamHost=s.UpstreamHost,UpstreamHttpMethod=s.UpstreamHttpMethod,UpstreamPathTemplate=s.UpstreamPathTemplate,};return result;}?
將配置信息放入ocelot里邊
ps:這個地方 需要看ocelot的源碼,才知道這中間的對象轉換邏輯
1 private void SetOcelotConfig(FileConfiguration configuration) 2 { 3 4 var internalConfigCreator = serviceProvider.GetService<IInternalConfigurationCreator>(); 5 Task<Response<IInternalConfiguration>> taskResponse = internalConfigCreator.Create(configuration); 6 taskResponse.Wait(); 7 IInternalConfigurationRepository internalConfigurationRepository = serviceProvider.GetService<IInternalConfigurationRepository>(); 8 internalConfigurationRepository.AddOrReplace(taskResponse.Result.Data); 9 }自定義監聽器:
ps:isLoadUri 防止處理過慢,監聽服務 多次監聽
routesMd5:判斷監聽到的服務 是否需要放入ocelot
自定義監聽的方式與nacos sdk中,監聽配置中心的方式類似,有興趣可以看看sdk的源碼
/// <summary>/// 獲取nacos里邊的所有服務信息,同時自定義服務監聽/// </summary>/// <param name="serviceProvider"></param>/// <returns></returns>private async Task<List<ListInstancesResult>> GetServerList(IServiceProvider serviceProvider){var request = new ListServicesRequest{PageNo = 1,PageSize = 100,};List<ListInstancesResult> listInstancesResults = await GetServerListener(serviceProvider, request);//return listInstancesResults;var timeSeconds = 1000 * 10;Timer timer = new Timer(async x =>{//防止重復Timerif (isLoadUri){return;}isLoadUri = true;List<ListInstancesResult> listInstancesList = await GetServerListener(serviceProvider, x);GetConfigRequest configRequest = configuration.GetSection("nacosData").Get<GetConfigRequest>();INacosConfigClient _configClient = serviceProvider.GetService<INacosConfigClient>();Task<string> taskResult = _configClient.GetConfigAsync(configRequest);taskResult.Wait();var responseJson = taskResult.Result;if (listInstancesList.Count>0){var fileConfiguration = InstancesResultToFileConfiguration(JsonConvert.DeserializeObject<FileConfigurationTemplate>(responseJson), listInstancesList);responseJson = JsonConvert.SerializeObject(fileConfiguration);var rMd5 = HashUtil.GetMd5(responseJson);if (!rMd5.Equals(routesMd5)){SetOcelotConfig(fileConfiguration);routesMd5 = rMd5;}}isLoadUri = false;}, request, timeSeconds, timeSeconds);timers.Add(timer);return listInstancesResults;}相關文章:手動造輪子——為Ocelot集成Nacos注冊中心
總結
以上是生活随笔為你收集整理的.net5+nacos+ocelot 配置中心和服务发现实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年,Azure云遇到. NET5
- 下一篇: 如何在 ASP.NET Core 中使用