為什麼要使用連線池
一個資料庫伺服器只擁有有限的連線資源,一旦所有的連線資源都在使用,那麼其它需要連線的資源就只能等待釋放連線資源。所以,在連線資源有限的情況下,提高單位時間的連線的使用效率,縮短連線時間,就能顯著縮短請求時間。
所以就有了連線池的概念,在初始化時,建立一定數量的連線,先把所有連線存起來,然後,誰需要使用,從這裡取走,幹完活立馬放回來。 如果請求數超出連線池容量,那麼就排隊等待或者直接丟棄掉。這樣就可以省掉每次都建立和關閉連線的資源消耗和時間。
如果不使用連線池,那麼,每次傳輸資料,我們都需要耗費大量的系統資源進行建立連線,收發資料,關閉連線。很明顯,重複建立連線 關閉連線這樣的消耗是可以節省。
怎麼使用Redis連線池
先看下簡單的使用案例。
首先當然是下載類庫包
go get github.com/gomodule/redigo/redis
貼下簡單的使用程式碼
package main
import (
red "github.com/gomodule/redigo/redis"
"time"
"fmt"
)
type Redis struct {
pool *red.Pool
}
var redis *Redis
func initRedis() {
redis = new(Redis)
redis.pool = &red.Pool{
MaxIdle: 256,
MaxActive: 0,
IdleTimeout: time.Duration(120),
Dial: func() (red.Conn, error) {
return red.Dial(
"tcp",
"127.0.0.1:6379",
red.DialReadTimeout(time.Duration(1000)*time.Millisecond),
red.DialWriteTimeout(time.Duration(1000)*time.Millisecond),
red.DialConnectTimeout(time.Duration(1000)*time.Millisecond),
red.DialDatabase(0),
//red.DialPassword(""),
)
},
}
}
func Exec(cmd string, key interface{}, args ...interface{}) (interface{}, error) {
con := redis.pool.Get()
if err := con.Err(); err != nil {
return nil, err
}
defer con.Close()
parmas := make([]interface{}, 0)
parmas = append(parmas, key)
if len(args) > 0 {
for _, v := range args {
parmas = append(parmas, v)
}
}
return con.Do(cmd, parmas...)
}
func main() {
initRedis()
Exec("set","hello","world")
fmt.Print(2)
result,err := Exec("get","hello")
if err != nil {
fmt.Print(err.Error())
}
str,_:=red.String(result,err)
fmt.Print(str)
}
使用類庫操作連線池就比較簡單,只要從連線池獲取一個連線,進行資料操作,然後關閉連線。連線池對連線的建立 回收等的管理,都是連線池內部實現。
執行看下結果是不是預想的
go build -o test_web.bin
./test_web.bin
2world
結果跟預想的一毛一樣
基本配置說明
MaxIdle:最大的空閒連線數,表示即使沒有redis連線時依然可以保持N個空閒的連線,而不被清除,隨時處於待命狀態。
MaxActive:最大的連線數,表示同時最多有N個連線。0表示不限制。
IdleTimeout:最大的空閒連線等待時間,超過此時間後,空閒連線將被關閉。如果設定成0,空閒連線將不會被關閉。應該設定一個比redis服務端超時時間更短的時間。
DialConnectTimeout:連線Redis超時時間。
DialReadTimeout:從Redis讀取資料超時時間。
DialWriteTimeout:向Redis寫入資料超時時間。
連線流程大概是這樣的
1.嘗試從空閒列表MaxIdle中,獲得一個可用連線;如果成功直接返回,失敗則嘗試步驟2
2.如果當前的MaxIdle < 連線數 < MaxActive,則嘗試建立一個新連線,失敗則嘗試步驟3
- 如果連線數 > MaxActive就等待,直到滿足步驟2的條件,重複步驟2
遇到過的問題
目前為止,連線池的問題只遇到過一次問題,而且是在測試環境的,當時的配置是
DialConnectTimeout:time.Duration(200)*time.Millisecond
DialReadTimeout:time.Duration(200)*time.Millisecond
DialWriteTimeout:time.Duration(200)*time.Millisecond
配置的都是200毫秒。有一次使用hgetall的時候,就一直報錯,大概類似下面的提示
read tcp 127.0.0.1:6379: i/o timeout
字面意思就是 read tcp 超時,可能某些寫入大點資料的時候也會報,write tcp timeout。
後來將讀寫超時時間都改為1000毫秒,就再也沒有出現過類似的報錯。
當然了,想了解更多的Redis使用,可以看下官方的文件,裡面有各種情況的各種說明。
https://github.com/gomodule/redigo/