目前主要的两个go语言的redis库主要是redigo和radix。最近想用go实现一个redis的连接池,看了一下网上的demo,基本都是直接套用的redigo的方法。实现很简单,如下:
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,设置各项参数即可正常运作。
接下里这个demo是我个人实现的,可能没redis.Pool配置那么全面,简单实现了下连接池的各项功能。
library包如下:
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包:
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))
}