From 0c403fd0c6f58df769163353175deeb06059562d Mon Sep 17 00:00:00 2001 From: kataras Date: Mon, 21 Aug 2017 13:29:49 +0300 Subject: [PATCH] .NET Core (no mvc) with Sessions vs Iris (no mvc) with Sessions Former-commit-id: 04a9660645a824dfbc49414605aeff2b3ff88b55 --- _benchmarks/README.md | 68 ++++++++++++++- _benchmarks/iris-sessions/main.go | 67 ++++++++++++++ _benchmarks/netcore-sessions/Program.cs | 25 ++++++ _benchmarks/netcore-sessions/Startup.cs | 82 ++++++++++++++++++ _benchmarks/netcore-sessions/appsettings.json | 8 ++ .../netcore-sessions/netcore-sessions.csproj | 15 ++++ .../screens/5m_requests_iris-sessions.png | Bin 0 -> 11251 bytes .../screens/5m_requests_netcore-sessions.png | Bin 0 -> 11580 bytes 8 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 _benchmarks/iris-sessions/main.go create mode 100644 _benchmarks/netcore-sessions/Program.cs create mode 100644 _benchmarks/netcore-sessions/Startup.cs create mode 100644 _benchmarks/netcore-sessions/appsettings.json create mode 100644 _benchmarks/netcore-sessions/netcore-sessions.csproj create mode 100644 _benchmarks/screens/5m_requests_iris-sessions.png create mode 100644 _benchmarks/screens/5m_requests_netcore-sessions.png diff --git a/_benchmarks/README.md b/_benchmarks/README.md index 6991dadf..b8217e4e 100644 --- a/_benchmarks/README.md +++ b/_benchmarks/README.md @@ -169,7 +169,73 @@ Statistics Avg Stdev Max Iris MVC with Templates Application ran for **37 seconds** serving **26656.76** requests per second with **192.51MB/s** within **1.18ms** latency in average and **22.52ms** max, the memory usage of all these was ~17MB. +## Results with Sessions + +Here we will check the sessions performance, this time +we wanna use the .NET Core raw, **not MVC** and Iris raw, not MVC respectfully. + +Spawn `5000000 requests` with 125 different "threads" that sets and gets a session with name `key` and string value `"value"` to the same static request path. + +### .NET Core with Sessions + +```bash +$ cd netcore-sessions +$ dotnet run -c Release +Hosting environment: Production +Content root path: C:\mygopath\src\github.com\kataras\iris\_benchmarks\netcore-sessions +Now listening on: http://localhost:5000 +Application started. Press Ctrl+C to shut down. +``` + +```bash +Bombarding http://localhost:5000/setget with 5000000 requests using 125 connections + 5000000 / 5000000 [====================================================================================] 100.00% 2m40s +Done! +Statistics Avg Stdev Max + Reqs/sec 31844.77 13856.19 253746 + Latency 4.02ms 15.57ms 0.96s + HTTP codes: + 1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0 + others - 0 + Throughput: 14.51MB/s +``` + +### Iris with Sessions + +```bash +$ cd iris-sessions +$ go run main.go +Now listening on: http://localhost:5000 +Application started. Press CTRL+C to shut down. +``` + +```bash +Bombarding http://localhost:5000/setget with 5000000 requests using 125 connections + 5000000 / 5000000 [====================================================================================] 100.00% 1m15s +Done! +Statistics Avg Stdev Max + Reqs/sec 66749.70 32110.67 110445 + Latency 1.88ms 9.13ms 1.94s + HTTP codes: + 1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0 + others - 0 + Throughput: 20.65MB/s +``` + +#### Summary + +* Time to complete the `5000000 requests` - smaller is better. +* Reqs/sec - bigger is better. +* Latency - smaller is better +* Throughput - bigger is better. + +.NET Core with Sessions Application ran for **2 minutes and 40 seconds** serving **31844.77** requests per second with **14.51MB/s** within **4.02ms** latency in average and **0.96s** max. + +Iris with Sessions Application ran for **1 minute and 15 seconds** serving **66749.70** requests per second with **20.65MB/s** within **1.88ms** latency in average and **1.94s** max. + + **Thank you all** for the 100% green feedback, have fun! -- https://dev.to/kataras/go-vsnet-core-in-terms-of-http-performance - https://medium.com/@kataras/go-vs-net-core-in-terms-of-http-performance-7535a61b67b8 +- https://dev.to/kataras/go-vsnet-core-in-terms-of-http-performance + diff --git a/_benchmarks/iris-sessions/main.go b/_benchmarks/iris-sessions/main.go new file mode 100644 index 00000000..d5a34062 --- /dev/null +++ b/_benchmarks/iris-sessions/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "time" + + "github.com/kataras/iris" + "github.com/kataras/iris/context" + "github.com/kataras/iris/sessions" +) + +var sess = sessions.New(sessions.Config{ + Cookie: ".cookiesession.id", + Expires: time.Minute, +}) + +func main() { + app := iris.New() + + app.Get("/setget", h) + /* + Test them one by one by these methods: + app.Get("/get", getHandler) + app.Post("/set", postHandler) + app.Delete("/del", delHandler) + */ + + app.Run(iris.Addr(":5000")) +} + +// Set and Get +func h(ctx context.Context) { + session := sess.Start(ctx) + session.Set("key", "value") + + value := session.GetString("key") + if value == "" { + ctx.WriteString("NOT_OK") + return + } + + ctx.WriteString(value) +} + +// Get +func getHandler(ctx context.Context) { + session := sess.Start(ctx) + value := session.GetString("key") + if value == "" { + ctx.WriteString("NOT_OK") + return + } + ctx.WriteString(value) +} + +// Set +func postHandler(ctx context.Context) { + session := sess.Start(ctx) + session.Set("key", "value") + ctx.WriteString("OK") +} + +// Delete +func delHandler(ctx context.Context) { + session := sess.Start(ctx) + session.Delete("key") + ctx.WriteString("OK") +} diff --git a/_benchmarks/netcore-sessions/Program.cs b/_benchmarks/netcore-sessions/Program.cs new file mode 100644 index 00000000..d7f42c8f --- /dev/null +++ b/_benchmarks/netcore-sessions/Program.cs @@ -0,0 +1,25 @@ +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_sessions +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/_benchmarks/netcore-sessions/Startup.cs b/_benchmarks/netcore-sessions/Startup.cs new file mode 100644 index 00000000..3f4e7b43 --- /dev/null +++ b/_benchmarks/netcore-sessions/Startup.cs @@ -0,0 +1,82 @@ +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.AspNetCore.Routing; +using Microsoft.AspNetCore.Http; + +namespace netcore_sessions +{ + 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.AddRouting(); + + // Adds a default in-memory implementation of IDistributedCache. + services.AddDistributedMemoryCache(); + + services.AddSession(options => + { + options.Cookie.Name = ".cookiesession.id"; + options.Cookie.HttpOnly = true; + options.IdleTimeout = TimeSpan.FromMinutes(1); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + var routeBuilder = new RouteBuilder(app); + + routeBuilder.MapGet("setget", context =>{ + context.Session.SetString("key", "value"); + + var value = context.Session.GetString("key"); + if (String.IsNullOrEmpty(value)) { + return context.Response.WriteAsync("NOT_OK"); + } + + return context.Response.WriteAsync(value); + }); + /* + Test them one by one by these methods: + + routeBuilder.MapGet("get", context =>{ + var value = context.Session.GetString("key"); + if (String.IsNullOrEmpty(value)) { + return context.Response.WriteAsync("NOT_OK"); + } + return context.Response.WriteAsync(value); + }); + + routeBuilder.MapPost("set", context =>{ + context.Session.SetString("key", "value"); + return context.Response.WriteAsync("OK"); + }); + + routeBuilder.MapDelete("del", context =>{ + context.Session.Remove("key"); + return context.Response.WriteAsync("OK"); + }); + */ + + var routes = routeBuilder.Build(); + + app.UseSession(); + app.UseRouter(routes); + } + } +} diff --git a/_benchmarks/netcore-sessions/appsettings.json b/_benchmarks/netcore-sessions/appsettings.json new file mode 100644 index 00000000..50fe9a31 --- /dev/null +++ b/_benchmarks/netcore-sessions/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Error" + } + } +} diff --git a/_benchmarks/netcore-sessions/netcore-sessions.csproj b/_benchmarks/netcore-sessions/netcore-sessions.csproj new file mode 100644 index 00000000..b36fc56a --- /dev/null +++ b/_benchmarks/netcore-sessions/netcore-sessions.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.0 + + + + + + + + + + + diff --git a/_benchmarks/screens/5m_requests_iris-sessions.png b/_benchmarks/screens/5m_requests_iris-sessions.png new file mode 100644 index 0000000000000000000000000000000000000000..8da528a57c77eea4b56098048fdf9ad17b1a2387 GIT binary patch literal 11251 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 N@GaAu<@yhw{vR{_R^I>s literal 0 HcmV?d00001 diff --git a/_benchmarks/screens/5m_requests_netcore-sessions.png b/_benchmarks/screens/5m_requests_netcore-sessions.png new file mode 100644 index 0000000000000000000000000000000000000000..6baeebb39e8bd00a6d6a030b20922e3cf50f3424 GIT binary patch literal 11580 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