Redigo:在 Apache 负载测试中出现错误
Redigo: getting errors on apache load testing
我正在使用库 redigo
将我的 go
程序连接到 redis
。当我 运行 一个请求时,我得到正确的结果。但是在负载测试中,使用 apache 基准测试工具,它在以下情况下工作:
ab -n 1000 -k -c 10 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
但是当请求是:
ab -n 1000 -k -c 15 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
我收到错误:
panic: dial tcp :6379: too many open files
这是我的代码:
func newPool() *redis.Pool {
return &redis.Pool{
MaxIdle: 80, // max number of connections
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", ":6379")
if err != nil {
panic(err.Error())
}
return c, err
},
// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning
Wait: true,
}
}
var pool = newPool()
func checkError(err error) {
if err != nil {
log.Fatal(err)
}
}
func func1(pool *redis.Pool, id int) string {
c := pool.Get()
defer c.Close()
m, err := redis.String(c.Do("HGET", "key", id))
checkError(err)
return m
}
func func2(pool *redis.Pool, string_ids []string) chan string {
c := make(chan string)
var ids []int
var temp int
for _, v := range string_ids {
temp, _ = strconv.Atoi(v)
ids = append(ids, temp)
}
go func() {
var wg sync.WaitGroup
wg.Add(len(ids))
for _, v := range ids {
go func(id int) {
defer wg.Done()
c <- func1(pool, id)
}(v)
}
wg.Wait()
close(c)
}()
return c
}
func getReq(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
checkError(err)
ids := req.Form["ids[]"]
for v := range func2(pool, ids) {
fmt.Println(v)
}
}
func main() {
http.HandleFunc("/abcd", getReq)
log.Fatal(http.ListenAndServe(":8084", nil))
}
如何使用 apache 基准测试工具处理至少 40 个并发请求。
注意: 我没有在我的redis conf文件中改变任何东西
我在 运行使用 Apache 基准测试工具时收到以下响应。仅完成 15 个请求。
$ ab -n 1000 -k -c 15 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
apr_socket_recv: Connection refused (111)
Total of 15 requests completed
要立即解决问题,请在您的 redis.Pool
上设置 MaxActive
,您在评论中提到了这一点,但您自己并没有设置。
但从根本上说,您不应该为每个 id
查找分配 goroutine。那么您的最大可能并发数将是 (number of client connections) x (number of ids in the request)
,每个都可以打开一个新的 redis 连接。让单个 redis 连接串行读取每个 ids
会更快、更有效。这里不需要任何额外的并发性,从处理程序串行执行所有操作,并且当 redis 仅对字符串键进行操作时,不要将字符串转换为整数。
func getReq(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
checkError(err)
c := pool.Get()
defer c.Close()
for _, id := range req.Form["ids[]"] {
m, err := redis.String(c.Do("HGET", "key", id))
checkError(err)
fmt.Println(id)
}
}
如果你想进一步优化它,你可以使用 pipelines 来减少到 redis 服务器的往返次数。
for _, id := range req.Form["ids[]"] {
c.Send("HGET", "key", id))
}
c.Flush()
values, err := redis.Strings(c.Receive())
checkError(err)
...
我正在使用库 redigo
将我的 go
程序连接到 redis
。当我 运行 一个请求时,我得到正确的结果。但是在负载测试中,使用 apache 基准测试工具,它在以下情况下工作:
ab -n 1000 -k -c 10 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
但是当请求是:
ab -n 1000 -k -c 15 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
我收到错误:
panic: dial tcp :6379: too many open files
这是我的代码:
func newPool() *redis.Pool {
return &redis.Pool{
MaxIdle: 80, // max number of connections
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", ":6379")
if err != nil {
panic(err.Error())
}
return c, err
},
// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning
Wait: true,
}
}
var pool = newPool()
func checkError(err error) {
if err != nil {
log.Fatal(err)
}
}
func func1(pool *redis.Pool, id int) string {
c := pool.Get()
defer c.Close()
m, err := redis.String(c.Do("HGET", "key", id))
checkError(err)
return m
}
func func2(pool *redis.Pool, string_ids []string) chan string {
c := make(chan string)
var ids []int
var temp int
for _, v := range string_ids {
temp, _ = strconv.Atoi(v)
ids = append(ids, temp)
}
go func() {
var wg sync.WaitGroup
wg.Add(len(ids))
for _, v := range ids {
go func(id int) {
defer wg.Done()
c <- func1(pool, id)
}(v)
}
wg.Wait()
close(c)
}()
return c
}
func getReq(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
checkError(err)
ids := req.Form["ids[]"]
for v := range func2(pool, ids) {
fmt.Println(v)
}
}
func main() {
http.HandleFunc("/abcd", getReq)
log.Fatal(http.ListenAndServe(":8084", nil))
}
如何使用 apache 基准测试工具处理至少 40 个并发请求。
注意: 我没有在我的redis conf文件中改变任何东西
我在 运行使用 Apache 基准测试工具时收到以下响应。仅完成 15 个请求。
$ ab -n 1000 -k -c 15 -p post.txt -T application/x-www-form-urlencoded http://localhost:8084/abcd
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
apr_socket_recv: Connection refused (111)
Total of 15 requests completed
要立即解决问题,请在您的 redis.Pool
上设置 MaxActive
,您在评论中提到了这一点,但您自己并没有设置。
但从根本上说,您不应该为每个 id
查找分配 goroutine。那么您的最大可能并发数将是 (number of client connections) x (number of ids in the request)
,每个都可以打开一个新的 redis 连接。让单个 redis 连接串行读取每个 ids
会更快、更有效。这里不需要任何额外的并发性,从处理程序串行执行所有操作,并且当 redis 仅对字符串键进行操作时,不要将字符串转换为整数。
func getReq(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
checkError(err)
c := pool.Get()
defer c.Close()
for _, id := range req.Form["ids[]"] {
m, err := redis.String(c.Do("HGET", "key", id))
checkError(err)
fmt.Println(id)
}
}
如果你想进一步优化它,你可以使用 pipelines 来减少到 redis 服务器的往返次数。
for _, id := range req.Form["ids[]"] {
c.Send("HGET", "key", id))
}
c.Flush()
values, err := redis.Strings(c.Receive())
checkError(err)
...