go - Redigo:在 Apache 负载测试中出现错误

标签 go benchmarking redigo

我正在使用库 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 查找分派(dispatch) goroutine。您的最大可能并发将是 (客户端连接数)x(请求中的 id 数),每个都可以打开一个新的 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)
...

关于go - Redigo:在 Apache 负载测试中出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39244845/

相关文章:

apache - 任何显示 Litespeed 比 Nginx 服务器更快的基准测试?

svn-bench 和 fsfs-stats 二进制使用情况

api - 如何将字符串转换为 time.Time

cuda - 如何测量矩阵乘法内核的 gflops?

go - 如何在 Golang 中处理动态 URL

go - 如何在 golang 中动态命名结构项?

go - 调用 tcp remote_ip :6379: connect: connection timed out

戈朗 : Selecting DB on a RedisPool in Redigo

go - 在 docker 容器中生成一个新进程,该进程是从头开始构建的

gomobile 绑定(bind)你好错误