用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))

}
相關文章
相關標籤/搜索