redis (redislabs でホストされている) に対して、1 秒あたり約 400 回の読み取りと 1 秒あたり 100 回の書き込みを行うアプリケーションがあります。アプリケーションはgithub.com/garyburd/redigo
パッケージを redis プロキシとして使用しています。
読み取りと書き込みに使用される唯一の関数が2つあります。
func getCachedVPAIDConfig(key string) chan *cachedVPAIDConfig {
c := make(chan *cachedVPAIDConfig)
go func() {
p := pool.Get()
defer p.Close()
switch p.Err() {
case nil:
item, err := redis.Bytes(p.Do("GET", key))
if err != nil {
c <- &cachedVPAIDConfig{nil, err}
return
}
c <- &cachedVPAIDConfig{item, nil}
default:
c <- &cachedVPAIDConfig{nil, p.Err()}
return
}
}()
return c
}
func setCachedVPAIDConfig(key string, j []byte) chan error {
c := make(chan error)
go func() {
p := pool.Get()
defer p.Close()
switch p.Err() {
case nil:
_, err := p.Do("SET", key, j)
if err != nil {
c <- err
return
}
c <- nil
default:
c <- p.Err()
return
}
}()
return c
}
ご覧のとおり、推奨される接続プーリング メカニズム ( http://godoc.org/github.com/garyburd/redigo/redis#Pool ) を使用しています。
アプリケーションのエンドポイントが取得するすべての http 要求でこれらの関数を呼び出しています。問題は、アプリケーションがリクエストの取得を開始すると、すぐにエラーをスローし始めることです。
dial tcp 54.160.xxx.xx:yyyy: connect: cannot assign requested address
(54.160.xxx.xx:yyyy は redis ホストです)
これが発生し始めたとき、約 600 の接続しかないことを redis で確認しましたが、これはそれほど多くないように思えます。
MaxActive
の設定で遊んでみましたpool
が、1000 から 50K の間のどこかに設定しましたが、結果は同じです。
何か案は?
編集
これが私のプール初期化コードです(これを で実行しますfunc init
):
pool = redis.Pool{
MaxActive: 1000, // note: I tried changing this to 50K, result the same
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", redisHost)
if err != nil {
return nil, err
}
if _, err := c.Do("AUTH", redisPassword); err != nil {
c.Close()
return nil, err
}
return c, err
},
}
編集2: 以下の回答で提案されているものを適用することで問題が解決しました!
プール初期化の新しいコード:
pool = redis.Pool{
MaxActive: 500,
MaxIdle: 500,
IdleTimeout: 5 * time.Second,
Dial: func() (redis.Conn, error) {
c, err := redis.DialTimeout("tcp", redisHost, 100*time.Millisecond, 100*time.Millisecond, 100*time.Millisecond)
if err != nil {
return nil, err
}
if _, err := c.Do("AUTH", redisPassword); err != nil {
c.Close()
return nil, err
}
return c, err
},
}
この新しい init により、get および set タイムアウトが redigo によって内部的に処理されるようになるため、getCachedVPAIDConfig および setCachedVPAIDConfig 関数でチャネルを返す必要がなくなりました。これは彼らが今どのように見えるかです:
func setCachedVPAIDConfig(key string, j []byte) error {
p := pool.Get()
switch p.Err() {
case nil:
_, err := p.Do("SET", key, j)
p.Close()
return err
default:
p.Close()
return p.Err()
}
}
func getCachedVPAIDConfig(key string) ([]byte, error) {
p := pool.Get()
switch p.Err() {
case nil:
item, err := redis.Bytes(p.Do("GET", key))
p.Close()
return item, err
default:
p.Close()
return nil, p.Err()
}
}