针对 Ocelot 网关的性能测试

匿名 (未验证) 提交于 2019-12-02 22:06:11

目前我们项目是采用的 Ocelot 作为 API 网关,并且在其基础上结合 IdentityServer4 开发了一套 API 开放平台。由于部分项目是基于 ABP 框架进行开发的,接口的平均 QPS 基本是在 2K~3K /S 左右 (E3 1231 16G)。采用 Ocelot 进行请求转发之后,前端反馈接口调用速度变慢了,也没有太过在意,以为是项目接口的问题,一直在接口上面尝试进行优化。

极限优化接口后仍然没有显著改善,故针对 Ocelot 的性能进行压力测试,得到的结果也是让我比较惊讶。

首先新建了一个解决方案,其名字为 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"   } }

测试项目的编写:

两个测试项目的监听端口分别为 60007000 ,都建立一个 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.csProgram.cs 文件内容基本一致,区别只是监听的端口分别是 60007000 而已。

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 实现机制的原因,还是我的使用方法不对。这样的性能测试结果数据确实不太好看,但也希望今后 Ocelot 能够继续努力。

如果有任何疑问也请在评论区指出。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!