用redigo本身实现一个redis链接池

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

}
相关文章
相关标签/搜索