• 庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现


    庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现

    一、简介
             在上一篇文章《庐山真面目之五微服务架构Consul集群、Ocelot网关和Nginx版本实现》中,我们已经探讨了如何搭建基于Consul服务集群的微服务架构。没错,那个版本也有它自己的问题,每篇文章都会解决一个问题,这样大家就会更能理解每篇文章的技术点。如果我们把所有的东西都放在一篇文章里,太多了,不利于学习和查看。看完上一篇文章后,我们知道如何解决单节点Consul服务不稳定的问题,这样问题就结束了吗?当然没有,否则就不会有今天这篇文章了。今天我们同样要解决单节点Ocelot网关的高可用的问题,这个问题和单节点Consul服务有点类似,如果我们当前这个Ocelot网关服务挂掉,系统的整个链路就会垮掉,系统的高可用性就无从谈起了。有了问题,我们就解决问题,要想高可用,那就要实现集群。Ocelot网关集群实例如何管理和发现呢?这个任务我们就交给Nginx服务。

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

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

        3、我们的目标
              今天我们的目标是,在Windows系统上实现基于Consul集群、Ocelot集群和Nginx网关服务的微服务架构,这样既可以解决单节点Ocelot网关服务的不可靠性,也可以实现针对Ocelot网关集群的负载均衡。当然这个肯定不是最终版本,我们还会继续演化下去。
               目标框架如图:
                
        

    二、搭建Consul服务的集群。
       
        
            
    在互联网的环境下,任何服务组件都很难通过单打独头,独立撑起一片天。随着分布式技术的发展和日益成熟,互联网的项目也开始进行分布式部署,或者是微服务架构部署。基于我们上一篇文章所介绍的,基于单点Consul搭建的微服务架构是有很大问题的。这种情况只是测试环境,不是真正的产品环境,如果我们想更接近产品环境,或者说,我们更接近真实环境,我们必须保证每个节点的高可用。
            Consul 用 Golang 实现,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X ),它的安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。
            在这里我们仅仅对Consul集群做简单的介绍,具体的详情可以自己去网上学习。Consul服务在Cluster集群上的每一个节点都运行一个Agent代理,这个Agent代理可以使用Server服务器或者Client客户端模式。Client客户端负责到Server服务器端的高效通信,相对为无状态的。 Server服务器端负责:包括选举领导节点,维护Cluster集群的状态,对所有的查询做出响应,跨数据中心的通信等等。
            Agent代理可以运行在Server服务器模式或者Client客户模式,每个数据中心至少有一个Agent代理运行在server服务器模式,一般建议是3或者5个Server。部署单个Server是非常不好的,因为在失败场景中出现数据丢失是不可避免的。我们今天要3个服务器端和1个客户端来完成我们今天的架构任务。

            名词解释:
            A、Client :Consul 的 Client模式,就是客户端模式。是 Consul 节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到 Server,本身不具有持久化数据的功能。
            B、Server :Consul 的 Server 模式,表明这个 Consul 是个 Server ,这种模式下,功能和 Client 都一样,唯一不同的是,它会把所有的数据持久化的本地,这样遇到故障,信息是可以被保留的。
            C、Server-Leader:是所有服务器们的老大,它和其它 Server 不一样的一点是,它需要负责同步注册的信息给其它的 Server ,同时也要负责各个节点的健康监测。
            D、Raft:Server 节点之间的数据一致性保证协议使用的是 raft,而 Zookeeper 用的 PAXOS,ETCD采用的也是Raft服务发现协议,Consul 采用 http 和 DNS 协议,ETCD 只支持 http 。
            E、服务注册:Consul 支持两种方式实现服务注册,一种是通过 Consul 的服务注册API(Http协议),由服务自己调用 API 实现注册;另一种方式是通过 JSON 格式的配置文件实现注册,将需要注册的服务以 JSON 格式的配置文件给出。Consul 官方建议使用第二种方式。

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

             我们开始在此搭建我们的Consul服务集群,以便改善单节点Consul的情况。
             1、我们开始现在Consul服务组件,存放在没有包含中文的目录里。
                   下载地址:https://www.consul.io/downloads         
                    

             2、解压文件,并存放在你指定的工作目录。
                    工作目录:D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windows
                    在这个目录下边,只有一个文件,consul.exe

                    

             3、开始启动服务实例,3个服务器端,一个客户端。
                  
    Consul其实不需要安装,这里所说的安装,指的是配置Consul地址到环境变量中,这样就可以在cmd命令框中直接执行命令了,避免切换目录。如果自己不嫌麻烦,就不用配置环境变量,我就没有配置(主要执行次数少),每次执行就直接进入目录执行Consul文件,执行命令:consul.exe,也就是Consul的文件名。

                  

              参数解释
                      consul agent命令头,必须要有。
                      -server表示要启动服务器代理(agent)模式。Consul Agent节点的运行模式有两种,Server模式和Client模式。其区别就是Server模式数据可以持久化到本地,而Client模式不可以。
                      -uiconsul运行后,会提供一个http://127.0.0.1:8500/ui/的网站,里面存储了Consul Agent各个节点以及注册的服务等相关信息,即数据中心的网页形式体现。这个参数代表是否创建这个网站,这个参数与这个数据中心网站有关。
                      -bind本机的IP地址,集群内其他代理服务器可以通过这个IP来访问这台电脑的consul代理服务器。
                      -bootstrap-expect是集群启动条件,指当服务器端模式(Server模式)的代理达到这个数目后,才开始运行。
                      -data-dir是存放数据中心数据的目录,该目录必须是稳定的,系统重启后也继续存在的。
                      -config-dir是存放数据中心日志的目录,该目录必须是稳定的,系统重启后也继续存在的。
                      -datacenter当前Consul的中心数据的名称,默认是dc1。
                      -node节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名(代表一个机器)。
                      -client本地IP地址,这里使用 0.0.0.0 ,就表示这个服务器所有IP都可以,即当这台电脑有俩IP,192.168.1.100和192.168.1.111,那么通过这俩IP都可以访问到这台机器的consul代理服务器。
                      -join表示当前的服务器节点或者是客户端节点要加入集群的服务器,后面跟要加入的服务器的具体IP地址。

                安装完成后,Agent就可以启动了,我们开始搭建我们Consul集群了。
                 (1)、创建Server-Leader,Consul集群中的领导者。
                         命令:consul agent –server -ui -bootstrap-expect=3 -data-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData -node=consul-Server1 –client=0.0.0.0 -bind=127.0.0.1 –datacenter=dc1 -config-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulDataconfig
                         配置:
                               当前路径:D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulDataconfig
                               JSON配置:
                                       
                         效果:
                               

                 (2)、创建Server- Follower,Consul集群中的第一个追随者
                         命令:consul agent –server -ui -bootstrap-expect=3 -data-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData2 -node=consul-Server2 –client=0.0.0.0 -bind=127.0.0.1 -config-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData2config –datacenter=dc1 –join 127.0.0.1:8301
                         配置:
                               当前路径:D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData2config
                               JSON配置:
                                       
                         效果:
                               
                               成功加入第一个Consul服务所创建的集群
                               

                 (3)、创建Server- Follower,Consul集群中的第二个追随者
                         命令:consul agent –server -ui -bootstrap-expect=3 -data-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData3 -node=consul-Server3 –client=0.0.0.0 -bind=127.0.0.1 -config-dir D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData3config –datacenter=dc1 –join 127.0.0.1:8301
                         配置:
                               当前路径:D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulData3config
                               JSON配置:
                                       
                         效果:
                               

                 (4)、创建Consul-Client ,Consul集群中的客户端。
                         命令:consul agent -ui –client=0.0.0.0 –bind=127.0.0.1  -data-dir=D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulClient -node=consul-Client -config-dir=D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulClientconfig –datacenter=dc1  -join 127.0.0.1:8301
                         配置:
                               当前路径:D:ProgramsMicroServicesConsulClusterconsul_1.8.4_windowsConsulClientconfig
                               JSON配置:
                                       
                         效果:
                               

             4、验证3个服务器端和一个客户端是否安装成功。
                   执行这些命令,都要切换到Consul所在的目录。切记。
                   (1)、consul members 查看Consul成员列表。
                

                 3
    个server,1个client,状态是:alive,说明集群创建成功。

             (2)、我们在看看服务器角色的分配是否合适?
                  执行命令:
    consul operator raft list-peers

                            

                   (3)、我们也可以通过浏览器访问以下地址,验证Consul服务是否安装成功。
                          第一主服务器: http://localhost:8500
                          第二从服务器: http://localhost:9500
                          第三从服务器: http://localhost:10500
                          Consul客户端: http://localhost:11500
                          能看到如下截图,也可以说明成功。我只截一个图了,其他都类似。
                          

    三、配置Nginx服务组件

              
              在这里我并不想对Nginx做更多的介绍,网上的资料太多了,我在这里只是简单说明一下,如果大家想去学习有关Nginx的知识,请去网上自行恶补了。还要说明一下,在进行这项工作之前,请确保上一步的工作配置完成,就是Consul集群的配置工作,因为在这一步里我们要配置Nginx,使用的地址信息就是Consul集群地址列表。
              Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,Nginx 1.0.4发布。
              其特点是占有内存少,并发能力强,事实上Nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用Nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

             1、下载Nginx服务组件。
                    网关下载:http://nginx.org/en/download.html
                    
                   我下载的版本号是:1.18.0,随着时间推移,你们下的版本可能不一样,但是只要是稳定版本就可以了。

             2、解压到没有包含中文字符的目录里。
                   Nginx 根目录:D:ProgramsMicroServicesConsulNginx
                   Nginx.Conf文件目录:D:ProgramsMicroServicesConsulNginxconf

             3、开始配置nginx.conf 文件,配置很简单,不多说了。
                   

             4、启动Nginx 服务。
                   
    执行命令:start nginx
                   
    如果修改文件后可以执行:nginx –s reload
                   如果想停止获或退出,可以执行:nginx –s stop|quit
                   

             5
    、检查Nginx服务是否启动成功。
                   我们可以通过访问以下地址,来验证Nginx配置是否正确。
                    http://localhost:8090,打开地址,我们看到了Consul服务界面,说明配置和启动成功。【截图的端口号有些问题,是8090,不是8080】
                    

    四、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

    五、搭建Ocelot网关集群

            在这一篇文章里,前两步骤已经完成了Consul服务集群和Nginx的配置、安装和启动的工作。要想进行这一步,当然上面的两个步骤也要成功,否则后面的代码无法测试,这个道理我想大家也很容易明白。这一步主要是涉及项目代码了,基本就没有什么开源项目的配置工作了。废话少说,我们开始吧。
        
            1、建立项目,并为项目引入 Consul包。

                  (1)、PatrickLiu.MicroService.Client(ASPNETCORE MVC),客户端项目,客户端代码,访问服务。

                           

              样例代码:

     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         private static int index;
    18 
    19         /// <summary>
    20         /// 初始化该类型的新实例。
    21         /// </summary>
    22         /// <param name="logger">注入日志对象。</param>
    23         /// <param name="userService">注入用户服务对象。</param>
    24         public HomeController(ILogger<HomeController> logger, IUserService userService)
    25         {
    26             _logger = logger;
    27             _userService = userService;
    28         }
    29 
    30         /// <summary>
    31         /// 首页。
    32         /// </summary>
    33         /// <returns></returns>
    34         public IActionResult Index()
    35         {
    36 
    37             #region 通过 Ocelot 网关访问服务实例。
    38 
    39             string url = "http://localhost:8080/gate/users/all";//Ocelot 集群的Nginx反向代理地址
    40 
    41             #endregion
    42 
    43             string content = InvokeAPI(url);
    44             this.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
    45             Console.WriteLine($"This is {url} Invoke.");
    46             
    47             #endregion
    48 
    49             return View();
    50         }
    51 
    52 
    53         /// <summary>
    54         /// 封装 HttpClient 实例,提供 Http 调用。
    55         /// </summary>
    56         /// <param name="url">http url 的地址。</param>
    57         /// <returns>返回结束数据,格式:JSON。</returns>
    58         public static string InvokeAPI(string url)
    59         {
    60             using (HttpClient client = new HttpClient())
    61             {
    62                 HttpRequestMessage message = new HttpRequestMessage();
    63                 message.Method = HttpMethod.Get;
    64                 message.RequestUri = new Uri(url);
    65                 var result = client.SendAsync(message).Result;
    66                 string conent = result.Content.ReadAsStringAsync().Result;
    67                 return conent;
    68             }
    69         }
    70     }
    71 }

                Startup.cs 的代码:
                  



                  (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),接口服务,必须引入PatrickLiu.MicroService.ServicesPatrickLiu.MicroService.ModelsPatrickLiu.MicroService.Interfaces

                           

                         1】、安装Consul服务组件,以支持Consul服务。
                  命令:Install-Package Consul              
                    可以在项目菜单【依赖项】菜单上点击右键,选择【管理 NuGet 程序包】来安装Consul服务。
                  
                           2】、HealthController.cs,主要用于Consul服务的健康检查。

                  

                         
    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 代码,红色标注代表增加的代码。 

                    

                  (6)、PatrickLiu.MicroService.Gateway(ASPNETCORE WEBAPI),这是Ocelot 网关项目。

                           

                          【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://*:6297 --port=6297
                                   

                          【7】、启动第二个网关实例。
                                  命令:dotnet PatrickLiu.MicroService.Gateway.dll --urls=http://*:6298 --port=6298
                                   

                          【8】、启动第三个网关实例。
                                  命令:dotnet PatrickLiu.MicroService.Gateway.dll --urls=http://*:6299 --port=6299
                                   

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

                    
                    刷新地址后:
                    

                                  第二网关地址:http://localhost:6298/gate/users/all,能获取到数据表示一切成功。
                                  截图如下:
                     
                    刷新地址后:
                    

                                  第三网关地址:http://localhost:6299/gate/users/all,能获取到数据表示一切成功。
                                  截图如下:
                    
                    地址刷新后:
                    

                         
                          【10】、配置Ocelot网关集群的Nginx服务。
                                   具体的下载方法,参考上面或者上文
                                   目录地址:D:ProgramsMicroServicesCulsterOcelotNginx
                                   配置信息:
                                        

               【11】、验证Ocelot网关集群的Nginx服务地址。
                                   Nginx地址:http://localhost:8080/gate/users/all,能获取到数据表示一切成功。

                                   
                  刷新地址,
                   

                   完美实现负载均衡,激动的很。注意:客户端程序要访问的地址,就是这个地址:http://localhost:8080/gate/users/all  
                                 
            2、编译项目,发布4个服务实例,独立进程承载。
                     
    再次提醒大家,在开始启动这4个服务实例之前,必须启动Consul服务中心,就是上面搭建的Consul服务集群,该Consul集群由一个Nginx代理管理。
                    (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中心的样子吧。
                        

                Nginx代理管理着由4个Consul服务组成的集群,Nginx的地址:http://localhost:8080,这个地址要配置到Ocelot网关的JSON文件里。Consul集群又管理者四个WebAPI服务实例,实现负载均衡:四个服务实例端口号分别是:5726,5727,5728,5729,地址:localhost。
                  访问效果如图:
                                 
                                 


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

                        5727端口的数据:
                             

                        5728端口的数据:
                             

                        5729端口的数据:
                             

            4、我们的结论。
                    虽然我们现在增加了Consul集群,也增加了Ocelot网关集群,每个集群也都有自己的Nginx服务实现负载均衡,系统从整体上来说,稳定性和高可用性得到了的保障,看似挺圆满的,这样就完成了吗?当然不是,还有另外一个问题等着我们去解决。这个问题就是,当前,我们所有的服务是没有任何认证的,任何人和机构都可以随便访问我们的服务,这样肯定不行的,相当于我们服务系统在互联网上裸奔啊,没有一点安全的措施。接下来,我们就要解决这个问题,这也是我们下一篇文章要解决的问题,有挑战啊。
             

    六、结束语
            
    好了,今天就写到这里了。俗话说,兵来将挡水来土掩,只要我们勇往直前,道路一定是光明的,再者说,老天不会饿死努力的小鸟的。努力吧,每天进步一点点。

  • 相关阅读:
    Hadoop 学习笔记 (十) hadoop2.2.0 生产环境部署 HDFS HA Federation 含Yarn部署
    hadoop 2.x 安装包目录结构分析
    词聚类
    Hadoop 学习笔记 (十一) MapReduce 求平均成绩
    Hadoop 学习笔记 (十) MapReduce实现排序 全局变量
    Hadoop 学习笔记 (九) hadoop2.2.0 生产环境部署 HDFS HA部署方法
    Visual Studio Code 快捷键大全(Windows)
    Eclipse安装教程 ——史上最详细安装Java &Python教程说明
    jquery操作select(取值,设置选中)
    $.ajax 中的contentType
  • 原文地址:https://www.cnblogs.com/PatrickLiu/p/14073192.html
Copyright © 2020-2023  润新知