Added output from tests

Tested tests and fixed errors
Adjusted default values
This commit is contained in:
mitch 2022-01-05 01:09:52 -05:00
parent 02fa79e9ce
commit 6c6595b2a0
5 changed files with 102 additions and 23 deletions

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"math"
"math/rand" "math/rand"
"time" "time"
) )
@ -15,14 +16,22 @@ getBurstTest starts goroutines for getRedis at the burstRateLimit per second
*/ */
func getBurstTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.Duration) { func getBurstTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.Duration) {
durationChannel := make(chan bool, 1) durationChannel := make(chan bool, 1)
burstRateLimiter := time.Tick(time.Second) burstRateLimiter := time.Tick(time.Millisecond * 250)
timesChan := make(chan time.Duration)
errorChan := make(chan bool)
endChan := make(chan bool)
totalErrorChan := make(chan int)
totalTimeChan := make(chan []int64)
quaterRate := math.Abs(float64(rate) / 4)
go func() { go func() {
for i := 0; i < int(duration.Seconds()); i++ { for i := 0; i < int(duration.Seconds()); i++ {
<-time.Tick(time.Second) <-time.Tick(time.Second)
} }
durationChannel <- true durationChannel <- true
}() }()
fmt.Println("Starting burst test at", rate, "requests per second...")
go keepTotal(timesChan, errorChan, endChan, totalTimeChan, totalErrorChan)
fmt.Println("Starting burst test at", quaterRate, "requests per 250 milliseconds...")
end := false end := false
for { for {
if end { if end {
@ -32,11 +41,26 @@ func getBurstTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.D
case <-durationChannel: case <-durationChannel:
end = true end = true
case <-burstRateLimiter: case <-burstRateLimiter:
for i := 0; i < rate; i++ { for i := float64(0); i < quaterRate; i++ {
//this might need toggled
time.Sleep(time.Millisecond * 5)
key := rand.Intn(keyMaxValue) key := rand.Intn(keyMaxValue)
go getRedis(rdbPtr, key) go getRedis(rdbPtr, key, timesChan, errorChan)
} }
} }
} }
endChan <- true
totalTimesFloat := <-totalTimeChan
totalErrors := <-totalErrorChan
errorRate := totalErrors / len(totalTimesFloat)
totalTimes := intToFloat(totalTimesFloat)
mean, stddev, perc99, perc95 := getResponseTimes(totalTimes)
fmt.Println("Burst test concluded...") fmt.Println("Burst test concluded...")
fmt.Println("Total Requests:", len(totalTimesFloat))
fmt.Println("Error Rate:", errorRate, "ms")
fmt.Println("Mean:", mean, "ms")
fmt.Println("Standard Deviation:", stddev, "ms")
fmt.Println("95 Percentile:", perc95, "ms")
fmt.Println("99 Percentile:", perc99, "ms")
} }

View File

@ -17,10 +17,17 @@ Then starts goroutines for getRedis at that interval
*/ */
func getRateTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.Duration) { func getRateTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.Duration) {
durationChannel := make(chan bool, 1) durationChannel := make(chan bool, 1)
x := int(math.Abs(60 / float64(rate) * 10000000)) x := int(math.Abs(100 / float64(rate) * 10000000))
rateLimiter := time.Tick(time.Duration(x)) rateLimiter := time.Tick(time.Duration(x))
fmt.Println("Starting Test at", rateLimiter, "milliseconds per request...") timesChan := make(chan time.Duration)
errorChan := make(chan bool)
endChan := make(chan bool)
totalErrorChan := make(chan int)
totalTimeChan := make(chan []int64)
go keepTotal(timesChan, errorChan, endChan, totalTimeChan, totalErrorChan)
fmt.Println("Starting Test at", time.Duration(x), "milliseconds per request...")
go func() { go func() {
for i := 0; i < int(duration.Seconds()); i++ { for i := 0; i < int(duration.Seconds()); i++ {
<-time.Tick(time.Second) <-time.Tick(time.Second)
@ -39,8 +46,20 @@ func getRateTest(rdbPtr *redis.Conn, rate int, keyMaxValue int, duration time.Du
end = true end = true
case <-rateLimiter: case <-rateLimiter:
key := rand.Intn(keyMaxValue) key := rand.Intn(keyMaxValue)
go getRedis(rdbPtr, key) go getRedis(rdbPtr, key, timesChan, errorChan)
} }
} }
endChan <- true
totalTimesFloat := <-totalTimeChan
totalErrors := <-totalErrorChan
errorRate := totalErrors / len(totalTimesFloat)
totalTimes := intToFloat(totalTimesFloat)
mean, stddev, perc99, perc95 := getResponseTimes(totalTimes)
fmt.Println("Rate test concluded...") fmt.Println("Rate test concluded...")
fmt.Println("Total Requests:", len(totalTimesFloat))
fmt.Println("Error Rate:", errorRate, "ms")
fmt.Println("Mean:", mean, "ms")
fmt.Println("Standard Deviation:", stddev, "ms")
fmt.Println("95 Percentile:", perc95, "ms")
fmt.Println("99 Percentile:", perc99, "ms")
} }

View File

@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"sync"
"time" "time"
) )
@ -15,7 +14,7 @@ returns err from database connection
*/ */
func newPool(host string, username string, password string) *redis.Pool { func newPool(host string, username string, password string) *redis.Pool {
return &redis.Pool{ return &redis.Pool{
MaxIdle: 80, MaxIdle: 12000,
MaxActive: 12000, MaxActive: 12000,
Dial: func() (redis.Conn, error) { Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", host) c, err := redis.Dial("tcp", host)
@ -44,7 +43,7 @@ setRateTest sets key/value into database
@param key int redis key for the storage @param key int redis key for the storage
@param value string string for the value to store @param value string string for the value to store
*/ */
func setRedis(rdbPtr *redis.Conn, key int, value string, waitGroup *sync.WaitGroup) { func setRedis(rdbPtr *redis.Conn, key int, value string) {
rdb := *rdbPtr rdb := *rdbPtr
//defer waitGroup.Done() //defer waitGroup.Done()
_, err := rdb.Do("Set", key, value) _, err := rdb.Do("Set", key, value)
@ -61,11 +60,10 @@ buildTestData iterates through a goroutine of setRedis to build test data into t
*/ */
func buildTestData(rdbPtr *redis.Conn, size int) { func buildTestData(rdbPtr *redis.Conn, size int) {
fmt.Println("Initializing Test Data...") fmt.Println("Initializing Test Data...")
var waitGroup sync.WaitGroup for i := 1; i < size; i++ {
for i := 1; i < 50000; i++ {
key := i key := i
value := "ThisIsATestStringThatShouldBeReplacedWithSomethingMoreRandomMaybeFromAnInputOrCSV" value := "ThisIsATestStringThatShouldBeReplacedWithSomethingMoreRandomMaybeFromAnInputOrCSV"
setRedis(rdbPtr, key, value, &waitGroup) setRedis(rdbPtr, key, value)
} }
fmt.Println("Database Initialized...") fmt.Println("Database Initialized...")
} }
@ -75,10 +73,14 @@ getRedis queries the redis database for value of key
@param rdbPtr connection is a pointer to the redis connection @param rdbPtr connection is a pointer to the redis connection
@param key int is key value to query in database @param key int is key value to query in database
*/ */
func getRedis(rdbPtr *redis.Conn, key int) { func getRedis(rdbPtr *redis.Conn, key int, timesChan chan time.Duration, errorChan chan bool) {
rdb := *rdbPtr rdb := *rdbPtr
startTime := time.Now()
_, err := rdb.Do("Get", key) _, err := rdb.Do("Get", key)
responseTime := time.Now().Sub(startTime)
if err != nil { if err != nil {
errorChan <- true
fmt.Println("Unhandled error:", err) fmt.Println("Unhandled error:", err)
} }
timesChan <- responseTime
} }

View File

@ -21,11 +21,11 @@ func main() {
passwordPtr := flag.String("password", "", "Redis user password") passwordPtr := flag.String("password", "", "Redis user password")
//dbPtr := flag.Int("db", 0, "Redis db, default 0") //dbPtr := flag.Int("db", 0, "Redis db, default 0")
initializeDBPtr := flag.Bool("initialize", false, "Boolean initialize db, default false") initializeDBPtr := flag.Bool("initialize", false, "Boolean initialize db, default false")
ratePtr := flag.Int("rate", 5, "Test rate limit, default 50/sec") ratePtr := flag.Int("rate", 50, "Test rate limit, default 30/sec")
burstPtr := flag.Bool("burst", false, "Boolean burst test default true") burstPtr := flag.Bool("burst", true, "Boolean burst test default true")
//todo this should be off that same csv rather than an input //todo this should be off that same csv rather than an input
maxEntriesPtr := flag.Int("dbEntries", 50000, "Test rate limit, default 50/sec") maxEntriesPtr := flag.Int("dbEntries", 50000, "Test rate limit, default 50/sec")
testDurationPtr := flag.Int("duration", 10, "Duration of each test") testDurationPtr := flag.Int("duration", 50, "Duration of each test")
flag.Parse() flag.Parse()
host := *hostPtr host := *hostPtr
@ -46,7 +46,17 @@ func main() {
if initializeDB { if initializeDB {
buildTestData(&client, 50000) buildTestData(&client, 50000)
} }
client.Close()
//refreshing state for next test
pool = newPool(host, username, password)
client = pool.Get()
defer client.Close()
getRateTest(&client, rate, keyMaxValue, duration) getRateTest(&client, rate, keyMaxValue, duration)
client.Close()
//refreshing state for next test
pool = newPool(host, username, password)
client = pool.Get()
defer client.Close()
if burst { if burst {
getBurstTest(&client, rate, keyMaxValue, duration) getBurstTest(&client, rate, keyMaxValue, duration)
} }

View File

@ -1,6 +1,20 @@
package main package main
import "github.com/montanaflynn/stats" import (
"github.com/montanaflynn/stats"
"time"
)
/**
intToFloat takes []int64 and converts it to []float64 for processing
*/
func intToFloat(times []int64) []float64 {
var floatArray []float64
for timeRange := range times {
floatArray = append(floatArray, float64(timeRange))
}
return floatArray
}
/** /**
getResponseTimes takes a list of ints and returns mean, stddev, 95p, 99p getResponseTimes takes a list of ints and returns mean, stddev, 95p, 99p
@ -14,8 +28,16 @@ func getResponseTimes(times []float64) (float64, float64, float64, float64) {
return mean, stddev, perc99, perc95 return mean, stddev, perc99, perc95
} }
func keepTotal(timesChan chan float64, errorChan chan bool, endChan chan bool) ([]float64, int) { /**
var timesSlice []float64 keepTotal takes several channels and keeps a running total of
duration and errors
*/
func keepTotal(timesChan chan time.Duration,
errorChan chan bool,
endChan chan bool,
totalTimeChan chan []int64,
totalErrorChan chan int) {
var timesSlice []int64
var errorRate int var errorRate int
end := false end := false
for { for {
@ -24,14 +46,16 @@ func keepTotal(timesChan chan float64, errorChan chan bool, endChan chan bool) (
} }
select { select {
case timeValue := <-timesChan: case timeValue := <-timesChan:
timesSlice = append(timesSlice, timeValue) typedTimeValue := int64(1) * timeValue.Microseconds()
timesSlice = append(timesSlice, typedTimeValue)
case <-errorChan: case <-errorChan:
errorRate++ errorRate += 1
case <-endChan: case <-endChan:
if len(errorChan) == 0 && len(timesChan) == 0 { if len(errorChan) == 0 && len(timesChan) == 0 {
end = true end = true
} }
} }
} }
return timesSlice, errorRate totalTimeChan <- timesSlice
totalErrorChan <- errorRate
} }