-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ripley performance improvements #8
Closed
Closed
Changes from 40 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
3164dd7
Use fasthttp.Client
eugenepaniot 5c1e826
Use fasthttp.Client
eugenepaniot bc13f29
Use handleResult
eugenepaniot c75b37d
Add minimum wait duration
eugenepaniot ff69c7e
Update dockerimage
eugenepaniot 6cf879a
Always time.Sleep
eugenepaniot 89c0b69
Rewrite dummyweb.go using fasthttp
eugenepaniot 9519a00
Add TestFasthttpRequest
eugenepaniot f2d2014
Use fasthttp.HostClient instead of fasthttp.Client
eugenepaniot 5f4ce0d
Reinvent http client
eugenepaniot aaa33fd
Reinvent http client
eugenepaniot c3c0ae2
Update metrics
eugenepaniot a0012f0
Add pacer_phases metric
eugenepaniot ed64d4e
Add linegen to generate data for ripley
eugenepaniot 17991ed
Update
eugenepaniot 5254c13
Use memory pointer in unmarshalRequest
eugenepaniot 14b823a
Add metricsRequestReceived channel to wait for the last metrics scrape
eugenepaniot c4e72c3
Add nLongestResults
eugenepaniot 15650fe
Thread-safe clientsPool LoadOrStore
eugenepaniot a157732
Thread-safe clientsPool LoadOrStore
eugenepaniot f8b2f26
Add SilentHttpError option
eugenepaniot c86c63a
json.Marshal to result.toJson
eugenepaniot c875e6a
update go.mod
eugenepaniot 3547f15
Add Result.Response
eugenepaniot 313b98e
Use go 1.20
eugenepaniot 583fc8a
Use httpResp.SkipBody = true
eugenepaniot b7d26f0
Better error handling
eugenepaniot 9880fa6
Optimised b2s func
eugenepaniot 8424b7f
update deps
eugenepaniot ebd0cc8
Fix waitGroupResults race
eugenepaniot f3c5427
Rollback httpResp.SkipBody as some strange behaviour occures
eugenepaniot d16fbf9
Use Slices for SlowestResults rather Heap
eugenepaniot f22cae9
Do not use global vars for metric recv channel
eugenepaniot 6b59a2a
printNSlowest over NlongestPrint and NlongestResults
eugenepaniot ce23a48
copy Result
eugenepaniot 8687e72
store
eugenepaniot f026f19
panic: runtime error: index out of range [0] with length 0 in waitDur…
eugenepaniot c9d382e
update new pacer call
eugenepaniot f1e5bd0
Use synchronization in waitDuration and onPhaseElapsed
eugenepaniot 24c0aa3
Print metrics and slowest results by signal
eugenepaniot 50933a6
Merge branch 'main' into benchmark-ep
eugenepaniot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,21 @@ | ||
FROM golang:1.20-alpine as build | ||
|
||
ADD . /src/ | ||
|
||
RUN cd /src && \ | ||
go mod download && \ | ||
go build -o /ripley . && \ | ||
go build -o /dummyweb etc/dummyweb.go && \ | ||
go build -o /linegen etc/linegen.go | ||
|
||
################################## | ||
# Start fresh from a smaller image | ||
FROM alpine:3.15.0 | ||
################################## | ||
FROM alpine:latest | ||
RUN apk add ca-certificates | ||
|
||
COPY ripley /usr/bin/ripley | ||
ENTRYPOINT ["/usr/bin/ripley"] | ||
COPY --from=build /ripley /usr/bin/ripley | ||
COPY --from=build /linegen /usr/bin/linegen | ||
COPY --from=build /dummyweb /usr/bin/dummyweb | ||
|
||
ENTRYPOINT ["/usr/bin/ripley"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,100 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/http/httputil" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/valyala/fasthttp" | ||
"github.com/valyala/fasthttp/reuseport" | ||
) | ||
|
||
func handler(w http.ResponseWriter, r *http.Request) { | ||
dump, err := httputil.DumpRequest(r, true) | ||
var silent bool | ||
|
||
func main() { | ||
flag.BoolVar(&silent, "silent", false, "whether to silence output") | ||
addr := flag.String("addr", "localhost:8080", "server listen address. Default: localhost:8080") | ||
flag.Parse() | ||
|
||
// Create a new listener on the given address using port reuse | ||
ln, err := reuseport.Listen("tcp4", *addr) | ||
if err != nil { | ||
panic(err) | ||
log.Fatalf("error creating listener: %v", err) | ||
} | ||
defer ln.Close() | ||
|
||
log.Printf("%v: %s\n", time.Now().Format(time.UnixDate), string(dump)) | ||
w.Write([]byte("hi\n")) | ||
// Create a new fasthttp server | ||
server := &fasthttp.Server{ | ||
TCPKeepalive: true, | ||
LogAllErrors: true, | ||
ReadBufferSize: 1024 * 1024, | ||
WriteBufferSize: 1024 * 1024, | ||
ReadTimeout: 90 * time.Second, | ||
WriteTimeout: 5 * time.Second, | ||
Handler: requestHandler, | ||
} | ||
|
||
// Start the server in a goroutine | ||
go func() { | ||
if err := server.Serve(ln); err != nil { | ||
log.Fatalf("error starting server: %v", err) | ||
} | ||
}() | ||
|
||
// Wait for a signal to stop the server | ||
sig := make(chan os.Signal, 1) | ||
signal.Notify(sig, os.Interrupt, syscall.SIGTERM) | ||
<-sig | ||
|
||
// Stop the server | ||
server.Shutdown() | ||
} | ||
|
||
func main() { | ||
http.HandleFunc("/", handler) | ||
log.Fatal(http.ListenAndServe(":8080", nil)) | ||
func requestToJSON(req *fasthttp.Request) ([]byte, error) { | ||
type requestJSON struct { | ||
URI string `json:"uri"` | ||
Method string `json:"method"` | ||
Headers map[string]string `json:"headers"` | ||
ContentType string `json:"content_type"` | ||
Body string `json:"body"` | ||
} | ||
|
||
// Get the request URI, method, headers, content type, and body | ||
uri := string(req.URI().FullURI()) | ||
method := string(req.Header.Method()) | ||
headers := make(map[string]string) | ||
req.Header.VisitAll(func(k, v []byte) { | ||
headers[string(k)] = string(v) | ||
}) | ||
contentType := string(req.Header.ContentType()) | ||
body := string(req.Body()) | ||
|
||
// Create a requestJSON struct and marshal it to JSON | ||
reqJSON := &requestJSON{ | ||
URI: uri, | ||
Method: method, | ||
Headers: headers, | ||
ContentType: contentType, | ||
Body: body, | ||
} | ||
return json.Marshal(reqJSON) | ||
} | ||
|
||
func requestHandler(ctx *fasthttp.RequestCtx) { | ||
jsonData, _ := requestToJSON(&ctx.Request) | ||
|
||
if !silent { | ||
fmt.Println(string(jsonData)) | ||
} | ||
|
||
ctx.SetContentType("application/json") | ||
ctx.Response.Header.SetContentLength(len(jsonData)) | ||
// ctx.Response.Header.Set("Connection", "keep-alive") | ||
ctx.SetStatusCode(fasthttp.StatusOK) | ||
ctx.Write(jsonData) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"flag" | ||
"fmt" | ||
"os" | ||
"time" | ||
) | ||
|
||
func main() { | ||
rate := flag.Int("rate", 10, "lines per second") | ||
flag.Parse() | ||
|
||
tickDuration := time.Duration((1000000 / (*rate))) * time.Microsecond | ||
|
||
ticker := time.NewTicker(tickDuration) | ||
defer ticker.Stop() | ||
|
||
scanner := bufio.NewScanner(os.Stdin) | ||
if !scanner.Scan() { | ||
return | ||
} | ||
line := scanner.Text() | ||
|
||
for range ticker.C { | ||
fmt.Println(line) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,12 @@ | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:50.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:51.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:52.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:53.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:54.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:55.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:56.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T18:59:57.9Z"} | ||
{"url": "http://localhost:8080/", "method": "POST", "body": "{\"foo\": \"bar\"}", "headers": {"Accept": "text/plain"}, "timestamp": "2021-11-08T18:59:58.9Z"} | ||
{"url": "http://localhost:8080/localhost:8080", "method": "GET", "timestamp": "2021-11-08T18:59:50.9Z", "headers": {"Content-Type": "application/json", "Host": "example.net", "Cookies":"cookie=1234567890", "User-Agent":"Mozilla/5.0", "x-custom-header":"x-custom-header-value"}} | ||
{"url": "http://localhost:8081/localhost:8081", "method": "GET", "timestamp": "2021-11-08T18:59:50.9Z", "headers": {"Content-Type": "application/json", "Host": "example.net", "Cookies":"cookie=1234567890", "User-Agent":"Mozilla/5.0", "x-custom-header":"x-custom-header-value"}} | ||
{"url": "http://localhost:8080/localhost:8080", "method": "POST", "body": "{\"foo\": \"bar\"}", "headers": {"Accept": "text/plain"}, "timestamp": "2021-11-08T18:59:58.9Z"} | ||
{"url": "http://localhost:8081/localhost:8081", "method": "POST", "body": "{\"foo\": \"bar\"}", "headers": {"Accept": "text/plain"}, "timestamp": "2021-11-08T18:59:58.9Z"} | ||
{"url": "http://localhost:8081/", "method": "GET", "headers": {"Accept": "text/plain"}, "timestamp": "2021-11-08T18:59:59.9Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "headers": {"Accept": "text/plain"}, "timestamp": "2021-11-08T18:59:59.9Z"} | ||
{"url": "http://localhost:8080/", "method": "HEAD", "timestamp": "2021-11-08T19:00:00.00Z"} | ||
{"url": "http://localhost:8080/", "method": "HEAD", "timestamp": "2021-11-08T19:00:00.00Z", "headers": {"Connection": "close" }} | ||
{"url": "http://localhost:8080/", "method": "OPTIONS", "timestamp": "2021-11-08T19:00:00.01Z"} | ||
{"url": "http://localhost:8080/", "method": "TRACE", "timestamp": "2021-11-08T19:00:00.02Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T19:00:00.04Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T19:00:00.04Z"}}} | ||
{"url": "http://localhost:8080/", "method": "PROPFIND", "timestamp": "2021-11-08T19:00:00.03Z"} | ||
{"url": "http://localhost:8080/", "method": "GET", "timestamp": "2021-11-08T19:00:00.04Z"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,20 @@ | ||
module github.com/loveholidays/ripley | ||
|
||
go 1.17 | ||
go 1.20 | ||
|
||
require ( | ||
github.com/VictoriaMetrics/metrics v1.23.1 | ||
github.com/montanaflynn/stats v0.7.0 | ||
github.com/valyala/fasthttp v1.45.0 | ||
github.com/valyala/fastjson v1.6.4 | ||
) | ||
|
||
require ( | ||
github.com/andybalholm/brotli v1.0.5 // indirect | ||
github.com/klauspost/compress v1.16.3 // indirect | ||
github.com/valyala/bytebufferpool v1.0.0 // indirect | ||
github.com/valyala/fastrand v1.1.0 // indirect | ||
github.com/valyala/histogram v1.2.0 // indirect | ||
github.com/valyala/tcplisten v1.0.0 // indirect | ||
golang.org/x/sys v0.6.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
github.com/VictoriaMetrics/metrics v1.23.1 h1:/j8DzeJBxSpL2qSIdqnRFLvQQhbJyJbbEi22yMm7oL0= | ||
github.com/VictoriaMetrics/metrics v1.23.1/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc= | ||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= | ||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= | ||
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= | ||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||
github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= | ||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | ||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= | ||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | ||
github.com/valyala/fasthttp v1.45.0 h1:zPkkzpIn8tdHZUrVa6PzYd0i5verqiPSkgTd3bSUcpA= | ||
github.com/valyala/fasthttp v1.45.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= | ||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= | ||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= | ||
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= | ||
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= | ||
github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= | ||
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY= | ||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= | ||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= | ||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,29 +20,49 @@ package main | |
|
||
import ( | ||
"flag" | ||
"fmt" | ||
_ "net/http/pprof" | ||
"os" | ||
"os/signal" | ||
"runtime" | ||
"runtime/pprof" | ||
"syscall" | ||
|
||
ripley "github.com/loveholidays/ripley/pkg" | ||
) | ||
|
||
func main() { | ||
paceStr := flag.String("pace", "10s@1", `[duration]@[rate], e.g. "1m@1 [email protected] 1h@2"`) | ||
silent := flag.Bool("silent", false, "Suppress output") | ||
dryRun := flag.Bool("dry-run", false, "Consume input but do not send HTTP requests to targets") | ||
timeout := flag.Int("timeout", 10, "HTTP client timeout in seconds") | ||
strict := flag.Bool("strict", false, "Panic on bad input") | ||
memprofile := flag.String("memprofile", "", "Write memory profile to `file` before exit") | ||
numWorkers := flag.Int("workers", 1000, "Number of client workers to use") | ||
var opts ripley.Options | ||
|
||
flag.StringVar(&opts.Pace, "pace", "10s@1", `[duration]@[rate], e.g. "1m@1 [email protected] 1h@2"`) | ||
flag.BoolVar(&opts.Silent, "silent", false, "Suppress output") | ||
flag.BoolVar(&opts.SilentHttpError, "silentHttpError", false, "Suppress HTTP errors (http codes 5xx) output") | ||
|
||
flag.BoolVar(&opts.DryRun, "dry-run", false, "Consume input but do not send HTTP requests to targets") | ||
flag.IntVar(&opts.Timeout, "timeout", 10, "HTTP client request timeout in seconds") | ||
flag.IntVar(&opts.TimeoutConnection, "timeoutConnection", 3, "HTTP client connetion timeout in seconds") | ||
flag.BoolVar(&opts.Strict, "strict", false, "Panic on bad input") | ||
flag.StringVar(&opts.Memprofile, "memprofile", "", "Write memory profile to `file` before exit") | ||
flag.IntVar(&opts.NumWorkers, "workers", 10, "Number of client workers to use") | ||
|
||
flag.BoolVar(&opts.PrintStat, "printStat", false, "Print statistics to stdout at the end") | ||
flag.BoolVar(&opts.MetricsServerEnable, "metricsServerEnable", false, "Enable metrics server. Server prometheus statistics on /metrics endpoint") | ||
flag.StringVar(&opts.MetricsServerAddr, "metricsServerAddr", "0.0.0.0:8081", "Metrics server listen address") | ||
|
||
flag.IntVar(&opts.PrintNSlowest, "printNSlowest", 0, "Print N slowest Requests") | ||
|
||
flag.Usage = func() { | ||
fmt.Fprintf(os.Stderr, "Usage: %s -target string\n", os.Args[0]) | ||
flag.PrintDefaults() | ||
} | ||
|
||
flag.Parse() | ||
|
||
exitCode := ripley.Replay(*paceStr, *silent, *dryRun, *timeout, *strict, *numWorkers) | ||
exitCode := ripley.Replay(&opts) | ||
defer os.Exit(exitCode) | ||
|
||
if *memprofile != "" { | ||
f, err := os.Create(*memprofile) | ||
if opts.Memprofile != "" { | ||
f, err := os.Create(opts.Memprofile) | ||
|
||
if err != nil { | ||
panic(err) | ||
|
@@ -54,5 +74,10 @@ func main() { | |
if err := pprof.WriteHeapProfile(f); err != nil { | ||
panic(err) | ||
} | ||
|
||
// Wait for a signal to stop the server | ||
sig := make(chan os.Signal, 1) | ||
signal.Notify(sig, os.Interrupt, syscall.SIGTERM) | ||
<-sig | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When is this useful?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
silentHttpError
could be useful when need to do some bechmark testing exclusively or in situations when it's acceptable to overlook any HTTP errors.