我有一个应用程序,大约每秒读取400次,每秒100次写入redis (驻留在redislabs上)。应用程序使用github.com/garyburd/redigo包作为redis代理。
我有两个函数,它们是唯一用来读写的:
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个连接,这听起来不太像。
我试着使用pool的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:问题通过应用下面的答案中建议的内容来解决!
池init的新代码:
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()
}
}发布于 2016-06-15 07:22:34
DialTimeout的连接设置一个超时。TestOnBorrow函数来消除死连接,特别是在超时的情况下。如果连接空闲超过3秒(函数接收空闲时间作为参数),则通常执行PING操作。MaxIdle设置为更大的数目,我记得在池中增加该参数解决了池的问题。https://stackoverflow.com/questions/37828284
复制相似问题