为什么会有连接池这个东西
redis是基于内存的,计算的效率很高,但是网络通信是redis性能提升的瓶颈,如果redis服务器每次都要与客户端随机创立连接然后释放连接,会造成一定性能浪费,执行的效率会大大降低。
连接池的技术就是redis服务端预先开通连接,等客户端需要的时候,直接从连接池里面取出连接,然后使用。不再是当客户端需要的时候再去创建连接了,提高了资源的利用率和访问速度。
说明:通过 Golang对Redis操作, 还可以通过Redis链接池 流程如下:
- 事先初始化一定数量的链接,放入到链接池
- 当 Go需要操作Redis时,直接从Redis链接池取出链接即可。
- 这样可以节省临时获取 Redis 链接的时间,从而提高效率。
pool.go 源码
type Pool struct {
// Dial is an application supplied function for creating and configuring a
// connection.
//
// The connection returned from Dial must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
Dial func() (Conn, error)
// DialContext is an application supplied function for creating and configuring a
// connection with the given context.
//
// The connection returned from Dial must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
DialContext func(ctx context.Context) (Conn, error)
// TestOnBorrow is an optional application supplied function for checking
// the health of an idle connection before the connection is used again by
// the application. Argument t is the time that the connection was returned
// to the pool. If the function returns an error, then the connection is
// closed.
TestOnBorrow func(c Conn, t time.Time) error
// Maximum number of idle connections in the pool.
MaxIdle int
// Maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
MaxActive int
// Close connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
IdleTimeout time.Duration
// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait bool
// Close connections older than this duration. If the value is zero, then
// the pool does not close connections based on age.
MaxConnLifetime time.Duration
mu sync.Mutex // mu protects the following fields
closed bool // set to true when the pool is closed.
active int // the number of open connections in the pool
initOnce sync.Once // the init ch once func
ch chan struct{} // limits open connections when p.Wait is true
idle idleList // idle connections
waitCount int64 // total number of connections waited for.
waitDuration time.Duration // total time waited for new connections.
}
核心代码:
var pool *redis.Pool
// 初始化连接池
pool = &redis.Pool{
MaxIdle: 8, //最大空闲链接数
MaxActive: 0, //表示和数据库的最大链接数,0表示没有限制
IdleTimeout: 100, //最大空闲时间
Dial: func() (redis.Conn, error) { // 初始化链接的代码,链接哪个ip的redis
return redis.Dial("tcp", "localhost:6379")
},
}
c := pool.Get() // 从连接池中取出一个链接
pool.Close() // 关闭连接池,一旦关闭链接池,就不能从链接池连接
代码体验
// redis 连接池
package main
import (
"fmt"
"github.com/gomodule/redigo/redis"
)
// 定义一个全局的 pool
var pool *redis.Pool
// 当启动程序时,初始化连接池
func init() {
pool = &redis.Pool{
MaxIdle: 8, //最大空闲链接数
MaxActive: 0, //表示和数据库的最大链接数,0表示没有限制
IdleTimeout: 100, //最大空闲时间
Dial: func() (redis.Conn, error) { // 初始化链接的代码,链接哪个ip的redis
return redis.Dial("tcp", "localhost:6379")
},
}
}
func main() {
fmt.Printf("pool 类型: %T, 值: %v \n", pool, pool)
// 1. 先从 pool 里面取出连接
conn := pool.Get()
// conn 类型: *redis.activeConn, 值: &{0xc000070500 0xc0000aa000 0}
fmt.Printf("conn 类型: %T, 值: %v \n", conn, conn)
defer conn.Close()
// 2. 操作
_, err := conn.Do("Set", "watch", "xiaomi")
if err != nil {
fmt.Println("操作失败", err)
return
}
val, err := redis.String(conn.Do("Get", "watch"))
if err != nil {
fmt.Println("操作失败", err)
return
}
fmt.Println("val =", val)
// 关闭连接池, 不能再继续读写了
pool.Close()
conn2 := pool.Get()
fmt.Println("conn2=", conn2)
_, err = conn2.Do("Set", "watch2", "xiaomi222")
if err != nil {
// Set()操作失败 redigo: get on closed pool
fmt.Println("Set()操作失败", err)
return
}
val, err = redis.String(conn2.Do("Get", "watch2"))
if err != nil {
fmt.Println("get操作失败", err)
return
}
fmt.Println("val2 =", val)
}