目前主要的两个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)) }