-1

我正在将我的go程序连接到redisusing library redigo。当我运行一个请求时,我得到了正确的结果。但是在负载测试中,使用 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
4

1 回答 1

2

要立即解决问题,请设置MaxActiveredis.Pool在评论中提到但不要设置自己的 。

但从根本上说,您不应该为每次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)
    }
}

如果您想进一步优化这一点,您可以使用管道来减少到 redis 服务器的往返次数。

for _, id := range req.Form["ids[]"] {
    c.Send("HGET", "key", id))
}
c.Flush()
values, err := redis.Strings(c.Receive())
checkError(err)
...
于 2016-08-31T13:21:02.153 回答