夫天地者,万物之逆旅;光阴者,百代之过客。而浮生若梦,为欢几何?
.NetCore3.1+微服务架构实操(中)

前言

前面我们已经基本搭建了一个简单的分布式系统集群,同时通过consul来注册服务和发现服务(consul的功能:服务注册与发现;心跳检查等),从而让客户端能够调用不同的服务实例。我们再通过下面一张简图来回顾一下前面已经做的事情:

从上面这个图里可以发现,client其实最终还是调用具体的service,也就是说服务实例是暴露的,consul并不负责调用服务。同时调用服务的策略是始终获取第一个服务实例,当第一个服务实例挂掉后,中间需要有一定的等待时间,才会自动切换到下一个运行的服务实例。下面我们首先来看下consul中服务的其它策略。

权重策略

调用服务的策略主要有:负载均衡策略、轮询策略和权重策略等,这里以配置权重为例。至于权重我们选择在启动服务的时候,通过命令行参数传入。因此我们需要修改一下之前的ConsulHelper中的扩展方法,修改后的代码如下:

public static void ConsulRegist(this IConfiguration configuration)
{
    //....
    int weight = string.IsNullOrWhiteSpace(configuration["weight"]) ? 1 : int.Parse(configuration["weight"]);
    client.Agent.ServiceRegister(new AgentServiceRegistration()
    {
        //...
        Tags = new string[] { weight.ToString() },//接收配置的权重
        Check = new AgentServiceCheck()
        {
           //....
        }
    });
    //命令行参数获取
    Console.WriteLine($"{ip}:{port}--weight:{weight}");
}

然后我们需要修改HomeController里具体调用的地方:

public IActionResult Index()
{
    //....
    AgentService agentService = null;
    //根据配置的权重来执行调用具体的服务实例
    List<KeyValuePair<string, AgentService>> pairsList = new List<KeyValuePair<string, AgentService>>();
    foreach (var item in serviceDictionary)
    {
        int count = Convert.ToInt32(item.Value.Tags?[0]);
        for (int i = 0; i < count; i++)
        {
            pairsList.Add(item);
        }
    }
    agentService = pairsList.ToArray()[new Random(iSeed++).Next(0, pairsList.Count)].Value;
    url= $"{uri.Scheme}://{agentService.Address}:{agentService.Port}{uri.PathAndQuery}";
    string content = InvokeApi(url);
    base.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
    Console.WriteLine($"这是从 {url} 接口中获取的数据");
    return View();
}

到这里我们重新运行客户端和服务端程序,并不断刷新客户端页面,可以看到3个服务被调用的次数比较(权重配置:8081→1,8082→3,8083→6):

网关(Gateway)

前面我们使用consul后发现,客户端还是需要直接去访问服务实例,服务实例需要被暴露,这时可以使用网关来保护这些服务实例,客户端只需要调用网关,然后由网关进行路由转发及一系列其他的功能(网关的重要性可自行查阅相关资料,本文的目的是如何实现在客户端和consul之间加一层网关)。

可想而知,网关在我们的项目里也是一个独立的进程,因此我们需要再新增一个Cateway的项目,具体如下:

在这个项目里我们主要的工作是配置,在这之前需要先通过nuget添加引用下面这个dll文件

然后新建一个configuration.json的文件,这里用于具体的配置。由于在.Net Core项目里会默认加载自带的appsetting.json的文件,因此我们需要在Program.CreateHostBuilder中修改一下配置,让程序自动加载configuration.json文件:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(conf =>
        {
            conf.AddJsonFile("configuration.json", optional: false, reloadOnChange: true);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

到这里,我们还需要在Startup.cs中修改两处配置,让程序使用Ocelot的管道处理请求:

public void ConfigureServices(IServiceCollection services)
{
    //services.AddControllers();
    services.AddOcelot();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    
    app.UseOcelot();//去掉默认管道,使用Ocelot管道处理请求
}

还需要一步配置文件:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8081 //服务端口
      ],
      "UpstreamPathTemplate": "/T8081/{url}", //网关地址--url变量   //冲突的还可以加权重Priority
      "UpstreamHttpMethod": [ "Get", "Post" ]
    },
    //...其它两个端口类似上面配置
  ]
}

现在我们可以编译并运行当前这个Gateway的项目了(另3个WebApi服务默认已经运行):

dotnet AspNetCore.MicroService.Gateway.dll --urls="http://*:6299" --ip="127.0.0.1" --port="6299"

最后运行的结果如下:

Ocelot与Consul的结合

网关已经实现了一个功能就是:client请求网关,网关进行路由转发请求具体的服务实例。接下来我们来结合Ocelot与Consul来实现,网关转发请求具体的服务实例时,由Consul去发现具体的可用的服务实例,并指定调用服务的策略。具体的做法如下:

首先在Gateway项目需要再引入下面这个dll文件:

然后再修改Startup中的方法,注册consul服务:

public void ConfigureServices(IServiceCollection services)
{
    //services.AddControllers();
    services.AddOcelot().AddConsul();
}

最后就是修改配置文件

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
      "DownstreamScheme": "http",
      "ServiceName": "limitcodeService", //consul服务名称
      "UseServiceDiscovery": true,
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询策略 其它策略:LeastConnection-最少连接数的服务器 NoLoadBalance不负载均衡
      },
      "UpstreamPathTemplate": "/dp/{url}", //网关地址--url变量
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://127.0.0.1:99", //网关对外地址
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul" //由Consul提供服务发现
    }
  }
}

到这里我们重新编译运行Gateway的项目,然后客户端就可以直接请求网关,通过不断刷新页面可以发现3个服务实例基本是被均衡调用,结果如下

小结

到这里,我们同时离微服务架构又近了一大步,赶紧喝一口82年的雪碧压压惊~~,下面仍是通过一张简图来总结一下本文实现的功能。

作者:一蓑烟雨

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

0

支持

0

反对

posted @2020-3-23  拜读(81)

评论列表

评论内容:



喜欢请打赏

支付宝 微信

请放心支付