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

前言

.Net Core和微服务架构都出来很久了,而对于笔者而言,还只是听过没见过,更没有实操过,眼看.Net5又要来了,为了使自己不至于太out,就需要不断去学习。所以今天就来聊聊.net core和微服务的那些事儿。对于概念性的东西,本文不作记录,只希望通过代码来搭建一个简单的微服务架构。

准备工作

开发环境:VS2019+SQL Server 2017

辅助技术:.Net Core3.1、Consul、Ocelot、网关

项目初始化

首先我们需要搭建一个简单的客户端程序(Client)和服务端程序(WebApi),具体的目录如下

下面直接开始撸代码,具体的功能是我们从数据库里获取用户表的信息,然后将用户列表展示到前台的view里,首先我们看下Home/Index视图的代码,只做了一件事:

@{
    ViewData["Title"] = "Home Page";
    IEnumerable<User> users = base.ViewBag.Users as IEnumerable<User>;
}
<div class="text-center">
    <h3>用户列表</h3>
    <ul>
        @foreach (var user in users)
        {
            <li>@user.Name</li>
        }
    </ul>
</div>

再看下HomeController里做了什么事情

public IActionResult Index()
{
    string url = "http://limitcodeService/api/users/all";
    ConsulClient client = new ConsulClient(c =>
    {
        c.Address = new Uri("http://localhost:8500/");
        c.Datacenter = "dc1";
    });
    var response = client.Agent.Services().Result.Response;
    Uri uri = new Uri(url);
    string groupName = uri.Host;
    var serviceDictionary = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase));
    {
        url = $"{uri.Scheme}://{serviceDictionary.First().Value.Address}:{serviceDictionary.First().Value.Port}{uri.PathAndQuery}";//先直接拿第一个,
        //后面可以使用不同的策略来调用不同的服务实例
    }
    string content = InvokeApi(url);
    base.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
    Console.WriteLine($"这是从 {url} 接口中获取的数据");
    return View();
}

这一步其实跨度比较大,中间省略了consul的相关引用及使用(consul的具体使用不是本文的重点),这里做了下面几件事:

  1. consul客户端获取到consul服务中监听到的所有limitcodeService

  2. 通过HttpClient来实现进程间的通信

  3. 客户端从limitcodeService调用第一个正常运行的服务实例(如果第一个服务实例挂掉了,则从列表中获取下一个服务实例并调用)

  4. 将从服务中获取到的用户列表数据返回给Index视图展示

那么首先一个疑问是limitcodeService是啥玩意,它是如何注册到consul中的?下面我们来看一下WebApi项目里的相关代码(UsersController)

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    private readonly ILogger<UsersController> _logger;
    private readonly IUserService _userService = null;
    private IConfiguration _iConfiguration;
    public UsersController(ILogger<UsersController> logger, IUserService userService, IConfiguration configuration)
    {
        _logger = logger;
        this._userService = userService;
        this._iConfiguration = configuration;
    }
    [HttpGet]
    [Route("Get")]
    public User Get(int id)
    {
        return this._userService.FindOne(id);
    }
    [HttpGet]
    [Route("All")]
    public IEnumerable<User> Get()
    {
        Console.WriteLine($"这是UsersController {this._iConfiguration["port"]} 端口在运行");
        return this._userService.FindAll();
    }
}

这个就是WebApi接口里干的事情,接着就是看这个webapi如何注册到consul里。那么我需要定义一个ConsulHelper的扩展方法,然后在Startup里注册即可。

/// <summary>
///  consul辅助类
/// </summary>
public static class ConsulHelper
{
    public static void ConsulRegist(this IConfiguration configuration)
    {
        ConsulClient client = new ConsulClient(c =>
        {
            c.Address = new Uri("http://localhost:8500/");
            c.Datacenter = "dc1";
        });
        string ip = configuration["ip"];
        int port = int.Parse(configuration["port"]);//命令行参数必须传入
        client.Agent.ServiceRegister(new AgentServiceRegistration()
        {
            ID = "service" + Guid.NewGuid(),
            Name = "limitcodeService",//组名称,即我们前面看到的limitcodeService
            Address = ip,
            Port = port,//不同实例
            Check = new AgentServiceCheck()
            {
                Interval = TimeSpan.FromSeconds(12),//间隔12s一次
                HTTP = $"http://{ip}:{port}/Api/Health/Index",
                Timeout = TimeSpan.FromSeconds(5),//检测等待时间
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(60)//失败后多久移除
            }
        });
    }
}

在Startup.Configure中注册上面的扩展方法

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //....
    //注册consul服务,执行且只执行一次的
    this.Configuration.ConsulRegist();
}

到这一步,我们的客户端和服务端的程序都开发完成了,下面就来看一下如何启动.net core的项目,客户端的项目我们可以直接点IIS Express运行(跟.net framework没啥不同),而本文使用的是命令行的方式来运行,由于我们的HomeController里已经通过HttpClient来调用WebApi接口了,因此我们先运行WebApi接口(这里我们同时运行3个服务实例,分别运行在不同的端口,来模拟3个不同的服务器)。运行的命令如下:

dotnet AspNetCore.MicroService.WebApi.dll --urls="http://*:8081" --ip="127.0.0.1" --port="8081"
dotnet AspNetCore.MicroService.WebApi.dll --urls="http://*:8082" --ip="127.0.0.1" --port="8082"
dotnet AspNetCore.MicroService.WebApi.dll --urls="http://*:8083" --ip="127.0.0.1" --port="8083"

启动成功后的效果如下:

到这里,我们就发布了3个完全相同的服务,分别放在3个不同的服务器上,那么我们如何监控这些服务呢?当然是要从consul控制台里去看:

好了,我们再来运行客户端的程序,同样是通过命令行的方式:

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

我们可以看到,客户端首先是调用的是8081端口的服务,并成功获取到数据展示到前台。下面我们将做一件事,就是把8081的服务器给断掉,看看会发生什么?

我们再次刷新客户端页面,可以看到程序也挂掉了

最后在等待了大约1min的时间之后,我们再次刷新页面,可以发现客户端程序又活过来了,并且这次调用的是8083端口的服务:

小结

本文的演示就到这里,基本完成了.Net Core3.1+微服务架构的初探,当然这里面还有许多问题,离微服务架构的闭环还有很长的距离,后续将继续进一步学习探究。

作者:一蓑烟雨

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

1

支持

0

反对

posted @2020-3-22  拜读(118)

评论列表

评论内容:



喜欢请打赏

支付宝 微信

请放心支付