2016-06-15 120 views
4

我有一個應用程序,每秒鐘約400次讀取和每秒100次寫入redis(託管在redislabs上)。該應用程序使用github.com/garyburd/redigo包作爲redis代理。redigo:獲得撥號tcp:連接:不能分配請求的地址

我有兩個功能,這是正在使用的唯一的讀寫:

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的主機)

我對Redis的看到,只有大約600個連接,當這開始發生時,聽起來不是很多。

我試着玩poolMaxActive設置,設置在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使得它,以便獲取和設置超時由redigo內部處理的,所以我不再需要返回的getCachedVPAIDConfig和setCachedVPAIDConfig funcs中通道。這是他們現在的樣子:

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() 
    } 
} 
+0

請附上池初始化代碼。 –

+0

@Not_a_Golfer完成 – orcaman

回答

2
  1. 你關閉連接發送的通道後,如果信道阻塞你不關閉連接,這將導致你錯誤看到。所以不要只推遲,明確關閉連接。

  2. 我不認爲這是問題,但一個好主意無論 - 設置與DialTimeout的連接超時。

  3. 請確保您有適當的TestOnBorrow函數來擺脫死連接,特別是如果您有超時。我通常做一個PING,如果連接空閒超過3秒(功能接收空閒時間作爲參數)

  4. 嘗試設置MaxIdle以及更大的數字,我記得有池的問題是通過增加池中的參數來解決。

+1

太棒了!你搖滾。增加了爲後代解決這個問題的代碼。 – orcaman