Skip to content

Commit af7e51f

Browse files
author
anjmao
committed
Initial commit
1 parent 89c3886 commit af7e51f

File tree

15 files changed

+366
-1
lines changed

15 files changed

+366
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
netcore/bin
2+
netcore/obj

README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,50 @@
1-
# netcore-vs-golang
1+
# netcore-vs-golang
2+
3+
Test http client, object serialize and deserialize times
4+
5+
## Start containers
6+
`docker-compose up -e HOST=192.168.1.145`
7+
8+
Note: change HOST to your local host IP
9+
10+
### .net core api
11+
12+
```
13+
wrk --connections 256 --duration 60s --threads 8 --timeout 5s --latency --script /Users/anma/go/src/github.com/anjmao/netcore-vs-golang/wrk/requests.lua http://localhost:5000
14+
Running 1m test @ http://localhost:5000
15+
8 threads and 256 connections
16+
Thread Stats Avg Stdev Max +/- Stdev
17+
Latency 135.48ms 36.55ms 307.72ms 73.63%
18+
Req/Sec 228.45 83.09 555.00 60.63%
19+
Latency Distribution
20+
50% 133.44ms
21+
75% 156.51ms
22+
90% 181.22ms
23+
99% 229.40ms
24+
109006 requests in 1.00m, 23.57MB read
25+
Socket errors: connect 0, read 415, write 2, timeout 0
26+
Non-2xx or 3xx responses: 6
27+
Requests/sec: 1815.36
28+
Transfer/sec: 401.99KB
29+
```
30+
31+
### golang api
32+
33+
```
34+
wrk --connections 256 --duration 60s --threads 8 --timeout 5s --latency --script /Users/anma/go/src/github.com/anjmao/netcore-vs-golang/wrk/requests.lua http://localhost:5001
35+
Running 1m test @ http://localhost:5001
36+
8 threads and 256 connections
37+
Thread Stats Avg Stdev Max +/- Stdev
38+
Latency 82.78ms 135.06ms 1.76s 95.92%
39+
Req/Sec 234.87 172.69 1.02k 72.98%
40+
Latency Distribution
41+
50% 54.63ms
42+
75% 85.81ms
43+
90% 134.80ms
44+
99% 800.28ms
45+
106498 requests in 1.00m, 19.37MB read
46+
Socket errors: connect 0, read 32597, write 0, timeout 0
47+
Requests/sec: 1772.37
48+
Transfer/sec: 330.17KB
49+
```
50+

api/Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM golang:1.8.3
2+
3+
WORKDIR /go/src/app
4+
COPY . .
5+
6+
RUN go-wrapper install
7+
8+
CMD ["go-wrapper", "run"]

api/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
build:
2+
docker build -t api .
3+
4+
run:
5+
docker run -it --rm \
6+
-p 5002:5002 \
7+
api

api/main.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log"
7+
"math/rand"
8+
"net/http"
9+
"strconv"
10+
"time"
11+
)
12+
13+
type Response struct {
14+
Id string
15+
Name string
16+
Time int64
17+
}
18+
19+
func main() {
20+
21+
http.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
22+
rsp := Response{
23+
Id: "id_" + strconv.Itoa(rand.Int()),
24+
Name: "name_" + strconv.Itoa(rand.Int()),
25+
Time: time.Now().Unix(),
26+
}
27+
28+
js, err := json.Marshal(rsp)
29+
if err != nil {
30+
http.Error(w, err.Error(), http.StatusInternalServerError)
31+
return
32+
}
33+
34+
w.Header().Set("Content-Type", "application/json")
35+
w.Write(js)
36+
})
37+
38+
addr := ":5002"
39+
fmt.Println("listening on " + addr)
40+
log.Fatal(http.ListenAndServe(addr, nil))
41+
}

docker-compose.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: '3'
2+
services:
3+
api:
4+
build: ./api
5+
ports:
6+
- "5002:5002"
7+
8+
go:
9+
build: ./go
10+
ports:
11+
- "5001:5001"
12+
environment:
13+
- HOST=${HOST}
14+
depends_on:
15+
- api
16+
17+
netcore:
18+
build: ./netcore
19+
ports:
20+
- "5000:5000"
21+
environment:
22+
- HOST=${HOST}
23+
depends_on:
24+
- api
25+

go/Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM golang:1.8.3
2+
3+
WORKDIR /go/src/app
4+
COPY . .
5+
6+
RUN go-wrapper install
7+
8+
CMD ["go-wrapper", "run"]

go/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Update to your host
2+
DOCKER_HOST=192.168.1.145
3+
4+
build:
5+
docker build -t goapp .
6+
7+
run:
8+
docker run -it --rm \
9+
-e DOCKER_HOST=$(DOCKER_HOST) \
10+
-p 5001:5001 \
11+
goapp

go/main.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"html"
7+
"log"
8+
"net/http"
9+
"os"
10+
)
11+
12+
type Response struct {
13+
Id string
14+
Name string
15+
Time int64
16+
}
17+
18+
func main() {
19+
url := "http://" + os.Getenv("HOST") + ":5002/data"
20+
tr := &http.Transport{
21+
MaxIdleConns: 2000,
22+
MaxIdleConnsPerHost: 2000,
23+
}
24+
client := &http.Client{Transport: tr}
25+
26+
http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
27+
rsp, err := client.Get(url)
28+
if err != nil {
29+
serverError(w, err.Error())
30+
return
31+
}
32+
33+
rsp.Close = true
34+
defer rsp.Body.Close()
35+
36+
// deserialize
37+
obj := Response{}
38+
err = json.NewDecoder(rsp.Body).Decode(&obj)
39+
if err != nil {
40+
serverError(w, err.Error())
41+
return
42+
}
43+
44+
// serialize
45+
jsonStr, err := json.Marshal(&obj)
46+
if err != nil {
47+
serverError(w, err.Error())
48+
return
49+
}
50+
51+
w.Header().Set("Content-Type", "application/json")
52+
w.Write(jsonStr)
53+
})
54+
55+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
56+
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
57+
})
58+
59+
addr := ":5001"
60+
fmt.Println("listening on " + addr)
61+
log.Fatal(http.ListenAndServe(addr, nil))
62+
}
63+
64+
func serverError(w http.ResponseWriter, msg string) {
65+
http.Error(w, msg, http.StatusInternalServerError)
66+
}

netcore/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM microsoft/dotnet:2.0.0-preview2-sdk
2+
3+
WORKDIR /dotnetapp
4+
5+
# copy project.json and restore as distinct layers
6+
COPY netcore.csproj .
7+
RUN dotnet restore
8+
9+
# copy and build everything else
10+
COPY . .
11+
RUN dotnet publish -c Release -o out
12+
ENTRYPOINT ["dotnet", "out/netcore.dll"]

netcore/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
build:
3+
docker build -t netcore .
4+
5+
run:
6+
docker run -it --rm \
7+
-p 5000:5000 \
8+
netcore

netcore/Program.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore;
9+
using Microsoft.AspNetCore.Builder;
10+
using Microsoft.AspNetCore.Hosting;
11+
using Microsoft.AspNetCore.Http;
12+
using Microsoft.Extensions.Configuration;
13+
using Microsoft.Extensions.Logging;
14+
using Newtonsoft.Json;
15+
16+
class Program
17+
{
18+
public static void Main(string[] args)
19+
{
20+
BuildWebHost(args).Run();
21+
}
22+
23+
public static IWebHost BuildWebHost(string[] args) =>
24+
WebHost.CreateDefaultBuilder(args)
25+
.UseStartup<Startup>()
26+
.UseUrls("http://*:5000")
27+
.Build();
28+
}
29+
class Response
30+
{
31+
public string Id { get; set; }
32+
public string Name { get; set; }
33+
public long Time { get; set; }
34+
}
35+
36+
class Startup
37+
{
38+
private static readonly HttpClient _http = new HttpClient
39+
{
40+
BaseAddress = new Uri($"http://{Environment.GetEnvironmentVariable("HOST")}:5002")
41+
};
42+
43+
private static Random _random = new Random();
44+
45+
private static void HandleTest(IApplicationBuilder app)
46+
{
47+
app.Run(async ctx =>
48+
{
49+
var rsp = await _http.GetAsync("/data");
50+
var str = await rsp.Content.ReadAsStringAsync();
51+
52+
// deserialize
53+
var obj = JsonConvert.DeserializeObject<Response>(str);
54+
55+
// serialize
56+
var json = JsonConvert.SerializeObject(obj);
57+
58+
ctx.Response.ContentType = "application/json";
59+
await ctx.Response.WriteAsync(json);
60+
});
61+
}
62+
63+
public void Configure(IApplicationBuilder app)
64+
{
65+
app.Map("/test", HandleTest);
66+
67+
app.Run(async ctx =>
68+
{
69+
await ctx.Response.WriteAsync($"Hello, {ctx.Request.Path}");
70+
});
71+
}
72+
}

netcore/netcore.csproj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview2-final" />
10+
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0-preview2-final" />
15+
</ItemGroup>
16+
17+
</Project>

wrk/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
URL?=http://localhost:5000
2+
3+
WRK=wrk --connections 256 \
4+
--duration 60s \
5+
--threads 8 \
6+
--timeout 5s \
7+
--latency \
8+
--script \
9+
$(shell pwd)/requests.lua \
10+
$(URL)
11+
12+
run:
13+
$(WRK)

wrk/requests.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
math.randomseed(os.time())
2+
3+
4+
function generate_query()
5+
local query = {}
6+
7+
seq = math.random(100000, 200000)
8+
9+
query["fn"] = string.format("Firstname_%s", seq)
10+
query["ln"] = string.format("Lastname_%s", seq)
11+
query["rn"] = string.format("ref_%s", seq)
12+
13+
local keyvals = {}
14+
15+
for key, val in pairs(query) do
16+
table.insert(keyvals, string.format("%s=%s", key, val))
17+
end
18+
19+
return string.format("/test?%s", table.concat(keyvals, "&"))
20+
end
21+
22+
23+
request = function()
24+
local path = generate_query()
25+
return wrk.format(nil, path)
26+
end

0 commit comments

Comments
 (0)