2016-08-31 14 views
0

私のgoプログラムをredisにライブラリredigoを使用して接続しています。 1つのリクエストを実行すると、正しい結果が得られます。要求があるとき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 

は、これは私のコードです:しかし、負荷テストで、Apacheのベンチマークツールを使用して、それは時に動作します

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)) 
} 

atleast 40の処理方法Apacheのベンチマークツールを使用した同時リクエスト。

:私は私の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 
+0

これはエラーではありません。スタックトレースの一部です。エラー出力、またはスタックトレース全体を表示してください。 – JimB

+0

@JimB質問を更新しました。また、スタックトレースが大きすぎます。私は最後の行を追加しました。 – Jagrati

+1

これは単にgoroutineスタックであり、エラーとは関係ありません。最初に印刷されたスタックトレースの原因と、パニックになっているゴルーチン。 – JimB

答えて

2

は、あなたがコメントで言及したが自分で設定しない、あなたのredis.PoolMaxActiveを設定します。

基本的には、idルックアップごとにゴルーチンをディスパッチしないでください。可能な最大同時実行性は(number of client connections) x (number of ids in the request)で、それぞれが新しいredis接続を開くことができます。 1つの赤線接続をそれぞれidsの順に読み取る方がはるかに高速で効率的です。余分な並行処理の必要はありません。ハンドラからすべてシリアルで処理し、文字列をintに変換しないでください。

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のサーバーへのラウンドトリップを減らすためにpipelinesを使用することができます。

for _, id := range req.Form["ids[]"] { 
    c.Send("HGET", "key", id)) 
} 
c.Flush() 
values, err := redis.Strings(c.Receive()) 
checkError(err) 
... 
+0

です。約80-100です。私はredisに連続して接続する必要がありますか?私はそれがパフォーマンスを低下させると思う。また、パイプラインを使用することについて、あなたは私のコードでどのように使用することができるの例を教えてくれますか? – Jagrati

+0

@Jagrati:はい、すべてのIDを1つの接続で照会し、1500の同時接続を開くとデータベースの競合が増え、パフォーマンスが大幅に低下します。 – JimB

関連する問題