<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Consul服務發現的使用方法:
      1. 在每臺電腦上都以Client Mode的方式運行一個Consul代理, 這個代理只負責與Consul Cluster高效地交換最新注冊信息(不參與Leader的選舉)
      2. 每臺電腦上的服務Service都向本機的consul代理注冊 服務名稱和提供服務的url
      3. 當Computer1上部署的程序ServiceA需要調用服務ServiceB時, 程序ServiceA直接從本機的Consul Agent通過服務名稱獲取ServiceB的訪問地址, 然后直接向ServiceB的url發出請求

       

       

      本文的重點不是描述上述過程, 只是準備分享一下自己編寫的服務注冊代碼, 雖然網上已經有不少類似的文章, 個人覺得自己的代碼要智能一點
      其他文章一般要求在參數中提供 服務訪問的外部地址, 但我想可以直接從 IWebHostBuilder.UseUrls(params string[] urls)獲取, 這樣就可以少輸入一個參數.
      但是在實現的時候才發現, 問題很多
      1. urls可以輸入多個, 要有一個種最佳匹配的方式, 從里面選取一個注冊到consul里
          這里假設該服務會被不同服務器的程序調用, 那么localhost(127.0.0.1)首先要排除掉, 剩下urls隨便選取一個供其他程序調用, 當然用戶也可以指定一個ip
      2. urls可以使用 "0.0.0.0"、"[::]", 表示綁定所有網卡地址的80端口, 而物理服務器往往有多個網卡
          假如服務器確實只有一個IP, 直接使用即可; 假如有多個IP, 還是必須讓用戶傳入通過參數指定一個IP
      3. urls還可以使用 "192.168.1.2:0"這種動態端口, asp.net core會隨機選擇一個端口讓外部訪問, 但這要服務器完全啟動后才能得知是哪個端口
          使用IApplicationLifetime.ApplicationStarted 發起注冊請求
      4. IPv6地址表示方式解析起來非常麻煩
           System.Uri這個類已經支持IPv6, 可以直接

       

      下面就是實現代碼, 需要nuget Consul

      using Consul;
      using Microsoft.AspNetCore.Builder;
      using Microsoft.AspNetCore.Hosting;
      using Microsoft.AspNetCore.Hosting.Server.Features;
      using Microsoft.Extensions.Configuration;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      public static class RegisterCansulExtension
      {
          public static void RegisterToConsul(this IApplicationBuilder app, IConfiguration configuration, IApplicationLifetime lifetime)
          {
              lifetime.ApplicationStarted.Register(() =>
              {
                  string serviceName = configuration.GetValue<string>("serviceName");
                  string serviceIP = configuration.GetValue<string>("serviceIP");
                  string consulClientUrl = configuration.GetValue<string>("consulClientUrl");
                  string healthCheckRelativeUrl = configuration.GetValue<string>("healthCheckRelativeUrl");
                  int healthCheckIntervalInSecond = configuration.GetValue<int>("healthCheckIntervalInSecond");
                  ICollection<string> listenUrls = app.ServerFeatures.Get<IServerAddressesFeature>().Addresses;
      
      
                  if (string.IsNullOrWhiteSpace(serviceName))
                  {
                      throw new Exception("Please use --serviceName=yourServiceName to set serviceName");
                  }
                  if (string.IsNullOrEmpty(consulClientUrl))
                  {
                      consulClientUrl = "http://127.0.0.1:8500";
                  }
                  if (string.IsNullOrWhiteSpace(healthCheckRelativeUrl))
                  {
                      healthCheckRelativeUrl = "health";
                  }
                  healthCheckRelativeUrl = healthCheckRelativeUrl.TrimStart('/');
                  if (healthCheckIntervalInSecond <= 0)
                  {
                      healthCheckIntervalInSecond = 1;
                  }
      
      
                  string protocol;
                  int servicePort = 0;
                  if (!TryGetServiceUrl(listenUrls, out protocol, ref serviceIP, out servicePort, out var errorMsg))
                  {
                      throw new Exception(errorMsg);
                  }
      
                  var consulClient = new ConsulClient(ConsulClientConfiguration => ConsulClientConfiguration.Address = new Uri(consulClientUrl));
      
                  var httpCheck = new AgentServiceCheck()
                  {
                      DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10),//服務啟動多久后注冊
                      Interval = TimeSpan.FromSeconds(healthCheckIntervalInSecond),
                      HTTP = $"{protocol}://{serviceIP}:{servicePort}/{healthCheckRelativeUrl}",
                      Timeout = TimeSpan.FromSeconds(2)
                  };
      
                  // 生成注冊請求
                  var registration = new AgentServiceRegistration()
                  {
                      Checks = new[] { httpCheck },
                      ID = Guid.NewGuid().ToString(),
                      Name = serviceName,
                      Address = serviceIP,
                      Port = servicePort,
                      Meta = new Dictionary<string, string>() { ["Protocol"] = protocol },
                      Tags = new[] { $"{protocol}" }
                  };
                  consulClient.Agent.ServiceRegister(registration).Wait();
      
                  //服務停止時, 主動發出注銷
                  lifetime.ApplicationStopping.Register(() =>
                  {
                      try
                      {
                          consulClient.Agent.ServiceDeregister(registration.ID).Wait();
                      }
                      catch
                      { }
                  });
              });
          }
      
      
          private static bool TryGetServiceUrl(ICollection<string> listenUrls, out string protocol, ref string serviceIP, out int port, out string errorMsg)
          {
              protocol = null;
              port = 0;
              errorMsg = null;
              if (!string.IsNullOrWhiteSpace(serviceIP)) // 如果提供了對外服務的IP, 只需要檢測是否在listenUrls里面即可
              {
                  foreach (var listenUrl in listenUrls)
                  {
                      Uri uri = new Uri(listenUrl);
                      protocol = uri.Scheme;
                      var ipAddress = uri.Host;
                      port = uri.Port;
      
                      if (ipAddress == serviceIP || ipAddress == "0.0.0.0" || ipAddress == "[::]")
                      {
                          return true;
                      }
                  }
                  errorMsg = $"The serviceIP that you provide is not in urls={string.Join(',', listenUrls)}";
                  return false;
              }
              else // 沒有提供對外服務的IP, 需要查找本機所有的可用IP, 看看有沒有在 listenUrls 里面的
              {
                  var allIPAddressOfCurrentMachine = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
                          .Select(p => p.GetIPProperties())
                          .SelectMany(p => p.UnicastAddresses)
                          // 這里排除了 127.0.0.1 loopback 地址
                          .Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address))
                          .Select(p => p.Address.ToString()).ToArray();
                  var uris = listenUrls.Select(listenUrl => new Uri(listenUrl)).ToArray();
                  // 本機所有可用IP與listenUrls進行匹配, 如果listenUrl是"0.0.0.0"或"[::]", 則任意IP都符合匹配
                  var matches = allIPAddressOfCurrentMachine.SelectMany(ip =>
                          uris.Where(uri => ip == uri.Host || uri.Host == "0.0.0.0" || uri.Host == "[::]")
                          .Select(uri => new { Protocol = uri.Scheme, ServiceIP = ip, Port = uri.Port })
                  ).ToList();
      
                  if (matches.Count == 0)
                  {
                      errorMsg = $"This machine has IP address=[{string.Join(',', allIPAddressOfCurrentMachine)}], urls={string.Join(',', listenUrls)}, none match.";
                      return false;
                  }
                  else if (matches.Count == 1)
                  {
                      protocol = matches[0].Protocol;
                      serviceIP = matches[0].ServiceIP;
                      port = matches[0].Port;
                      return true;
                  }
                  else
                  {
                      errorMsg = $"Please use --serviceIP=yourChosenIP to specify one IP, which one provide service: {string.Join(",", matches)}.";
                      return false;
                  }
              }
          }
      }
      View Code

      使用時可以提供5個參數, 只有serviceName是必須要由參數提供的, serviceIP會自動盡可能匹配出來, consulClientUrl默認是http://127.0.0.1:8500, healthCheckRelativeUrl默認是 /health, healthCheckIntervalInSecond默認是1秒

       

      使用方法
      上面代碼里 健康檢查 使用了asp.net core的HealthChecks中間件, 需要在Startup.ConfigureServices(IServiceCollection services)中增加
      services.AddHealthChecks();
      在Startup.Configure也要增加UseHealthChecks()

      public class Startup
      {
          public Startup(IConfiguration configuration)
          {
              Configuration = configuration;
          }
      
          public IConfiguration Configuration { get; }
      
          public void ConfigureServices(IServiceCollection services)
          {
              services.AddHealthChecks();
              services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
          }
      
          public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
          {
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
              }
      
              // consul的http check只需要返回是200, 就認為服務可用; 這里必須把Degraded改為503
              app.UseHealthChecks("/Health", new HealthCheckOptions()
              {
                  ResultStatusCodes =
                  {
                      [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Healthy] = StatusCodes.Status200OK,
                      [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Degraded] = StatusCodes.Status503ServiceUnavailable,
                      [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
                  }
              });
      
              app.UseMvc();
      
              app.RegisterToConsul(Configuration, lifetime);
          }
      }

       調試的時候, 也不能使用默認的 http://localhost:5000了

       

       

       

      后記: 這段代碼也是很久以前寫的了, 后來發現Ocelot是個功能很豐富的網關, 幫我們做了很大部分工作, 實施微服務的基礎功能就不再寫了.

      后來又學習了Kubernetes, 感覺這才是微服務的正道, 但Kubernetes更復雜, 對運維有更高的要求, 幸好各大云服務商都提供了Kubernetes的基礎設施, 這樣只需要開發人員提升開發方式即可

      現在Service Mesh不斷發展, 但還沒形成統一的解決方案, 其中Consul也支持Mesh, 有時間再寫吧

       

       

       

      End

       

      posted on 2019-03-15 08:44  zhouandke  閱讀(2499)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 国产精品精品一区二区三| 2021亚洲va在线va天堂va国产| 狠狠色噜噜狠狠狠777米奇小说| 国产精品亚洲二区在线看| 花式道具play高h文调教| 国产99视频精品免费视频36| 深夜免费av在线观看| 日韩少妇人妻vs中文字幕| 国产成人无码一二三区视频 | 久久久国产乱子伦精品作者| 国产中文三级全黄| 亚洲天堂成人一区二区三区| 免青青草免费观看视频在线 | 九九久久人妻精品一区色| 人妻蜜臀久久av不卡| 欧美乱大交aaaa片if| 内射视频福利在线观看| 粉嫩av国产一区二区三区| 久久中文字幕无码一区二区| 天堂v亚洲国产v第一次| 国产精品视频免费一区二区三区| 亚洲va成无码人在线观看天堂| 苍山县| 欧美精品黑人粗大破除| 99久久er热在这里只有精品99| 久久久久人妻一区精品色| 久久国内精品自在自线91| 在线播放亚洲成人av| 国产无套精品一区二区| 一本久道久久综合狠狠躁av| 久久热精品视频在线视频| 国产精品国产高清国产av| 亚洲色成人网站www永久四虎| 久久国产自偷自偷免费一区| 4虎四虎永久在线精品免费| 一本色道婷婷久久欧美| 激情综合网激情五月俺也去| 国产区成人精品视频| 日韩中文字幕v亚洲中文字幕| 国产蜜臀在线一区二区三区| 性欧美乱熟妇xxxx白浆|