目前主要的兩個go語言的redis庫主要是redigo和radix。最近想用go實現一個redis的鏈接池,看了一下網上的demo,基本都是直接套用的redigo的方法。實現很簡單,以下:git
func newPool(server, password string) *redis.Pool { return &redis.Pool{ MaxIdle: 3, IdleTimeout: 240 * time.Second, Dial: func () (redis.Conn, error) { c, err := redis.Dial("tcp", server) if err != nil { return nil, err } if _, err := c.Do("AUTH", password); err != nil { c.Close() return nil, err } return c, err }, TestOnBorrow: func(c redis.Conn, t time.Time) error { _, err := c.Do("PING") return err }, } } var ( pool *redis.Pool redisServer = flag.String("redisServer", ":6379", "") redisPassword = flag.String("redisPassword", "", "") ) func main() { flag.Parse() pool = newPool(*redisServer, *redisPassword) }
這是從網上copy過來的鏈接池實現,很簡單,直接使用redis.Pool,設置各項參數便可正常運做。github
接下里這個demo是我我的實現的,可能沒redis.Pool配置那麼全面,簡單實現了下鏈接池的各項功能。redis
library包以下:tcp
package library import ( "errors" "github.com/garyburd/redigo/redis" ) const ( DEFAULT_MAX_ACTIVE = 20 DEFAULT_MAX_IDLE = 10 ) //go redis 結構 type Godis struct { Server string Options map[string]string } type RedisPool struct { max_active int max_idle int current_idle int //關於pool究竟用何種類型來存儲 一開始使用的map,可是脫離了池的概念更像一個單例 後來使用slice,可是沒法標記當前鏈接的狀態,是否被佔用 Pool chan redis.Conn } //redis鏈接 func (config Godis) connect() (redis.Conn, error) { // var option_auth redis.DialOption // if auth, ok := config["auth"]; ok { // if auth != "" { // option_auth = redis.DialPassword(auth) // } // } // option_connecttime := redis.DialConnectTimeout(time.Microsecond * 3000) conn, err := redis.Dial("tcp", config.Server) if err != nil { return nil, err } if auth, ok := config.Options["auth"]; ok { if auth != "" { if _, err := conn.Do("AUTH", auth); err != nil { conn.Close() return nil, err } } } return conn, nil } //初始化pool的各項參數 func (p *RedisPool) InitPool(active_num int, idle_num int) { if active_num <= 0 { active_num = DEFAULT_MAX_ACTIVE } if idle_num > active_num { idle_num = active_num / 2 } p.max_active = active_num p.max_idle = idle_num p.current_idle = 0 //設置跟池子同樣大的緩衝 若是沒有緩衝就只是單例的鏈接了 p.Pool = make(chan redis.Conn, active_num) } //獲取池子中的鏈接 func (p *RedisPool) Get() (redis.Conn, error) { if p.current_idle == 0 { err := errors.New("has no available resource!!") return nil, err } p.current_idle-- return <-p.Pool, nil } //添加鏈接 func (p *RedisPool) PutPool(config Godis) error { //pool已經滿了 if len(p.Pool) >= p.max_active { err := errors.New("pool is full") return err } if p.current_idle >= p.max_idle { err := errors.New("idle resource is too much!!") return err } conn, err := config.connect() if err != nil { return err } p.current_idle++ p.Pool <- conn return nil } func (p *RedisPool) PutConn(conn redis.Conn) error { //pool已經滿了 if len(p.Pool) >= p.max_active { err := errors.New("pool is full") return err } if p.current_idle >= p.max_idle { err := errors.New("idle resource is too much!!") return err } p.current_idle++ p.Pool <- conn return nil } //刪除鏈接 func (p *RedisPool) RemovePool() error { if p.current_idle > 0 { conn := <-p.Pool p.current_idle-- return conn.Close() } return nil }
main包:code
package main import ( "fmt" "library" "time" ) func main() { redisConfig := library.Godis{Server: "101.138.97.217:1578", Options: make(map[string]string)} redisConfig.Options["auth"] = "xxxxxxxxxxx" //初始化鏈接池 pool := new(library.RedisPool) pool.InitPool(10, 5) go func() { for i := 0; i < 5; i++ { err := pool.PutPool(redisConfig) if err != nil { fmt.Println(err) } } }() //主協程等待20毫秒再進行 time.Sleep(time.Millisecond * 20) //從池子中取出鏈接來操做redis conn, err := pool.Get() if err != nil { fmt.Println(err) return } dbsize, err := conn.Do("dbsize") fmt.Println(dbsize) pool.PutConn(conn) //用完以後放回到池子中 fmt.Println(len(pool.Pool)) }