一、背景

目前我们项目是采用的 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": "API 1 服务器IP",
"Port": 6000
},
{
"Host": "API 2 服务器IP",
"Port": 7000
}
],
"UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
],
"GlobalConfiguration": { }
}

测试项目的编写:

两个测试项目的监听端口分别为 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 实现机制的原因,还是我的使用方法不对。这样的性能测试结果数据对于 API 网关来说确实不太好看,但也希望今后 Ocelot 能够继续努力。

如果大家对于我的测试方式有疑问的话,可以在评论区指出,我将按照你所提供的方法再次进行测试。(PS: 我也不想换啊,多希望是我测错了)

五、原生 API、Ocelot、Kong API 性能比较

针对于评论区各位朋友所提出的建议,以及我最近针对 Ocelot 的再次测试,整理出来一份测试结果的表格。以下结果均是单节点进行部署,如果使用 LB + API 集群的话是可以有效提升吞吐量。

使用的网关 测试时间 并发数 总请求 QPS 超时数量 平均响应
没有使用网关 1 分钟 15000 2495541 41518.07 1592 115.98 ms
Kong API 1 分钟 15000 690141 11478.06 43997 860.31 ms
Ocelot 1 分钟 15000 277627 4618.98 1795 1.7 s
没有使用网关 1 分钟 5000 2530107 42111.44 0 115.48 ms
Kong API 1 分钟 5000 866449 14418.25 3090 383.75 ms
Ocelot 1 分钟 5000 307226 5113.09 78 932.19 ms
没有使用网关 10 分钟 8000 13080964 21797.98 103 364.97 ms
Kong API 10 分钟 8000 4809613 8014.7 305503 636.41 ms
Ocelot 10 分钟 8000 2558431 4263.34 2137 1.84 s

Ocelot 与 Kong 均部署在一台 32G 12C 3.0Ghz 的 CentOS 服务器上,API 1 与 API 2 部署在 8C 16G 3.0 Ghz 的服务器上,所有环境都是基于 Docker CE 进行部署。

另外针对于 Kong API 不知道是我使用方式不对还是什么情况,其网络吞吐量经常波动,如下图,还请不吝赐教。

网关服务器:

API 1 与 API 2 服务器:

针对 Ocelot 网关的性能测试的更多相关文章

  1. .net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试

    有感于 myzony 发布的 针对 Ocelot 网关的性能测试 ,并且公司下一步也需要对.net和java的应用做一定的整合,于是对Ocelot网关.Spring Cloud Gateway网关做个 ...

  2. 庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现

    庐山真面目之六微服务架构Consul集群.Ocelot网关集群和Nginx版本实现 一.简介      在上一篇文章<庐山真面目之五微服务架构Consul集群.Ocelot网关和Nginx版本实 ...

  3. .Net Core 商城微服务项目系列(三):Ocelot网关接入Grafana监控

    使用网关之后我们面临的一个问题就是监控,我们需要知道网关的实时状态,比如当前的请求吞吐量.请求耗费的时间.请求峰值甚至需要知道具体哪个服务的哪个方法花费了多少时间.网关作为请求的中转点是监控品牌的要塞 ...

  4. Ocelot网关+IdentityServer4实现API权限认证

    Ocelot是一个用.NET Core实现并且开源的API网关,它功能强大,包括了:路由.请求聚合.服务发现.认证.鉴权.限流熔断.并内置了负载均衡器与Service Fabric.Butterfly ...

  5. 庐山真面目之七微服务架构Consul集群、Ocelot网关集群和IdentityServer4版本实现

    庐山真面目之七微服务架构Consul集群.Ocelot网关集群和IdentityServer4版本实现 一.简介      在上一篇文章<庐山真面目之六微服务架构Consul集群.Ocelot网 ...

  6. 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介      在第七篇文章<庐山真面目之七微服务架构Consul ...

  7. 微服务之十四如何在 Ocelot 网关中配置多实例 Swagger 访问

    一.介绍 当我们开发基于微服务的应用程序的时候,有一个环节总是跳不过去的,那就是要创建 WebApi,然后,我们的应用程序基于 WebApi 接口去访问.在没有 Swagger 以前,我们开发好了 W ...

  8. 针对C#程序做性能测试的一些基本准则

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:针对C#程序做性能测试的一些基本准则.

  9. 基于.NET平台的Ocelot网关框架教程汇总

    Ocelot 框架是基于.NET 开发的 API 网关,API网关是系统内部服务暴露在外部的一个访问入口,类似于代理服务器,就像一个公司的门卫承担着寻址.限制进入.安全检查.位置引导等工作,我们可以形 ...

随机推荐

  1. kafka写入hdfs

    碰到的问题 (1)线程操作问题,因为单机节点,代码加锁就好了,后续再写 (2) 消费者写hdfs的时候以流的形式写入,但是什么时候关闭流就是一个大问题了,这里引入了   fsDataOutputStr ...

  2. Windows环境下应用Java代码操作Linux资源

    >>>>>>>>>>>>>>>>>>>>>>>>> ...

  3. 各种输出速度比较(小白应该来看看,dalao绕道)

    其实这个是修改之后测试的速度,因为之前测量方式有一点问题,经过@复杂的哈皮狗 的正确提醒后更正了一下 之前我一直以为各种输出速度比较是putchar>printf>cout; 但事实上并不 ...

  4. Game 23

    Polycarp plays "Game 23". Initially he has a number nn and his goal is to transform it to  ...

  5. MongoDb安装和快速入门

    1.Mongodb安装 2.mongodb的增删改查 3.MongoDB数据类型 4.Mongodb $关键字 $修改器 5.MongoDB 之 "$" 的奇妙用法 6.Mongo ...

  6. 网页加水印 svg 方式

    /** *网页加水印 svg 方式 * * @export * @param {*} [{ * container = document.body, * content = '请勿外传', * wid ...

  7. (BUG记录)使用迭代器安全的删除处于循环下集合中的元素

    今日在写一个功能时,需要从MQ拿取数据集合调用对端系统进行批量处理,为了幂等支持,在循环内部如果不满足调用条件就直接从集合中移除. 以上是一个典型的循环集合内删除的场景任务,工作一年第一次遇到这个场景 ...

  8. python3脚本打开摄像头

    openCamera 脚本地址:https://github.com/Mrlshadows/openCamera Mac OS 安装 OpenCV Python 环境为 python3 终端执行如下指 ...

  9. Python练手例子(9)

    49.使用lambda来创建匿名函数. #python3.7 MAXIMUM = lambda x,y : (x > y) * x + (x < y) * y MINIMUM = lamb ...

  10. gdbserver移植到DM368板子上的过程 以及segment fault problem

    问题描述 我在PC机上安装了gdbserver,但是移植到板子上后却出现了问题.运行不了,显示错误:"segment fault". 决定重新在另一台虚拟机上gdbserver. ...