Nginx+.Net Core Api 负载均衡(一)

Nginx 是一款高性能的 HTTP 服务器和反向代理软件,主要功能:反向代理负载均衡静态处理SSL缓存、高并发、模块化、热部署等

核心功能概念

  • 与正向代理的区别
    • 正向代理:代表客户端向外部服务器发送请求(如VPN),隐藏客户端身份。
    • 反向代理:代表后端服务器接收客户端请求,隐藏服务器身份,提升安全性与可扩展性。
  • 工作原理
    1. 客户端向Nginx发送请求(如访问example.com)。
    2. Nginx根据配置结合 负载均衡策略(轮询、加权轮询、IP 哈希、最少连接数),将请求转发至后端服务器(如IIS、Tomcat等)。可优化资源分配,提升服务可用性和容错能力。
    3. 后端服务器处理请求后,返回响应给Nginx
    4. Nginx将响应传递给客户端,客户端无需感知后端服务器的存在。

实现

代码修改

我们想法是建立不同的程序实例,用不同的端口号去发布。如果我们想看访问Nginx最终走的哪个实例,我们可以把接收请求实例的端口号在请求的返回结果中展示就很清晰了。我们对代码进行改造

新增属性

    public class WeatherForecast
    {
        public DateOnly Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string? Summary { get; set; }
        /// <summary>
        /// 新增端口号
        /// </summary>
        public int Port { get; set; }
    }

接口返回

 [HttpGet(Name = "GetWeatherForecast")]
 public IEnumerable<WeatherForecast> Get()
 {
     //获取请求触发的程序实例的端口号
     var port = HttpContext.Connection.LocalPort;
     return Enumerable.Range(1, 5).Select(index => new WeatherForecast
     {
         Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
         TemperatureC = Random.Shared.Next(-20, 55),
         Summary = Summaries[Random.Shared.Next(Summaries.Length)],
         Port = port //结果返回
     })
     .ToArray();
 }

环境准备

创建一个ASP.NET Core Web API程序,命名为WebApiDemo,基础框架选择.NET 8(自带swagger),我们准备WebApiDemo两个实例去实现负载均衡。有两种方式:

  1. 命令行发布

    cmd进入项目的目录执行对应的dotnet run启动一个实例,然后进入【Properties】文件夹里的launchSettings.json去修改发布的端口,这里选的是http将5222改成5223,然后再次通过dotnet run再启动一个实例

    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5223",//原端口为5222
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
    
  2. IIS发布

    1. 直接将WebApiDemo发布到文件夹,注意发布的时候注意【目标运行时(U)】(现在一般电脑为win-x64)、【部署模式(M)】(如果没装运行时选择独立)。

    2. 进入打包文件下的web.config用以下内容替换aspNetCore标签内容。

      <aspNetCore processPath=".\WebApiDemo.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
      			<environmentVariables>
                        <environmentVariable name="ASPNETCORE_ENVIRONMENT"                      value="Development" />
      			</environmentVariables>
      </aspNetCore>
      
    3. 将打包文件夹复制成两份分别为WebApiDemo1WebApiDemo2,进入IIS新建两个对应的资源池(注意资源池【.NET CLR 版本(C)】选择无托管代码

    4. 创建两个站点,各自选择对应的资源池及打包文件夹,注意区分端口号,我这里选择的是88、89两个端口

Nginx配置

下载Nginx

地址:Download,这里选择带Windows的版本,解压

这里以IIS发布的版本为例(端口88、89),进入到Nginx的文件夹--conf--nginx.conf

定义后端服务器集群dotnet_servers,在location里配置proxy_pass指定dotnet_servers,修改nginx对外暴露的端口listen80改为86

http {
    #其他配置忽略
    # 定义后端服务器集群(默认轮询策略)
    upstream dotnet_servers {
        server 127.0.0.1:88;
        server 127.0.0.1:89;
    }
    server {  
		#服务端的监听端口,对外暴露的端口,默认是80,因为被其他应用占用改为86		
        listen       86;
		#监听地址		
        server_name  localhost;

		#项目本地部署的端口
        location / {
			//dotnet_servers在这里应用
            proxy_pass http://dotnet_servers;
            root   html;
            index  index.html index.htm;
        }
   
}

展示验证

执行nginx.exe(注意修改配置文件后,要在任务管理器-详细找到对应nginx.exe后结束任务)

访问http://127.0.0.1:86/WeatherForecast

结果:

[{"date":"2025-05-01","temperatureC":49,"temperatureF":120,"summary":"Cool","port":89},{"date":"2025-05-02","temperatureC":40,"temperatureF":103,"summary":"Sweltering","port":89},{"date":"2025-05-03","temperatureC":33,"temperatureF":91,"summary":"Cool","port":89},{"date":"2025-05-04","temperatureC":45,"temperatureF":112,"summary":"Scorching","port":89},{"date":"2025-05-05","temperatureC":-4,"temperatureF":25,"summary":"Hot","port":89}]

[{"date":"2025-05-01","temperatureC":6,"temperatureF":42,"summary":"Balmy","port":88},{"date":"2025-05-02","temperatureC":-17,"temperatureF":2,"summary":"Freezing","port":88},{"date":"2025-05-03","temperatureC":10,"temperatureF":49,"summary":"Chilly","port":88},{"date":"2025-05-04","temperatureC":-13,"temperatureF":9,"summary":"Scorching","port":88},{"date":"2025-05-05","temperatureC":14,"temperatureF":57,"summary":"Freezing","port":88}]

可以看到端口号Port的变化

默认采用轮询的方式,我们也可以设置权重比例,weight值越大,请求到达此实例的次数就越多!

 upstream dotnet_servers {
        server 127.0.0.1:88 weight=1;
        server 127.0.0.1:89 weight=3;
    }