Compare commits

...

1 Commits

Author SHA1 Message Date
jonaustin09
27a8aa66d9 feat: Added s3 proxy comparison to upload, download and throughput benchmark tests 2023-11-20 14:28:02 -05:00
2 changed files with 99 additions and 24 deletions

View File

@@ -2,6 +2,9 @@ package main
import (
"fmt"
"math"
"os"
"text/tabwriter"
"github.com/urfave/cli/v2"
"github.com/versity/versitygw/integration"
@@ -13,6 +16,7 @@ var (
endpoint string
prefix string
dstBucket string
proxyURL string
partSize int64
objSize int64
concurrency int
@@ -118,6 +122,7 @@ func initTestCommands() []*cli.Command {
Name: "bucket",
Usage: "Destination bucket name to read/write data",
Destination: &dstBucket,
Required: true,
},
&cli.Int64Flag{
Name: "partSize",
@@ -143,6 +148,11 @@ func initTestCommands() []*cli.Command {
Value: false,
Destination: &checksumDisable,
},
&cli.StringFlag{
Name: "proxy-url",
Usage: "S3 proxy server url to compare",
Destination: &proxyURL,
},
},
Action: func(ctx *cli.Context) error {
if upload && download {
@@ -152,10 +162,6 @@ func initTestCommands() []*cli.Command {
return fmt.Errorf("must specify one of upload or download")
}
if dstBucket == "" {
return fmt.Errorf("must specify bucket")
}
opts := []integration.Option{
integration.WithAccess(awsID),
integration.WithSecret(awsSecret),
@@ -177,9 +183,47 @@ func initTestCommands() []*cli.Command {
s3conf := integration.NewS3Conf(opts...)
if upload {
return integration.TestUpload(s3conf, files, objSize, dstBucket, prefix)
if proxyURL == "" {
integration.TestUpload(s3conf, files, objSize, dstBucket, prefix)
return nil
} else {
size, elapsed, err := integration.TestUpload(s3conf, files, objSize, dstBucket, prefix)
opts = append(opts, integration.WithEndpoint(proxyURL))
proxyS3Conf := integration.NewS3Conf(opts...)
proxySize, proxyElapsed, proxyErr := integration.TestUpload(proxyS3Conf, files, objSize, dstBucket, prefix)
if err != nil || proxyErr != nil {
return nil
}
printProxyResultsTable([][4]string{
{" # ", "Total Size", "Time Taken", "Speed(MB/S)"},
{"---------", "----------", "----------", "-----------"},
{"S3 Server", fmt.Sprint(size), fmt.Sprintf("%v", elapsed), fmt.Sprint(int(math.Ceil(float64(size)/elapsed.Seconds()) / 1048576))},
{"S3 Proxy", fmt.Sprint(proxySize), fmt.Sprintf("%v", proxyElapsed), fmt.Sprint(int(math.Ceil(float64(proxySize)/proxyElapsed.Seconds()) / 1048576))},
})
return nil
}
} else {
return integration.TestDownload(s3conf, files, objSize, dstBucket, prefix)
if proxyURL == "" {
integration.TestDownload(s3conf, files, objSize, dstBucket, prefix)
return nil
} else {
size, elapsed, err := integration.TestDownload(s3conf, files, objSize, dstBucket, prefix)
opts = append(opts, integration.WithEndpoint(proxyURL))
proxyS3Conf := integration.NewS3Conf(opts...)
proxySize, proxyElapsed, proxyErr := integration.TestDownload(proxyS3Conf, files, objSize, dstBucket, prefix)
if err != nil || proxyErr != nil {
return nil
}
printProxyResultsTable([][4]string{
{" # ", "Total Size", "Time Taken", "Speed(MB/S)"},
{"---------", "----------", "----------", "-----------"},
{"S3 server", fmt.Sprint(size), fmt.Sprintf("%v", elapsed), fmt.Sprint(int(math.Ceil(float64(size)/elapsed.Seconds()) / 1048576))},
{"S3 proxy", fmt.Sprint(proxySize), fmt.Sprintf("%v", proxyElapsed), fmt.Sprint(int(math.Ceil(float64(proxySize)/proxyElapsed.Seconds()) / 1048576))},
})
return nil
}
}
},
},
@@ -211,12 +255,13 @@ func initTestCommands() []*cli.Command {
Value: false,
Destination: &checksumDisable,
},
&cli.StringFlag{
Name: "proxy-url",
Usage: "S3 proxy server url to compare",
Destination: &proxyURL,
},
},
Action: func(ctx *cli.Context) error {
if dstBucket == "" {
return fmt.Errorf("must specify the destination bucket")
}
opts := []integration.Option{
integration.WithAccess(awsID),
integration.WithSecret(awsSecret),
@@ -233,7 +278,27 @@ func initTestCommands() []*cli.Command {
s3conf := integration.NewS3Conf(opts...)
return integration.TestReqPerSec(s3conf, totalReqs, dstBucket)
if proxyURL == "" {
_, _, err := integration.TestReqPerSec(s3conf, totalReqs, dstBucket)
return err
} else {
elapsed, rps, err := integration.TestReqPerSec(s3conf, totalReqs, dstBucket)
opts = append(opts, integration.WithEndpoint(proxyURL))
s3proxy := integration.NewS3Conf(opts...)
proxyElapsed, proxyRPS, proxyErr := integration.TestReqPerSec(s3proxy, totalReqs, dstBucket)
if err != nil || proxyErr != nil {
return nil
}
printProxyResultsTable([][4]string{
{" # ", "Total Requests", "Time Taken", "Requests Per Second(Req/Sec)"},
{"---------", "--------------", "----------", "----------------------------"},
{"S3 Server", fmt.Sprint(totalReqs), fmt.Sprintf("%v", elapsed), fmt.Sprint(rps)},
{"S3 Proxy", fmt.Sprint(totalReqs), fmt.Sprintf("%v", proxyElapsed), fmt.Sprint(proxyRPS)},
})
return nil
}
},
},
}
@@ -264,3 +329,13 @@ func getAction(tf testFunc) func(*cli.Context) error {
return nil
}
}
func printProxyResultsTable(stats [][4]string) {
w := new(tabwriter.Writer)
w.Init(os.Stdout, minwidth, tabwidth, padding, padchar, flags)
for _, elem := range stats {
fmt.Fprintf(w, "%v\t%v\t%v\t%v\n", elem[0], elem[1], elem[2], elem[3])
}
fmt.Fprintln(w)
w.Flush()
}

View File

@@ -17,16 +17,16 @@ type prefResult struct {
err error
}
func TestUpload(s *S3Conf, files int, objSize int64, bucket, prefix string) error {
func TestUpload(s *S3Conf, files int, objSize int64, bucket, prefix string) (size int64, elapsed time.Duration, err error) {
var sg sync.WaitGroup
results := make([]prefResult, files)
start := time.Now()
if objSize == 0 {
return fmt.Errorf("must specify object size for upload")
return 0, time.Since(start), fmt.Errorf("must specify object size for upload")
}
if objSize > (int64(10000) * s.PartSize) {
return fmt.Errorf("object size can not exceed 10000 * chunksize")
return 0, time.Since(start), fmt.Errorf("object size can not exceed 10000 * chunksize")
}
runF("performance test: upload objects")
@@ -45,13 +45,13 @@ func TestUpload(s *S3Conf, files int, objSize int64, bucket, prefix string) erro
}(i)
}
sg.Wait()
elapsed := time.Since(start)
elapsed = time.Since(start)
var tot int64
for i, res := range results {
if res.err != nil {
failF("%v: %v\n", i, res.err)
break
return 0, time.Since(start), res.err
}
tot += res.size
fmt.Printf("%v: %v in %v (%v MB/s)\n",
@@ -63,10 +63,10 @@ func TestUpload(s *S3Conf, files int, objSize int64, bucket, prefix string) erro
passF("run upload: %v in %v (%v MB/s)\n",
tot, elapsed, int(math.Ceil(float64(tot)/elapsed.Seconds())/1048576))
return nil
return tot, time.Since(start), nil
}
func TestDownload(s *S3Conf, files int, objSize int64, bucket, prefix string) error {
func TestDownload(s *S3Conf, files int, objSize int64, bucket, prefix string) (size int64, elapsed time.Duration, err error) {
var sg sync.WaitGroup
results := make([]prefResult, files)
start := time.Now()
@@ -86,13 +86,13 @@ func TestDownload(s *S3Conf, files int, objSize int64, bucket, prefix string) er
}(i)
}
sg.Wait()
elapsed := time.Since(start)
elapsed = time.Since(start)
var tot int64
for i, res := range results {
if res.err != nil {
failF("%v: %v\n", i, res.err)
break
return 0, elapsed, err
}
tot += res.size
fmt.Printf("%v: %v in %v (%v MB/s)\n",
@@ -104,10 +104,10 @@ func TestDownload(s *S3Conf, files int, objSize int64, bucket, prefix string) er
passF("run download: %v in %v (%v MB/s)\n",
tot, elapsed, int(math.Ceil(float64(tot)/elapsed.Seconds())/1048576))
return nil
return tot, elapsed, nil
}
func TestReqPerSec(s *S3Conf, totalReqs int, bucket string) error {
func TestReqPerSec(s *S3Conf, totalReqs int, bucket string) (time.Duration, int, error) {
client := s3.NewFromConfig(s.Config())
var wg sync.WaitGroup
var resErr error
@@ -132,11 +132,11 @@ func TestReqPerSec(s *S3Conf, totalReqs int, bucket string) error {
wg.Wait()
if resErr != nil {
failF("performance test failed with error: %w", resErr)
return nil
return time.Since(startTime), 0, resErr
}
elapsedTime := time.Since(startTime)
rps := int(float64(totalReqs) / elapsedTime.Seconds())
passF("Success\nTotal Requests: %d,\nConcurrency Level: %d,\nTime Taken: %s,\nRequests Per Second: %dreq/sec", totalReqs, s.Concurrency, elapsedTime, rps)
return nil
return elapsedTime, rps, nil
}