庐山真面目之四微服务架构Consul和Ocelot简单版本实现

一、简介
       在上一篇文章《庐山真面目之三微服务架构Consul简单版本实现》中,我们已经探讨了如何搭建基于Consul组件的微服务架构,可能很多人感觉很简单。没错,的确很简单,因为我的每篇文章只会解决一个问题,这样更单纯、更精准。如果我们把所有的东西都放在一篇文章里,太多了,不利于学习和查看。我们通过上一篇文章可知,在客户端访问 Consul 组件管理的业务服务实例是多么的麻烦,需要自己写代码实现。项目少,无所谓,只要项目一大,或者项目多了,规模大了,都会对管理和维护带来很大的挑战,毕竟,人喜欢操作简单的东西,想抬杠的免开尊口,主要是没必要。今天我们就解决客户端手写调用策略的问题。

  1、说明
        我先说明一下,这个实现的版本只过是测试版本,以后会把相关的技术点都增加上去,我们一步一步的演化而来,如果是大牛,就可以直接跳过,因为这些东西相对于您来说,这个太简单了。特别说明,这里的所有代码都经过测试,所以大家可以放心使用。

  2、开发环境
        
以下就是开发环境,不用多说,都很简单,一看就知道。
       (1)、开发工具:Visual Studio 2019
       (2)、开发语言:C#
       (3)、开发平台:Net Core3.1,跨平台。
       (4)、服务注册:Consul,服务注册、发现中心
       (5)、网关服务:Ocelot 开源组件,负载均衡,服务治理。
       (6)、操作系统:Windows 10,64bit。

  3、我们的目标
        今天我们要解决的问题是如何做到服务实例调用策略不许要手写,并且还能实现负载均衡,其他问题,比如:Consul 本身的集群的问题暂时就不考虑,我们会一步一步的演变下去。
                  

二、Consul注册、发现服务组件的简介。
                    
         在这里我们只是做简单的介绍,不会详细讨论它的所有技术点,没有那么大的篇幅,再说这样做也就跑题了。如果大家想去学习Consul的有关内容,地址我已经贴出来了,大家可以自行恶补。
         Consul是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,它是一个一个分布式的,高度可用的系统,而且开发使用都很简便。它提供了一个功能齐全的控制平面,主要特点是:服务发现、健康检查、键值存储、安全服务通信、多数据中心。
        上面的一幅图就说明了Consul的工作原理。S-A是使用服务的客户端,他不用关系有多少个服务,只要它需要的时候,他就会向Consul服务中心发出请求,Consul中心就会把和服务名称(在Consul中的名称,也可以说是服务的类别名称)匹配的、在此注册的所有服务实例的地址信息全部返回给S-A客户端,然后客户端,可以根据自己的情况,决定调用的具体策略,可以轮训、可以权重、可以随机,当然其他方式也可以,但是这些工作必须由使用服务的客户端S-A自行解决。
         S-B-1、S-B-2、S-B-3等是在Consul中心注册的服务实例,包括服务实例的地址、端口号、ID名称、服务类别名称等信息。这些服务实例,每个服务实例都有自己的ID名称,多个服务实例可以取一个相同的名称,其实,这个名称是用于分类的。Consul中心查找的时候就是通过这个名称来查找的。这些服务实例,在应用程序一开始的时候就开始注册,并且只注册一次。
         所有的服务实例都注册成功了,时间一分一秒的过去,一个小时之后或者一段时候之后服务还存在吗?我们如何判断呢?这就涉及到我们要谈的第三个方面,健康监测,英文叫:Health Check。Consul中心为我们提供了现成的接口,可以定义针对服务的健康检查,这个健康检查是一个完整的策略,包括:如果检查失败,多久注销服务;服务检查的时间间隔;还有调用检查的超时时间等。这样就能为我们提供一个比较完备的服务注册、发现和检测的解决方案。

        总结如下:
            1
、服务自动注册,可以发现新服务。
            2
、健康检测,可以过滤掉线服务。
            3
、客户端要完成服务调用逻辑,比较麻烦,没有Nginx 方便。

    Consul文档:https://www.consul.io/docs
    Consul官网:https://www.consul.io

三、Ocelot服务组件简介。
              

       今天要给大家介绍的Ocelot是一个基于 .net core的开源WebAPI服务网关项目,它的功能非常强大,包括了路由、请求聚合、服务发现、认证鉴权、限流、负载均衡等功能。而这些功能都可以直接通过修改json配置文件即可使用,非常方便。Ocelot是系统中对外暴露的一个请求入口,所有外部接口都必须通过这个网关才能向下游API发出请求,就如地铁中的安检系统,所有人都必须经过安检才能乘坐地铁。
       当然了,我今天肯定也不会对Ocelot服务组件进行详细的讨论,它有官网和详细的文档,如果想看它的源码也是没有问题的,因为它是开源的。如果大家想去学习的话,可以直接点击我贴出的连接。

         官网:https://threemammals.com/ocelot

       文档:https://ocelot.readthedocs.io/en/latest

       Git:https://github.com/ThreeMammals/Ocelot

四、微服务架构Consul和Ocelot版本实现

      上一篇文章我们解决了业务服务实例的发现和注册问题,当然也有健康检查,可以做到服务实例的动态伸缩。非常给力,也非常兴奋,因为我们又战胜了一个问题,做技术的人员都懂我说的意思。兵来将挡水来土掩,今天我们要解决手写代码去实现服务实例的调用策略。废话少说,我们开始吧。

      1、下载 Consul 服务组件。
              官网下载:https://www.consul.io/downloads
                         
              Consul下载成功后,放在没有包含中文的目录里面,这是我的个人的习惯。
              我的运行目录:D:\Programs\MicroServices\Consul_1.8.4_windows_amd64
                  
      2、配置 Consul 服务组件。
              切换到当前目录,执行如下命令:Consul agent –dev
              
              我们也可以通过浏览器查看 Consul服务中心是否启动成功,地址:http://localhost:8500,如果成功,效果如下:
                    

      3、建立项目,并为项目引入 Consul包。
              (1)、PatrickLiu.MicroService.Client(ASPNETCORE MVC),客户端项目。

                       
            代码如下:
             【1】、HomeController.cs的代码

                 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net.Http;
 5 using Consul;
 6 using Microsoft.AspNetCore.Mvc;
 7 using Microsoft.Extensions.Logging;
 8 using PatrickLiu.MicroService.Interfaces;
 9 using PatrickLiu.MicroService.Models;
10 
11 namespace PatrickLiu.MicroService.Client.Controllers
12 {
13     public class HomeController : Controller
14     {
15         private readonly ILogger<HomeController> _logger;
16         private readonly IUserService _userService;
17 
18         /// <summary>
19         /// 初始化该类型的新实例。
20         /// </summary>
21         /// <param name="logger">注入日志对象。</param>
22         /// <param name="userService">注入用户服务对象。</param>
23         public HomeController(ILogger<HomeController> logger, IUserService userService)
24         {
25             _logger = logger;
26             _userService = userService;
27         }
28 
29         /// <summary>
30         /// 首页。
31         /// </summary>
32         /// <returns></returns>
33         public IActionResult Index()
34         {
35             #region 通过 Ocelot 网关访问服务实例。
36 
37             string url = "http://localhost:6299/gate/users/all";//这个地址是网关的
38 
39             #endregion
40 
41             string content = InvokeAPI(url);
42             this.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
43             Console.WriteLine($"This is {url} Invoke.");
44             
45             #endregion
46 
47             return View();
48         }
49 
50 
51         /// <summary>
52         /// 封装 HttpClient 实例,提供 Http 调用。
53         /// </summary>
54         /// <param name="url">http url 的地址。</param>
55         /// <returns>返回结束数据,格式:JSON。</returns>
56         public static string InvokeAPI(string url)
57         {
58             using (HttpClient client = new HttpClient())
59             {
60                 HttpRequestMessage message = new HttpRequestMessage();
61                 message.Method = HttpMethod.Get;
62                 message.RequestUri = new Uri(url);
63                 var result = client.SendAsync(message).Result;
64                 string conent = result.Content.ReadAsStringAsync().Result;
65                 return conent;
66             }
67         }
68     }
69 }


             【2】、修改Startup.cs代码,红色增加的代码。
                

1 public void ConfigureServices(IServiceCollection services)
2 {
3         services.AddControllersWithViews();
4 
5          services.AddSingleton<IUserService, UserService>();
6  }

 


              (2)、PatrickLiu.MicroService.Interfaces(NETCORE 类库),定义接口。

                       

           代码如下:
                        

 1 using PatrickLiu.MicroService.Models;
 2 using System.Collections.Generic;
 3 
 4 namespace PatrickLiu.MicroService.Interfaces
 5 {
 6     /// <summary>
 7     /// 用户服务的接口定义。
 8     /// </summary>
 9     public interface IUserService
10     {
11         /// <summary>
12         /// 查找指定主键的用户实例对象。
13         /// </summary>
14         /// <param name="id">用户的主键。</param>
15         /// <returns>返回查找到的用户实例对象。</returns>
16         User FindUser(int id);
17 
18         /// <summary>
19         /// 获取所有用户的实例集合。
20         /// </summary>
21         /// <returns>返回所有的用户实例。</returns>
22         IEnumerable<User> UserAll();
23     }
24 }


              (3)、PatrickLiu.MicroService.Models(NETCORE 类库),定义实例类型。

                       

                       代码如下:
            

 1 using System;
 2 
 3 namespace PatrickLiu.MicroService.Models
 4 {
 5     /// <summary>
 6     /// 用户模型。
 7     /// </summary>
 8     public class User
 9     {
10         /// <summary>
11         /// 获取或者设置用户主键。
12         /// </summary>
13         public int ID { get; set; }
14 
15         /// <summary>
16         /// 获取或者设置用户姓名。
17         /// </summary>
18         public string Name { get; set; }
19 
20         /// <summary>
21         /// 获取或者设置用户账号名称。
22         /// </summary>
23         public string Account { get; set; }
24 
25         /// <summary>
26         /// 获取或者设置用户密码。
27         /// </summary>
28         public string Password { get; set; }
29 
30         /// <summary>
31         /// 获取或者设置用户的电子邮箱地址。
32         /// </summary>
33         public string Email { get; set; }
34 
35         /// <summary>
36         /// 获取或者设置用户角色。
37         /// </summary>
38         public string Role { get; set; }
39 
40         /// <summary>
41         /// 获取或者设置用户的登录时间。
42         /// </summary>
43         public DateTime LoginTime { get; set; }
44     }
45 }


              (4)、PatrickLiu.MicroService.Services(NETCORE 类库),定义服务实现。

                       

                       代码如下:
            

 1 using PatrickLiu.MicroService.Interfaces;
 2 using PatrickLiu.MicroService.Models;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Linq;
 6 
 7 namespace PatrickLiu.MicroService.Services
 8 {
 9     /// <summary>
10     /// 实现用户服务接口的实现类型。
11     /// </summary>
12     public class UserService : IUserService
13     {
14         private IList<User> dataList;
15 
16         /// <summary>
17         /// 初始化类型的实例
18         /// </summary>
19         public UserService()
20         {
21             dataList = new List<User>()
22             { new User {ID=1,Name="黄飞鸿",Account="HuangFeiHong",Password="HuangFeiHong123456",Email="huangFeiHong@sina.com", Role="Admin", LoginTime=DateTime.Now },
23             new User {ID=2,Name="洪熙官",Account="HongXiGuan",Password="HongXiGuan54667",Email="HongXiGuan@sina.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) },
24             new User {ID=3,Name="方世玉",Account="FangShiYu",Password="FangShiYu112233",Email="fangShiYu@163.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-30) },
25             new User {ID=4,Name="苗翠花",Account="MiaoCuiHua",Password="MiaoCuiHua887766",Email="miaoCuiHua@sohu.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-90) },
26             new User {ID=5,Name="严咏春",Account="YanYongChun",Password="YanYongChun09392",Email="yanYongChun@263.com", Role="Admin", LoginTime=DateTime.Now.AddMinutes(-50) }};
27         }
28 
29         /// <summary>
30         /// 查找指定主键的用户实例对象。
31         /// </summary>
32         /// <param name="id">用户的主键。</param>
33         /// <returns>返回查找到的用户实例对象。</returns>
34         public User FindUser(int id)
35         {
36             return dataList.FirstOrDefault(user => user.ID == id);
37         }
38 
39         /// <summary>
40         /// 获取所有用户的实例集合。
41         /// </summary>
42         /// <returns>返回所有的用户实例。</returns>
43         public IEnumerable<User> UserAll()
44         {
45             return dataList;
46         }
47     }
48 }


              (5)、PatrickLiu.MicroService.ServiceInstance(ASPNETCORE WEBAPI),接口服务。
            
           【1】、安装Consul服务组件,以支持Consul服务。
               
命令:Install-Package Consul
                可以在项目菜单【依赖项】菜单上点击右键,选择【管理 NuGet 程序包】来安装Consul服务。

                        【2】、HealthController.cs,主要用于Consul服务的健康检查。
                               

 1 using System;
 2 using Microsoft.AspNetCore.Mvc;
 3 using Microsoft.Extensions.Configuration;
 4 
 5 namespace PatrickLiu.MicroService.ServiceInstance.Controllers
 6 {
 7     /// <summary>
 8     /// 健康检查的控制器。
 9     /// </summary>
10     [ApiController]
11     [Route("api/[controller]")]
12     public class HealthController : ControllerBase
13     {
14         private IConfiguration _configuration;
15 
16         /// <summary>
17         /// 初始化该类型的新实例。
18         /// </summary>
19         /// <param name="configuration">配置接口。</param>
20         public HealthController(IConfiguration configuration)
21         {
22             _configuration = configuration;
23         }
24 
25         /// <summary>
26         /// 要调用的接口。
27         /// </summary>
28         [HttpGet]
29         [Route("Index")]
30         public IActionResult Index()
31         {
32             Console.WriteLine($"This is HealhController {_configuration["port"]} Invoke");
33             return Ok();
34         }
35     }
36 }


                        【3】、UsersController.cs,主要是业务类型,内容很简单。
                

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading;
  5 using Microsoft.AspNetCore.Authorization;
  6 using Microsoft.AspNetCore.Mvc;
  7 using Microsoft.Extensions.Configuration;
  8 using Microsoft.Extensions.Logging;
  9 using PatrickLiu.MicroService.Interfaces;
 10 using PatrickLiu.MicroService.Models;
 11 
 12 namespace PatrickLiu.MicroService.ServiceInstance.Controllers
 13 {
 14     /// <summary>
 15     /// 用户的 API 类型。
 16     /// </summary>
 17     [Route("api/[controller]")]
 18     [ApiController]    
 19     public class UsersController : ControllerBase
 20     {
 21         #region 私有字段
 22 
 23         private readonly ILogger<UsersController> _logger;
 24         private readonly IUserService _userService;
 25         private IConfiguration _configuration;
 26 
 27         #endregion
 28 
 29         #region 构造函数
 30 
 31         /// <summary>
 32         /// 初始化该类型的新实例。
 33         /// </summary>
 34         /// <param name="logger">日志记录器。</param>
 35         /// <param name="userService">用户服务接口。</param>
 36         /// <param name="configuration">配置服务。</param>
 37         public UsersController(ILogger<UsersController> logger, IUserService userService, IConfiguration configuration)
 38         {
 39             _logger = logger;
 40             _userService = userService;
 41             _configuration = configuration;
 42         }
 43 
 44         #endregion
 45 
 46         #region 实例方法
 47 
 48         /// <summary>
 49         /// 获取一条记录
 50         /// </summary>
 51         /// <param name="id"></param>
 52         /// <returns></returns>
 53         [HttpGet]
 54         [Route("Get")]
 55         public User Get(int id)
 56         {
 57             return _userService.FindUser(id);
 58         }
 59 
 60         /// <summary>
 61         /// 获取所有记录。
 62         /// </summary>
 63         /// <returns></returns>
 64         [HttpGet]
 65         [Route("All")]
 66         //[Authorize]
 67         public IEnumerable<User> Get()
 68         {
 69             Console.WriteLine($"This is UsersController {this._configuration["port"]} Invoke");
 70 
 71             return this._userService.UserAll().Select((user => new User
 72             {
 73                 ID = user.ID,
 74                 Name = user.Name,
 75                 Account = user.Account,
 76                 Password = user.Password,
 77                 Email = user.Email,
 78                 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
 79                 LoginTime = user.LoginTime
 80             })); ;
 81         }
 82 
 83         /// <summary>
 84         /// 超时处理
 85         /// </summary>
 86         /// <returns></returns>
 87         [HttpGet]
 88         [Route("Timeout")]
 89         public IEnumerable<User> Timeout()
 90         {
 91             Console.WriteLine($"This is Timeout Start");
 92             //超时设置。
 93             Thread.Sleep(3000);
 94 
 95             Console.WriteLine($"This is Timeout End");
 96 
 97             return this._userService.UserAll().Select((user => new User
 98             {
 99                 ID = user.ID,
100                 Name = user.Name,
101                 Account = user.Account,
102                 Password = user.Password,
103                 Email = user.Email,
104                 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
105                 LoginTime = user.LoginTime
106             })); ;
107         }
108 
109         #endregion
110     }
111 }


            【4】、增加扩展类型:ConsulExtension.cs
                

 1 using Consul;
 2 using Microsoft.Extensions.Configuration;
 3 using Microsoft.Extensions.Hosting;
 4 using System;
 5 
 6 namespace PatrickLiu.MicroService.ServiceInstance.Utilities
 7 {
 8     /// <summary>
 9     /// Consul 静态扩展类。
10     /// </summary>
11     public static class ConsulExtension
12     {
13         /// <summary>
14         ///类型初始化器,初始化 Consul 网址和数据中心。
15         /// </summary>
16         static ConsulExtension()
17         {
18             Uri = new Uri("http://localhost:8500");
19             DataCenter = "dc1";
20         }
21 
22         /// <summary>
23         /// 获取或者设置 Consul 的网址。
24         /// </summary>
25         public static Uri Uri { get; set; }
26 
27         /// <summary>
28         /// 获取或者设置数据中心。
29         /// </summary>
30         public static string DataCenter { get; set; }
31 
32         /// <summary>
33         /// 向 Consul 服务中心注册服务实例。
34         /// </summary>
35         /// <param name="configuration">配置对象。</param>
36         /// <param name="consulServiceName">在 Consul 服务中心注册的服务类别名称,多个实例的 ID 可以属于一个服务类别名称。</param>
37         /// <param name="serviceID">服务实例的主键值,必须唯一。</param>
38         public static void ConsulRegist(this IConfiguration configuration,string consulServiceName, string serviceID)
39         {
40             if (string.IsNullOrEmpty(consulServiceName) || string.IsNullOrWhiteSpace(consulServiceName))
41             {
42                 throw new ArgumentNullException("consulServiceName is null");
43             }
44             if (string.IsNullOrEmpty(serviceID) || string.IsNullOrWhiteSpace(serviceID))
45             {
46                 throw new ArgumentNullException("serviceID is null.");
47             }
48 
49             using (ConsulClient client = new ConsulClient(config =>
50             {
51                 config.Address = Uri;
52                 config.Datacenter = DataCenter;
53             }))
54             {
55                 string ip = configuration["ip"];
56                 int port = int.Parse(configuration["port"]);
57                 int weight = string.IsNullOrWhiteSpace(configuration["weight"]) ? 1 : int.Parse(configuration["weight"]);
58 
59                 client.Agent.ServiceRegister(new AgentServiceRegistration()
60                 {
61                     ID = serviceID,
62                     Name = consulServiceName,
63                     Address = ip,
64                     Port = port,
65                     Tags = new string[] { weight.ToString() },
66                     Check = new AgentServiceCheck()
67                     {
68                         Interval = TimeSpan.FromSeconds(12),
69                         HTTP = $"http://{ip}:{port}/API/Health/Index",
70                         Timeout = TimeSpan.FromSeconds(5),
71                         DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20)
72                     }
73                 }).Wait();
74                 Console.WriteLine($"注册服务:{ip}:{port}--Weight:{weight}");
75             };                       
76         }
77 
78         /// <summary>
79         /// 向 Consul 服务中心注销服务实例。
80         /// </summary>
81         /// <param name="applicationLifetime">配置对象。</param>
82         /// <param name="serviceID">服务实例的主键值,必须唯一。</param>
83         public static void ConsulDown(this IHostApplicationLifetime applicationLifetime, string serviceID)
84         {
85             if (string.IsNullOrEmpty(serviceID) || string.IsNullOrWhiteSpace(serviceID))
86             {
87                 throw new ArgumentNullException("serviceID is null");
88             }
89             applicationLifetime.ApplicationStopped.Register(() =>
90             {
91                 using (var consulClient = new ConsulClient(config => { config.Address = Uri; config.Datacenter = DataCenter; }))
92                 {
93                     Console.WriteLine("服务已经退出");
94                     consulClient.Agent.ServiceDeregister(serviceID);
95                 }
96             });
97         }
98     }
99 }


            【5】、修改 Startup.cs 代码。

                               

 1 using Consul;
 2 using Microsoft.AspNetCore.Builder;
 3 using Microsoft.AspNetCore.Hosting;
 4 using Microsoft.Extensions.Configuration;
 5 using Microsoft.Extensions.DependencyInjection;
 6 using Microsoft.Extensions.Hosting;
 7 using PatrickLiu.MicroService.Interfaces;
 8 using PatrickLiu.MicroService.ServiceInstance.Utilities;
 9 using PatrickLiu.MicroService.Services;
10 using System;
11 using System.Security.Policy;
12 
13 namespace PatrickLiu.MicroService.ServiceInstance
14 {
15     /// <summary>
16     /// 应用程序启动配置
17     /// </summary>
18     public class Startup
19     {
20         /// <summary>
21         /// 构造函数注入配置对象
22         /// </summary>
23         /// <param name="configuration">配置实例</param>
24         public Startup(IConfiguration configuration)
25         {
26             Configuration = configuration;
27         }
28 
29         /// <summary>
30         /// 获取配置实例。
31         /// </summary>
32         public IConfiguration Configuration { get; }
33 
34         /// <summary>
35         /// 配置注入对象。
36         /// </summary>
37         /// <param name="services"></param>
38         public void ConfigureServices(IServiceCollection services)
39         {
40             //其他代码省略
41             services.AddSingleton<IUserService, UserService>();
42         }
43 
44         /// <summary>
45         /// 配置 HTTP 处理管道。
46         /// </summary>
47         /// <param name="app">应用程序对象。</param>
48         /// <param name="env">环境对象。</param>
49         /// <param name="applicationLifetime">应用程序生命周期的对象。</param>
50         public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IHostApplicationLifetime applicationLifetime)
51         {
52             //其他代码省略
53             #region Consul 注册
54 
55             string serviceID = $"Service:{Configuration["ip"]}:{Configuration["port"]}---{Guid.NewGuid()}";
56             string consuleServiceName = "PatrickLiuService";
57             
58             //注册服务。
59             Configuration.ConsulRegist(consuleServiceName,serviceID);
60 
61             //注销服务
62             applicationLifetime.ConsulDown(serviceID);
63 
64             #endregion
65         }
66     }
67 }


             【6】、修改 Program.cs 代码,红色标注代表增加的代码。
                             

 1 using System.IO;
 2 using Microsoft.AspNetCore.Hosting;
 3 using Microsoft.Extensions.Configuration;
 4 using Microsoft.Extensions.Hosting;
 5 
 6 namespace PatrickLiu.MicroService.ServiceInstance
 7 {
 8     public class Program
 9     {
10         public static void Main(string[] args)
11         {
12             new ConfigurationBuilder()
13                 .SetBasePath(Directory.GetCurrentDirectory())
14                 .AddCommandLine(args)//支持命令行
15                 .Build();
16                 
17             CreateHostBuilder(args).Build().Run();
18         }
19 
20         public static IHostBuilder CreateHostBuilder(string[] args) =>
21             Host.CreateDefaultBuilder(args)
22                 .ConfigureWebHostDefaults(webBuilder =>
23                 {
24                     webBuilder.UseStartup<Startup>();
25                 });
26     }
27 }


              (6)、PatrickLiu.MicroService.Gateway(ASPNETCORE WEBAPI),网关服务。

                       

                      【1】、安装Ocelot组件包。
                              在【程序包管理器控制台】执行命令
                              命令:Install-Package Ocelot
                              
                              当然也可以在项目下的【依赖项】上点右键,点击【管理NuGet程序包】菜单,在【浏览】项先安装,输入Ocelot,在右侧安装则可以。

                      【2】、安装Ocelot.Provider.Consul组件包。
                               在【程序包管理器控制台】执行命令。
                               命令:Intall-Package Ocelot.Provider.Consul
                               
                               当然也可以在项目下的【依赖项】上点右键,点击【管理NuGet程序包】菜单,在【浏览】项先安装,输入Ocelot.Provider.Consul,在右侧安装则可以。

                      【3】、配置Startup.cs文件。
                              
                      【4】、增加JSON配置文件,文件名:configuration.json。
                                
                      【5】、修改 Program.cs 文件,使用上面增加的JSON配置文件。
                                
                      【6】、启动网关实例。
                              命令:dotnet PatrickLiu.MicroService.Gateway.dll –urls=http://*:6299 –port=6299
                              

                      【7】、验证是否启动成功。
                              网关地址:http://localhost:6299/gate/users/all,能获取到数据表示一切成功。
                              截图如下:
                                  

      4、编译项目,发布4个服务实例,独立进程承载。
               再次提醒大家,在开始启动这4个服务实例之前,必须启动Consul服务中心。

              (1)、dotnet PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5726" --ip="127.0.0.1" --port=5726
          
                                  健康检查如图:
                        

              (2)、dotnet PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5727" --ip="127.0.0.1" --port=5727
          
                                   健康检查如图:
                          

              (3)、dotnet PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5728" --ip="127.0.0.1" --port=5728
          
                                 健康检查如图:
          

              (4)、dotnet PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5729" --ip="127.0.0.1" --port=5729
          
                                   健康检查如图:
          
                                以上是我们成功启动了4个服务实例,并且在Consul 服务中心注册成功,也可以执行健康检查,功能基本完善了。让我们看看4个服务实例在Consul中心的样子吧。
                  

            注册的服务详情。

           

      5、客户端通过网关访问 Consul服务,最终访问我们服务实例。
         
              客户端我们自己实现的轮训策略,每次刷新,端口号都变,效果如图:
                  5726端口的数据:
                       
                  5727端口的数据:
                       
                  5728端口的数据:
                       
                  5729端口的数据:
                       

        6、我们的结论。
              我们解决了服务的发现和注册问题,也解决了客户端访问的问题,很不错,我们还需继续努力。实话实说,这样的架构肯定还不能在产品环境里面使用,因为有太多的问题了。当下就有一个可靠性的问题,如果这个单节点的Consul服务挂掉,怎么办?整个系统就会垮掉,我们为了增加系统的高可用性,需要对Consul组件进行升级,它需要集群来提供高可用。这就是我们下一篇文章要解决的问题,很有挑战啊。
         

五、 结束语
 
      好了,今天就写到这里了。完整高楼平地起,我们通过不断的努力,不断的解决遇到的问题,我们的知识也在剧增,眼界也就更宽广了。俗话说得好,兵来将挡水来土掩,努力吧,每天进步一点点。

posted on 2020-11-25 13:24  可均可可  阅读(1784)  评论(1编辑  收藏  举报