微信:tangy8080
電子郵箱:914661180@qq.com
更新時間:2019-06-28 14:25:40 星期五node
歡迎您訂閱和分享個人訂閱號,訂閱號內會不按期分享一些我本身學習過程當中的編寫的文章
如您在閱讀過程當中發現文章錯誤,可添加個人微信 tangy8080 進行反饋.感謝您的支持。
git
介紹多個服務之間進行通信算法
[無]數據庫
服務之間應該儘可能較少調用.以減小耦合度,若是彼此調用鏈過於頻繁.可能會引發整個調用鏈的異常.
https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/architect-microservice-container-applications/communication-in-microservice-architecture
The microservice community promotes the philosophy of "smart endpoints and dumb pipes" This slogan encourages a design that's as decoupled as possible between microservices, and as cohesive as possible within a single microservice. As explained earlier, each microservice owns its own data and its own domain logic. But the microservices composing an end-to-end application are usually simply choreographed by using REST communications rather than complex protocols such as WS-* and flexible event-driven communications instead of centralized business-process-orchestrators.
微信
但服務之間的調用有時候會變得"隨其天然",以上一章利用consul實現k8s服務自動發現
結尾的兩個服務爲例說明
app
terminal須要數據庫的配置信息(ip,port等)以存儲各個終端的數據,這些配置存放在configcenter中.那麼terminal服務如何從configcenter中取出配置呢? 這時候就涉及到了服務間的通信了框架
凡是涉及到通信的,通常都會涉及到兩個概念asp.net
在微服務之間通信目前比較流行的有兩種 TCP和HTTPdom
HTTP函數
這裏,我選擇本身手擼一個簡單的微服務之間的調用的庫,它的工做模式以下
在ConsulCaller中,咱們使用了Consul庫進行服務發現.當發現了服務實例時,程序會根據隨機算法選取實例.而後返回給調用方.
git://gitblit.honeysuckle.site/public/Honeysuckle.git
public static void AddConsulCaller(this IServiceCollection services, Action<ConsulCallerOptions> optionsAction) { var consulConfiguration=new ConsulConfiguration(); services.AddSingleton<IConsulConfiguration>(consulConfiguration); services.AddSingleton<IServiceDiscover, ServiceDiscover>(); services.AddSingleton<IConsulClientFactory, ConsulClientFactory.ConsulClientFactory>(); services.AddTransient<IConsulCaller, ConsulCaller>(); var consulCallerOptions = new ConsulCallerOptions(consulConfiguration); optionsAction.Invoke(consulCallerOptions); }
public IConsulClient Get(IConsulConfiguration config) { return new ConsulClient(c => { c.Address = new Uri($"http://{config.Host}:{config.Port}"); if (!string.IsNullOrEmpty(config?.Token)) { c.Token = config.Token; } }); }
3.另一個重要的接口是IServiceDiscover,它包含一個GetServices的函數,該函數根據服務名稱返回服務實例列表
private readonly IConsulClient _consul; private const string VersionPrefix = "version-"; public ServiceDiscover(IConsulClientFactory consulClientFactory, IConsulConfiguration consulConfiguration) { _consul = consulClientFactory.Get(consulConfiguration); } public List<Service> GetServices(string key) { var queryResult = _consul.Health.Service(key, string.Empty, true).Result; var services = new List<Service>(); foreach (var serviceEntry in queryResult.Response) { if (IsValid(serviceEntry)) { var nodes = _consul.Catalog.Nodes().Result; if (nodes.Response == null) { services.Add(BuildService(serviceEntry, null)); } else { var serviceNode = nodes.Response.FirstOrDefault(n => n.Address == serviceEntry.Service.Address); services.Add(BuildService(serviceEntry, serviceNode)); } } else { Console.WriteLine($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"); } } return services; } private static Service BuildService(ServiceEntry serviceEntry, Node serviceNode) { return new Service( serviceEntry.Service.Service, new ServiceHostAndPort(serviceNode == null ? serviceEntry.Service.Address : serviceNode.Name, serviceEntry.Service.Port), serviceEntry.Service.ID, GetVersionFromStrings(serviceEntry.Service.Tags), serviceEntry.Service.Tags ?? Enumerable.Empty<string>()); } private static bool IsValid(ServiceEntry serviceEntry) { if (string.IsNullOrEmpty(serviceEntry.Service.Address) || serviceEntry.Service.Address.Contains("http://") || serviceEntry.Service.Address.Contains("https://") || serviceEntry.Service.Port <= 0) { return false; } return true; } private static string GetVersionFromStrings(IEnumerable<string> strings) { return strings ?.FirstOrDefault(x => x.StartsWith(VersionPrefix, StringComparison.Ordinal)) .TrimStart(VersionPrefix); }
4.最後咱們提供了一個IConsulCaller接口,它提供一個Call接口,輸入服務名稱和一個回調函數.
1.在asp.net core引用中添加了ConsulCaller服務
//使用ConsulCaller服務 services.AddConsulCaller(options => { options.ConsulConfiguration.Host = Configuration["Consul:Host"]; options.ConsulConfiguration.Port = Convert.ToInt32(Configuration["Consul:Port"]); });
2.調用集羣中的其餘服務
const string serviceName = "configcenter"; _consulCaller.Call(serviceName, (endpoint, httpclient) => { try { var uri = $"http://{endpoint.DownstreamHost}:{endpoint.DownstreamPort}/Consul/Get"; //根據返回的服務實例,實現本身的調用邏輯 } catch (Exception ex) { var errorMsg = $"{nameof(TerminalServerDbContext)}.{nameof(OnConfiguring)} _consulCaller.Call Error "; Console.WriteLine(errorMsg + ex.Message); Logger.Error(errorMsg, ex); } finally { httpclient.Dispose(); } });
[無]