ASP.NET Core vs Go: Hiệu suất HTTP của ai tốt hơn
Trong bài viết này, chúng tôi sẽ so sánh hiệu suất HTTP của ASP.NET Core và Go. Để đạt được sự so sánh công bằng, chúng tôi sẽ sử dụng mô hình kiến trúc MVC trên cả ASP.NET Core và Go.
Điều kiện tiên quyết
Go (hay Golang): là một ngôn ngữ lập trình mã nguồn mở đang phát triển nhanh chóng được thiết kế để xây dựng phần mềm đơn giản, nhanh chóng và đáng tin cậy.
Không có nhiều web framework cho Go có hỗ trợ MVC nhưng may mắn cho chúng tôi là Iris đã làm được công việc đó.
Iris: Một micro web framework nhanh chóng, đơn giản và hiệu quả cho Go. Nó cung cấp một nền tảng tuyệt vời và dễ sử dụng cho trang web, API hoặc ứng dụng được phân phối tiếp theo của bạn.
C#: là một ngôn ngữ lập trình hướng đối tượng, đa mục đích chung. Nhóm phát triển của nó được dẫn dắt bởi Anders Hejlsberg.
.NET Core: Phát triển các ứng dụng hiệu suất cao trong thời gian ngắn hơn, trên mọi nền tảng.
Tải xuống Go từ https://golang.org/dl và .NET Core từ https://www.microsoft.com/net/core.
Sau khi bạn tải xuống và cài đặt chúng, bạn sẽ cần cài đặt Iris cho Go. Cài đặt rất dễ dàng, chỉ cần mở thiết bị đầu cuối (cửa sổ dòng lệnh) của bạn và gõ lệnh:
go get -u github.com/kataras/iris
Benchmark
Hardware
- Processor: Intel(R) Core(TM) i7–4710HQ CPU @ 2.50GHz 2.50GHz
- RAM: 8.00 GB
Software
- OS: Microsoft Windows [Version 10.0.15063], power plan is “High performance”
- HTTP Benchmark Tool: https://github.com/codesenberg/bombardier, version 1.1
- .NET Core: https://www.microsoft.com/net/core, version 2.0
- Iris: https://github.com/kataras/iris, version 8.3 built with go 1.8.3
Tiêu chí đánh giá
- Thời gian để hoàn thành
5.000.000 request
– càng nhỏ càng tốt. - Số lượng request / giây – càng lớn càng tốt.
- Độ trễ – càng nhỏ càng tốt.
- Thông lượng – càng lớn càng tốt.
Benchmark cho API
Cả hai ứng dụng ASP.NET Core và Go sẽ chỉ trả về dữ liệu dạng text khi gọi vào API url “api/values/{id}”.
ASP.NET Core Web API
Được tạo bằng cách sử dụng lệnh dotnet new webapi
. Mẫu webapi
sẽ tạo mã API sẵn cho bạn.
Mã nguồn của API như sau:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace netcore_mvc
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace netcore_mvc
{
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.AddMvcCore();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace netcore_mvc.Controllers
{
// ValuesController is the equivalent
// `ValuesController` of the Iris 8.3 mvc application.
[Route("api/[controller]")]
public class ValuesController : Controller
{
// Get handles "GET" requests to "api/values/{id}".
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// Put handles "PUT" requests to "api/values/{id}".
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// Delete handles "DELETE" requests to "api/values/{id}".
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
Chạy ASP.NET Core web server:
$ cd netcore-mvc
$ dotnet run -c Release
Hosting environment: Production
Content root path: C:mygopathsrcgithub.comkatarasiris_benchmarksnetcore-mvc
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
Kết quả benchmark:
$ bombardier -c 125 -n 5000000 http://localhost:5000/api/values/5
Bombarding http://localhost:5000/api/values/5 with 5000000 requests using 125 connections
5000000 / 5000000 [=====================================================] 100.00% 2m3s
Done!
Statistics Avg Stdev Max
Reqs/sec 40226.03 8724.30 161919
Latency 3.09ms 1.40ms 169.12ms
HTTP codes:
1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 8.91MB/s
Go với Iris MVC
Mã nguồn của API như sau:
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/_benchmarks/iris-mvc/controllers"
)
func main() {
app := iris.New()
app.Controller("/api/values/{id}", new(controllers.ValuesController))
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
}
package controllers
import "github.com/kataras/iris/mvc"
// ValuesController is the equivalent
// `ValuesController` of the .net core 2.0 mvc application.
type ValuesController struct {
mvc.Controller
}
// Get handles "GET" requests to "api/values/{id}".
func (vc *ValuesController) Get() {
// id,_ := vc.Params.GetInt("id")
vc.Ctx.WriteString("value")
}
// Put handles "PUT" requests to "api/values/{id}".
func (vc *ValuesController) Put() {}
// Delete handles "DELETE" requests to "api/values/{id}".
func (vc *ValuesController) Delete() {}
Chạy Go web server:
$ cd iris-mvc
$ go run main.go
Now listening on: http://localhost:5000
Application started. Press CTRL+C to shut down.
Kết quả benchmark:
$ bombardier -c 125 -n 5000000 http://localhost:5000/api/values/5
Bombarding http://localhost:5000/api/values/5 with 5000000 requests using 125 connections
5000000 / 5000000 [======================================================] 100.00% 47s
Done!
Statistics Avg Stdev Max
Reqs/sec 105643.81 7687.79 122564
Latency 1.18ms 366.55us 22.01ms
HTTP codes:
1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 19.65MB/s
Kết quả benchmark
ASP.NET Core Web API:
- Chạy trong 2 phút 3 giây.
- Xử lý 40.226,03 yêu cầu mỗi giây.
- Độ trễ trung bình là 3,09ms và độ trễ tối đa là 169,12ms.
- Thông lượng là 8,91 MB/s.
Go với Iris MVC:
- Chạy trong cho 47 giây.
- Phục vụ 105.643,81 yêu cầu mỗi giây.
- Độ trễ trung bình là 1,18ms và độ trễ tối đa là 22,01ms.
- Thông lượng là 19,65 MB/s.
Benchmark cho Web MVC
Trong phần này chúng ta sẽ tiến hành benchmark cho web MVC.
ASP.NET Core MVC
Mã nguồn của Web MVC như sau:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace netcore_mvc_templates
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace netcore_mvc_templates
{
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.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.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using netcore_mvc_templates.Models;
namespace netcore_mvc_templates.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View(new ErrorViewModel { Title = "Error", Code = 500});
}
}
}
using System;
namespace netcore_mvc_templates.Models
{
public class ErrorViewModel
{
public string Title { get; set; }
public int Code { get; set; }
}
}
Chạy ASP.NET Core web server:
$ cd netcore-mvc-templates
$ dotnet run -c Release
Hosting environment: Production
Content root path: C:mygopathsrcgithub.comkatarasiris_benchmarksnetcore-mvc-templates
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
Kết quả benchmark:
$ bombardier -c 125 -n 1000000 http://localhost:5000/home/error
Bombarding http://localhost:5000 with 1000000 requests using 125 connections
1000000 / 1000000 [====================================================] 100.00% 1m20s
Done!
Statistics Avg Stdev Max
Reqs/sec 11738.60 7741.36 125887
Latency 10.10ms 22.10ms 1.97s
HTTP codes:
1xx — 0, 2xx — 1000000, 3xx — 0, 4xx — 0, 5xx — 0
others — 0
Throughput: 89.03MB/s
Go với Iris MVC
Mã nguồn của Web MVC như sau:
package controllers
import "github.com/kataras/iris/mvc"
type AboutController struct{ mvc.Controller }
func (c *AboutController) Get() {
c.Data["Title"] = "About"
c.Data["Message"] = "Your application description page."
c.Tmpl = "about.html"
}
package controllers
import "github.com/kataras/iris/mvc"
type ContactController struct{ mvc.Controller }
func (c *ContactController) Get() {
c.Data["Title"] = "Contact"
c.Data["Message"] = "Your contact page."
c.Tmpl = "contact.html"
}
package models
// HTTPError a silly structure to keep our error page data.
type HTTPError struct {
Title string
Code int
}
package controllers
import "github.com/kataras/iris/mvc"
type IndexController struct{ mvc.Controller }
func (c *IndexController) Get() {
c.Data["Title"] = "Home Page"
c.Tmpl = "index.html"
}
package main
import (
"github.com/kataras/iris/_benchmarks/iris-mvc-templates/controllers"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
const (
// templatesDir is the exactly the same path that .NET Core is using for its templates,
// in order to reduce the size in the repository.
// Change the "C\mygopath" to your own GOPATH.
templatesDir = "C:\mygopath\src\github.com\kataras\iris\_benchmarks\netcore-mvc-templates\wwwroot"
)
func main() {
app := iris.New()
app.Configure(configure)
app.Controller("/", new(controllers.IndexController))
app.Controller("/about", new(controllers.AboutController))
app.Controller("/contact", new(controllers.ContactController))
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
}
func configure(app *iris.Application) {
app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html"))
app.StaticWeb("/public", templatesDir)
app.OnAnyErrorCode(onError)
}
type err struct {
Title string
Code int
}
func onError(ctx context.Context) {
ctx.ViewData("", err{"Error", ctx.GetStatusCode()})
ctx.View("shared/error.html")
}
Chạy ASP.NET Core web server:
$ cd iris-mvc-templates
$ go run main.go
Now listening on: http://localhost:5000
Application started. Press CTRL+C to shut down.
Kết quả benchmark:
$ bombardier -c 125 -n 1000000 http://localhost:5000/home/error
Bombarding http://localhost:5000 with 1000000 requests using 125 connections
1000000 / 1000000 [======================================================] 100.00% 37s
Done!
Statistics Avg Stdev Max
Reqs/sec 26656.76 1944.73 31188
Latency 4.69ms 1.20ms 22.52ms
HTTP codes:
1xx — 0, 2xx — 1000000, 3xx — 0, 4xx — 0, 5xx — 0
others — 0
Throughput: 192.51MB/s
Kết quả benchmark
ASP.NET Core MVC:
- Chạy trong 1 phút 20 giây.
- Xử lý 11.738,60 yêu cầu mỗi giây.
- Độ trễ trung bình là 10,10ms và độ trễ tối đa là 1,97s.
- Thông lượng là 89,03 MB/s.
Go với Iris MVC:
- Chạy trong cho 37 giây.
- Phục vụ 26.656,76 yêu cầu mỗi giây.
- Độ trễ trung bình là 4,69ms và độ trễ tối đa là 22,52ms.
- Thông lượng là 192,51 MB/s.