一, 背景
目前我们项目是采用的 Ocelot 作为 API 网关, 并且在其基础上结合 IdentityServer4 开发了一套 API 开放平台. 由于部分项目是基于 ABP 框架进行开发的, 接口的平均 QPS 基本是在 2K~3K /S 左右 (E3 1231 16G). 采用 Ocelot 进行请求转发之后, 前端反馈接口调用速度变慢了, 也没有太过在意, 以为是项目接口的问题, 一直在接口上面尝试进行优化.
极限优化接口后仍然没有显著改善, 故针对 Ocelot 的性能进行压力测试, 得到的结果也是让我比较惊讶.
二, 准备工作
2.1 测试项目准备
首先新建了一个解决方案, 其名字为 OcelotStudy , 其下面有三个项目, 分别是两个 API 项目和一个网关项目.
网关项目编写:
为 OcelotStudy 项目引入 Ocelot 的 NuGet 包.
在 OcelotStudy 项目的 Program.cs 文件当中显式指定我们网关的监听端口.
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- namespace OcelotStudy
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigurewebHostDefaults(webBuilder =>
- {
- // 指定监听端口为 5000
- webBuilder.UseStartup<Startup>()
- .UseKestrel(x=>x.ListenAnyIP(5000));
- });
- }
- }
在 Startup.cs 类当中注入 Ocelot 的服务, 并应用 Ocelot 的中间件.
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using Ocelot.DependencyInjection;
- using Ocelot.Middleware;
- namespace OcelotStudy
- {
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- // 禁用日志的控制台输出, 防止由于线程同步造成的性能损失
- services.AddLogging(op => op.ClearProviders());
- services.AddMvc();
- services.AddOcelot(new ConfigurationBuilder().AddJsonFile("Ocelot.json").Build());
- }
- public async void Configure(IApplicationBuilder App, IHostingEnvironment env)
- {
- await App.UseOcelot();
- App.UseMvc();
- }
- }
- }
在 OcelotStudy 项目下建立 Ocelot.JSON 文件, 内容如下.
- {
- "ReRoutes": [
- {
- "DownstreamPathTemplate": "/api/{everything}",
- "DownstreamScheme": "http",
- "DownstreamHostAndPorts": [
- {
- "Host": "localhost",
- "Port": 6000
- },
- {
- "Host": "localhost",
- "Port": 7000
- }
- ],
- "UpstreamPathTemplate": "/{everything}",
- "UpstreamHttpMethod": [ "Get", "Post" ],
- "LoadBalancerOptions": {
- "Type": "RoundRobin"
- }
- }
- ],
- "GlobalConfiguration": {
- // "BaseUrl": "https://api.yilezhu.cn"
- }
- }
测试项目的编写:
两个测试项目的监听端口分别为 6000 与 7000 , 都建立一个 ValuesController 控制器, 返回一个字符串用于输出当前请求的 API 服务器信息.
ApiService01 的文件信息:
- using Microsoft.AspNetCore.Mvc;
- namespace ApiService01.Controllers
- {
- [Route("api/[controller]")]
- [ApiController]
- public class ValuesController : ControllerBase
- {
- // GET API/values
- [HttpGet]
- public ActionResult<string> Get()
- {
- return "当前请求的 API 接口是 1 号服务器.";
- }
- // GET API/values/5
- [HttpGet("{id}")]
- public ActionResult<string> Get(int id)
- {
- return "value";
- }
- // POST API/values
- [HttpPost]
- public void Post([FromBody] string value)
- {
- }
- // PUT API/values/5
- [HttpPut("{id}")]
- public void Put(int id, [FromBody] string value)
- {
- }
- // DELETE API/values/5
- [HttpDelete("{id}")]
- public void Delete(int id)
- {
- }
- }
- }
ApiService02 的文件信息:
- using Microsoft.AspNetCore.Mvc;
- namespace ApiService02.Controllers
- {
- [Route("api/[controller]")]
- [ApiController]
- public class ValuesController : ControllerBase
- {
- // GET API/values
- [HttpGet]
- public ActionResult<string> Get()
- {
- return "当前请求的 API 接口是 2 号服务器.";
- }
- // GET API/values/5
- [HttpGet("{id}")]
- public ActionResult<string> Get(int id)
- {
- return "value";
- }
- // POST API/values
- [HttpPost]
- public void Post([FromBody] string value)
- {
- }
- // PUT API/values/5
- [HttpPut("{id}")]
- public void Put(int id, [FromBody] string value)
- {
- }
- // DELETE API/values/5
- [HttpDelete("{id}")]
- public void Delete(int id)
- {
- }
- }
- }
他们两个的 Startup.cs 与 Program.cs 文件内容基本一致, 区别只是监听的端口分别是 6000 和 7000 而已.
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- namespace ApiService02
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- webBuilder.UseKestrel(x => x.ListenAnyIP(6000)); // 或者 7000
- });
- }
- }
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- namespace ApiService02
- {
- 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.AddLogging(op => op.ClearProviders());
- 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)
- {
- App.UseRouting(routes => { routes.MapApplication(); });
- }
- }
- }
以上三个项目都采用 Release 版本进行发布.
dotnet publish -c Release
ApiService01 部署在单独的 E3 1231 v3 16G DDR3 服务器.
ApiService02 部署在单独的 i3-7100 16G DDR4 服务器.
OcelotStudy 部署在单独的 E3 1231 v3 16G DDR3 服务器.
三, 开始测试
这里我使用的是 WRK 来进行压力测试, OcelotStudy 网关项目的 IP 地址为 172.31.61.41:5000 , 故使用以下命令进行测试.
./wrk -t 10 -c 10000 -d 20s --latency --timeout 3s "http://172.31.61.41:5000/values"
测试结果:
我将 ApiService01 项目放在网关的服务器, 直接调用 ApiService01 的接口, 其压力测试情况.
四, 结语
最后 Ocelot 的 QPS 结果为: 3461.53
直接请求 API 接口的 QPS 结果为: 38874.50
这样的结果让我感到很意外, 不知道是由于 Ocelot 实现机制的原因, 还是我的使用方法不对. 这样的性能测试结果数据对于 API 网关来说确实不太好看, 但也希望今后 Ocelot 能够继续努力.
如果大家对于我的测试方式有疑问的话, 可以在评论区指出, 我将按照你所提供的方法再次进行测试.(PS: 我也不想换啊, 多希望是我测错了)
来源: https://www.cnblogs.com/myzony/p/10401298.html