.Net Core 微服务学习(二): 服务治理发现(Consul)

Consul([ˈkɒnsl],康搜)是注册中心,服务提供者、服务消费者等都要注册到Consul中,这样就可以实现服务提供者、服务消费者的隔离。
除了Consul之外,还有Eureka、Zookeeper等类似软件。

COnsul主要功能如下

1.服务注册与发现

2.服务负载均衡

3.健康检查

用DNS举例来理解Consul。consul是存储服务名称与IP和端口对应关系的服务器。

假设:我有3台用于发帖的服务器,他们的IP和端口分别是

127.0.0.1:5726

127.0.0.1:5727

127.0.0.1:5728

那么这三台服务器就在Consul中注册,那么Consul就知道了这三台服务器的IP可端口了。当我们要发帖,想调用发帖服务的时候,就像Consul要,Consul会告诉我们,哪些服务器提供了发帖服务,然后我们自己选择一个发帖服务器就可以了。(是不是特别简单,这样就不需要我们记住有那些发帖服务器的IP地址和端口了)

 

Consul还提供一个健康检查的功能

假如有三台发帖的服务器都在Consul进行注册了发帖服务,假如有一台服务器挂了怎么办? 所有Consul就提供了一个服务器的健康检查功能,他会每隔一段时间向这三台服务器发送心跳包,比如每隔10秒钟就向这三台服务器请求一次,通过这样来检查这三台服务器是否还活着

 

一:Consul服务器安装与启动
https://www.consul.io/downloads.html
因为我的电脑是windows64位的,因为仅仅是测试,所有就下了一个windows版本的Consul

下载下来后,在运行中输入cmd 命令,然后在cmd中输入命令,执行cd命令切换到consul文件所在的盘符及文件夹

然后执行  consul.exe agent -dev


【这是开发环境测试,所有运行一台服务器就够了,因为开发环境无所谓稳定不稳定,但是如果是生产环境就要建集群,要至少一台Server,多台Agent】如果觉得搭建环境麻烦的话就去阿里云去买Consul服务吧,阿里云都给你配置好了,直接用就行
开发环境中consul重启后数据就会丢失。
consul的监控页面http://127.0.0.1:8500/
consult主要做三件事:提供服务到ip地址的注册;提供服务到ip地址列表的查询;对提供服务方的健康检查(HealthCheck);

二:.Net Core连接consul
在nuget管理器中执行:Install-Package Consul

三、 Rest服务的准备


1>创建一个Asp.Net Core Web应用程序(这个应用程序主要提供发送信息的服务,所有我取名叫MsgServer)

在程序中添加一个API控制器(这个控制器主要用于做服务器的健康检查,所有我取名叫HealthController)

using Microsoft.AspNetCore.Mvc;
 
namespace MsgServer.Controllers
{
    [Produces("application/json")]
    [Route("api/Health")]
 
    public class HealthController : Controller
    {
        //这个控制器主要用于对这个服务的健康检查,如果返回OK表示服务正常,没有挂掉
        [HttpGet]
        public IActionResult Get()
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "health check");
            return Content("ok");
 
        }
    }

}

  

四、 服务注册到Consul 与 服务从Consul中注销

Program.cs文件

namespace MsgServer
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }
 
        public static IWebHost BuildWebHost(string[] args)
        {
            //程序通过selfhost方式启动,可以设置这个args参数值。比如:dotnet test.dll --ip 127.0.0.1 --port 8080
            //args就会接收到ip,port这些值。如果直接以IIS Express方式启动,这里好像是接收不到args参数的
 
            var config = new ConfigurationBuilder().AddCommandLine(args).Build();
            string ip = config["ip"];
            string port = config["port"];
 
            return WebHost.CreateDefaultBuilder(args)
                   .UseStartup<Startup>()
                   //.UseUrls("http://127.0.0.1:8080") //如果要在之类指定了URL地址,那么它的优先权最高
                   .UseUrls($"http://{ip}:{port}")
                   .Build();
        }
    }
}

  Startup.cs文件

using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
 
namespace MsgServer
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
 
        public IConfiguration Configuration { get; }
 
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
 
            app.UseStaticFiles();
 
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
 
            string ip = Configuration["ip"];
            string port = Configuration["port"];
            string serviceName = "MsgService";//服务名称
            string serviceId = serviceName + Guid.NewGuid();//服务编号
 
 
            using (var consulClient = new ConsulClient(consulConfig))
            {
 
                AgentServiceRegistration ars = new AgentServiceRegistration();
                ars.Address = ip; //服务器的IP地址(必须能被调用者访问的IP地址,所有正式环境就不能用127.0.0.1)
                ars.Port = Convert.ToInt32(port); //服务器的端口号,必须能被调用者访问的的端口
                ars.Name = serviceName;//服务器名称(同一个服务,服务名称都是一致的)
                ars.ID = serviceId; //服务器的编号(如果有5个发帖服务器,那么它们的服务器编号都是唯一的)
                ars.Check = new AgentServiceCheck() //健康检查
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //发现服务器挂了后,多久时间注销掉这个服务器
                    HTTP = $"http://{ip}:{port}/api/Health",//健康检查调用的控制器地址
                    Interval = TimeSpan.FromSeconds(10),//多久多一次健康检查(心跳检查)
 
                    Timeout = TimeSpan.FromSeconds(5)
                };
                consulClient.Agent.ServiceRegister(ars).Wait();//注意:Consult客户端的所有方法几乎都是异步方法,但是都没按照规范加上Async后缀,所以容易误导。记得调用后要Wait()或者await
 
            };
 
            //服务器正常退出的时候的注册事件,这个注册事件就是从Consul注销服务(它是调用的Register方法进行事件注册的)
            //它需要通过方法参数注入IApplicationLifetime对象,从这个对象中可以知道,服务器是否退出
            appLifetime.ApplicationStopped.Register(() =>
            {
                using (var consulClient = new ConsulClient(consulConfig))
                {
                    Console.WriteLine("应用退出,开始从consul注销");
                    consulClient.Agent.ServiceDeregister(serviceId).Wait();//即注销服务编号为serviceId的服务器
                }
 
            });
            //appLifetime.ApplicationStarted.Register(() => { });//服务启动的注册事件
            //appLifetime.ApplicationStopping.Register(() => { }); //服务正在启动中的注册事件
 
        }
        private void consulConfig(ConsulClientConfiguration c)
        {
            c.Address = new Uri("http://127.0.0.1:8500"); //Consul服务的地址,Consul默认端口号就是8500
            c.Datacenter = "dc1";
        }
    }
}

 

启动项目

 

 

 此处采用 命令行启动的方式  我们只有一套代码 要启动多个实例 

命令如下

dotnet MicroService.dll --urls="http://*:5726"  --ip="127.0.0.1" --port=5726

此处指定ip 和端口 启动服务实例

 

服务的调用

1>创建一个控制台项目(获取其他项目)我取名叫ClientProject

2>在项目中安装Consul

using Consul;
using System;
 
namespace ClientProject
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var consulClient = new ConsulClient(r => r.Address = new Uri("http://127.0.0.1:8500")))
            {
                //获取到在Consul中注册的所有服务
                var services = consulClient.Agent.Services().Result.Response;
                foreach (var service in services.Values)
                {
                    //我们获取到所有的服务器后,自己决定要连接那台服务器(我们可以随机的选择一条服务器,或则采用轮询机制,或其他的方式,总之是达到负载均衡的效果)
                    Console.WriteLine($"id={service.ID},name={service.Service},ip={service.Address},port={service.Port}");
                }
                Console.ReadKey();
            }
        }
    }
}

 

posted @ 2020-03-16 09:24  Felix-Zhang  阅读(871)  评论(1编辑  收藏  举报