Ocelot\Consul\.NetCore的微服务应用案例

案例资料链接:https://download.csdn.net/download/ly1h1/90733765

1.效果

实现两个微服务ServerAPI1和ServerAPI2的负载均衡以及高可用。具体原理,看以下示意图。

2.部署条件

 1、腾讯云的轻量化服务器

 2、WindowServer2016 

 3、.NETCore7.0

 4、Negut 包:Consul1.7.14.7、Ocelot16.0.1、Ocelot.Provider.Conusl16.0.1

 5、.NET捆绑托管 dotnet-hosting-9.0.4-win.exe

3.开放端口

 2.1 云服务安全组端口开放

  端口:5000,是服务1

  端口:5001,是服务2

  端口:5010,是Ocelot网关

  端口:8050/8030/8031/8032,是Consul的端口

  • 8500 是核心 API 端口,必知;

  • 8030/31/32 需结合具体配置,可能是用户自定义的服务或工具端口。

2.2 服务器配置入栈站规则

3.Consul配置(部署可参考链接Consul安装部署(Windows环境)-CSDN博客

{
  "datacenter": "dc1",
  "data_dir": "C:\\consul\\data",
  "node_name": "node-10-4-0-7",
  "bind_addr": "0.0.0.0",
  "advertise_addr": "10.0.4.7",(云服务内网的IP)
  "client_addr": "0.0.0.0",
  "ports": {
    "http": 8500,
    "dns": 8600,
    "grpc": -1
  },
  "ui_config": {
    "enabled": true
  },
  "server": true,
  "bootstrap": true,
  "log_level": "ERROR",
  "disable_update_check": true,
  "performance": {
    "raft_multiplier": 3,
    "leave_drain_time": "5s"
  }
}

4.Ocelot代码

4.1 Progrm.CS

using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Consul; // 引入 Consul 支持

var builder = WebApplication.CreateBuilder(args);

// 1. 配置 Kestrel 只监听 5010 端口(不绑定特定 IP)
builder.WebHost.UseUrls("http://*:5010"); // 监听所有网络接口
// 或者用 ConfigureKestrel(更灵活):
// builder.WebHost.ConfigureKestrel(serverOptions => serverOptions.ListenAnyIP(5010));

// 2. 加载 Ocelot 配置
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

// 3. 添加 Ocelot 和 Consul 支持
builder.Services
    .AddOcelot(builder.Configuration)
    .AddConsul(); // 关键:注入 Consul 提供程序

var app = builder.Build();

// 4. 使用 Ocelot 中间件
await app.UseOcelot();
app.Run();

4.2 Ocelot.JSON

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/values/{action}",
      "UpstreamPathTemplate": "/api/values/{action}",
      "ServiceName": "ServerAPI",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "ServiceDiscoveryProvider": {
        "Type": "Consul",
        "Host": "43.162.118.209",
        "Port": 8500,
        "PollingInterval": 2000, // 每2秒从Consul拉取最新健康实例
        "SkipItemsWithUnhealthyStatus": true
      }
    }
  ]
}

5.服务1代码

5.1 Program.CS

using Consul;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// 添加控制器和Swagger
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "ServerAPI1", Version = "v1" });
});

// 注册Consul客户端
builder.Services.AddSingleton<IConsulClient>(new ConsulClient(c =>
{
    c.Address = new Uri("http://192.168.0.102:8500");
}));

// 配置Kestrel(可选,根据实际需求)
builder.WebHost.UseUrls("http://*:5000");

var app = builder.Build();



// 健康检查端点
//app.MapGet("/health", () => Results.Ok("Healthy"));

// 健康检查端点(模拟5000端口故障)
//app.MapGet("/health", (HttpContext context) =>
//{
//    var port = context.Request.Host.Port;
//    return port == 5000 ? Results.StatusCode(503) : Results.Ok("Healthy (Port: " + port + ")");
//});
//app.MapGet("/health", () => Results.Ok("Healthy (Port: 5000)"));
app.MapGet("/health", () =>
{
    // 基础存活检查(不依赖任何业务逻辑)
    return Results.Ok("Alive");
});

// 注册到Consul
var consulClient = app.Services.GetRequiredService<IConsulClient>();
var registration = new AgentServiceRegistration
{
    ID = "ServerAPI-5000",
    Name = "ServerAPI",
    Address = "192.168.0.102",
    Port = 5000,
    Check = new AgentServiceCheck
    {
        HTTP = "http://192.168.0.102:5000/health",
        Interval = TimeSpan.FromSeconds(3),  // 每3秒检查一次
        Timeout = TimeSpan.FromSeconds(1),  // 1秒无响应视为失败
        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10) // 10秒后自动移除
    }
};
consulClient.Agent.ServiceRegister(registration).Wait();

// 其他中间件
app.UseRouting();
app.MapControllers();

// 配置Swagger(开发环境)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ServerAPI1 v1"));
}




// 路由和控制器
app.UseRouting();
app.MapControllers();

// 应用停止时注销服务
app.Lifetime.ApplicationStopping.Register(() =>
{
    consulClient.Agent.ServiceDeregister(registration.ID).Wait();
});

app.Run();

5.2 接口

    using Microsoft.AspNetCore.Mvc;
    using ServerAPI1.Models;

    namespace ServerAPI1.Controllers
    {
        [ApiController]
        [Route("api/[controller]")]
        [Produces("application/json")]
        public class ValuesController : ControllerBase
        {
            /// <summary>
            /// 获取服务基本信息
            /// </summary>
            [HttpGet("info")]
            [ProducesResponseType(200)]
            public IActionResult GetInfo()
            {
                return Ok(new { Service = "ServerAPI1", Port = 5000 });
            }

            /// <summary>
            /// 计算服务 (A+B)
            /// </summary>
            /// <param name="model">输入参数</param>
            [HttpPost("calculate")]
            [ProducesResponseType(200)]
            [ProducesResponseType(400)]
            public IActionResult Calculate([FromBody] TestModel model)
            {
                if (!ModelState.IsValid) return BadRequest(ModelState);
                return Ok(new { Result = 123 + 321, Input = model });
            }

            [HttpGet("getail")] // 实现 /api/values/getail
            public IActionResult Get()
            {
                return Ok("This is /api/values/getail from ServerAPI1");
            }

            [HttpGet("setail")]
            public IActionResult Gett()
            {
                return Ok("This is /api/values/setail from " + GetType().Assembly.GetName().Name);
            }
    }
    }

5.3 数据模型

using System.ComponentModel.DataAnnotations;

namespace ServerAPI1.Models
{
    public class TestModel
    {
        [Required]
        [StringLength(100)]
        public string AAA { get; set; }

        [StringLength(200)]
        public string BBB { get; set; }
    }
}

6.服务2代码

6.1 Program.CS

using Consul;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// 添加控制器和Swagger
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "ServerAPI2", Version = "v1" });
});

// 注册Consul客户端
builder.Services.AddSingleton<IConsulClient>(new ConsulClient(c =>
{
    c.Address = new Uri("http://192.168.0.102:8500");
}));

// 配置Kestrel(可选,根据实际需求)
builder.WebHost.UseUrls("http://*:5001");

var app = builder.Build();



// 健康检查端点
//app.MapGet("/health", () => Results.Ok("Healthy"));

// 健康检查端点(模拟5000端口故障)
//app.MapGet("/health", (HttpContext context) =>
//{
//    var port = context.Request.Host.Port;
//    return port == 5000 ? Results.StatusCode(503) : Results.Ok("Healthy (Port: " + port + ")");
//});
//app.MapGet("/health", () => Results.Ok("Healthy (Port: 5001)"));
app.MapGet("/health", () =>
{
    // 基础存活检查(不依赖任何业务逻辑)
    return Results.Ok("Alive");
});


// 注册到Consul
var consulClient = app.Services.GetRequiredService<IConsulClient>();
var registration = new AgentServiceRegistration
{
    ID = "ServerAPI-5001",
    Name = "ServerAPI",
    Address = "192.168.0.102",
    Port = 5001,
    Check = new AgentServiceCheck
    {
        HTTP = "http://192.168.0.102:5001/health",
        Interval = TimeSpan.FromSeconds(3),  // 每3秒检查一次
        Timeout = TimeSpan.FromSeconds(1),  // 1秒无响应视为失败
        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10) // 10秒后自动移除
    }
};
consulClient.Agent.ServiceRegister(registration).Wait();
// 其他中间件
app.UseRouting();
app.MapControllers();


// 配置Swagger(开发环境)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ServerAPI2 v1"));
}

 健康检查端点
//app.MapGet("/health", () => Results.Ok("Healthy"));

// 路由和控制器
app.UseRouting();
app.MapControllers();

// 应用停止时注销服务
app.Lifetime.ApplicationStopping.Register(() =>
{
    consulClient.Agent.ServiceDeregister(registration.ID).Wait();
});

app.Run();

6.2 接口

using Microsoft.AspNetCore.Mvc;
using ServerAPI2.Models;

namespace ServerAPI2.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    [Produces("application/json")]
    public class ValuesController : ControllerBase
    {
        /// <summary>
        /// 获取服务元数据
        /// </summary>
        [HttpGet("info")]
        [ProducesResponseType(200)]
        public IActionResult GetInfo()
        {
            return Ok(new { Service = "ServerAPI2", Port = 8016 });
        }

        /// <summary>
        /// 字符串转换服务
        /// </summary>
        /// <param name="model">输入参数</param>
        [HttpPost("calculate")]
        [ProducesResponseType(200)]
        [ProducesResponseType(400)]
        public IActionResult Transform([FromBody] TestModel model)
        {
            if (!ModelState.IsValid) return BadRequest(ModelState);
            return Ok(new { Result = $"{model.AAA}-{model.BBB}".ToUpper() });
        }


        [HttpGet("getail")] // 实现 /api/values/getail
        public IActionResult Get()
        {
            return Ok("This is /api/values/getail from ServerAPI2");
        }
        [HttpGet("setail")]
        public IActionResult Gett()
        {
            return Ok("This is /api/values/setail from " + GetType().Assembly.GetName().Name);
        }
    }
}

6.3 数据模型

    using System.ComponentModel.DataAnnotations;

    namespace ServerAPI2.Models
    {
        public class TestModel
        {
            [Required]
            [StringLength(100)]
            public string AAA { get; set; }

            [StringLength(200)]
            public string BBB { get; set; }
        }
    }

7.发布形成Publish文件包

7.发布文件效果

8.运行Consul

8.1 显示双击文件夹内的Consul.exe

8.2 cmd进入Consul文件夹,运行指令:consul agent --config-file=C:\consul\config.json

9.运行服务

8.Publish文件夹内的Server1.exe\Server2.exe\OcelotDemo.exe,运行2个业务服务和网关服务

10.效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值