为什么会有连接池这个东西

redis是基于内存的,计算的效率很高,但是网络通信是redis性能提升的瓶颈,如果redis服务器每次都要与客户端随机创立连接然后释放连接,会造成一定性能浪费,执行的效率会大大降低。
连接池的技术就是redis服务端预先开通连接,等客户端需要的时候,直接从连接池里面取出连接,然后使用。不再是当客户端需要的时候再去创建连接了,提高了资源的利用率和访问速度。

说明:通过 Golang对Redis操作, 还可以通过Redis链接池 流程如下:

  • 事先初始化一定数量的链接,放入到链接池
  • 当 Go需要操作Redis时,直接从Redis链接池取出链接即可。
  • 这样可以节省临时获取 Redis 链接的时间,从而提高效率。

image.png

pool.go 源码

  1. type Pool struct {
  2. // Dial is an application supplied function for creating and configuring a
  3. // connection.
  4. //
  5. // The connection returned from Dial must not be in a special state
  6. // (subscribed to pubsub channel, transaction started, ...).
  7. Dial func() (Conn, error)
  8. // DialContext is an application supplied function for creating and configuring a
  9. // connection with the given context.
  10. //
  11. // The connection returned from Dial must not be in a special state
  12. // (subscribed to pubsub channel, transaction started, ...).
  13. DialContext func(ctx context.Context) (Conn, error)
  14. // TestOnBorrow is an optional application supplied function for checking
  15. // the health of an idle connection before the connection is used again by
  16. // the application. Argument t is the time that the connection was returned
  17. // to the pool. If the function returns an error, then the connection is
  18. // closed.
  19. TestOnBorrow func(c Conn, t time.Time) error
  20. // Maximum number of idle connections in the pool.
  21. MaxIdle int
  22. // Maximum number of connections allocated by the pool at a given time.
  23. // When zero, there is no limit on the number of connections in the pool.
  24. MaxActive int
  25. // Close connections after remaining idle for this duration. If the value
  26. // is zero, then idle connections are not closed. Applications should set
  27. // the timeout to a value less than the server's timeout.
  28. IdleTimeout time.Duration
  29. // If Wait is true and the pool is at the MaxActive limit, then Get() waits
  30. // for a connection to be returned to the pool before returning.
  31. Wait bool
  32. // Close connections older than this duration. If the value is zero, then
  33. // the pool does not close connections based on age.
  34. MaxConnLifetime time.Duration
  35. mu sync.Mutex // mu protects the following fields
  36. closed bool // set to true when the pool is closed.
  37. active int // the number of open connections in the pool
  38. initOnce sync.Once // the init ch once func
  39. ch chan struct{} // limits open connections when p.Wait is true
  40. idle idleList // idle connections
  41. waitCount int64 // total number of connections waited for.
  42. waitDuration time.Duration // total time waited for new connections.
  43. }

核心代码:

  1. var pool *redis.Pool
  2. // 初始化连接池
  3. pool = &redis.Pool{
  4. MaxIdle: 8, //最大空闲链接数
  5. MaxActive: 0, //表示和数据库的最大链接数,0表示没有限制
  6. IdleTimeout: 100, //最大空闲时间
  7. Dial: func() (redis.Conn, error) { // 初始化链接的代码,链接哪个ip的redis
  8. return redis.Dial("tcp", "localhost:6379")
  9. },
  10. }
  11. c := pool.Get() // 从连接池中取出一个链接
  12. pool.Close() // 关闭连接池,一旦关闭链接池,就不能从链接池连接

代码体验

  1. // redis 连接池
  2. package main
  3. import (
  4. "fmt"
  5. "github.com/gomodule/redigo/redis"
  6. )
  7. // 定义一个全局的 pool
  8. var pool *redis.Pool
  9. // 当启动程序时,初始化连接池
  10. func init() {
  11. pool = &redis.Pool{
  12. MaxIdle: 8, //最大空闲链接数
  13. MaxActive: 0, //表示和数据库的最大链接数,0表示没有限制
  14. IdleTimeout: 100, //最大空闲时间
  15. Dial: func() (redis.Conn, error) { // 初始化链接的代码,链接哪个ip的redis
  16. return redis.Dial("tcp", "localhost:6379")
  17. },
  18. }
  19. }
  20. func main() {
  21. fmt.Printf("pool 类型: %T, 值: %v \n", pool, pool)
  22. // 1. 先从 pool 里面取出连接
  23. conn := pool.Get()
  24. // conn 类型: *redis.activeConn, 值: &{0xc000070500 0xc0000aa000 0}
  25. fmt.Printf("conn 类型: %T, 值: %v \n", conn, conn)
  26. defer conn.Close()
  27. // 2. 操作
  28. _, err := conn.Do("Set", "watch", "xiaomi")
  29. if err != nil {
  30. fmt.Println("操作失败", err)
  31. return
  32. }
  33. val, err := redis.String(conn.Do("Get", "watch"))
  34. if err != nil {
  35. fmt.Println("操作失败", err)
  36. return
  37. }
  38. fmt.Println("val =", val)
  39. // 关闭连接池, 不能再继续读写了
  40. pool.Close()
  41. conn2 := pool.Get()
  42. fmt.Println("conn2=", conn2)
  43. _, err = conn2.Do("Set", "watch2", "xiaomi222")
  44. if err != nil {
  45. // Set()操作失败 redigo: get on closed pool
  46. fmt.Println("Set()操作失败", err)
  47. return
  48. }
  49. val, err = redis.String(conn2.Do("Get", "watch2"))
  50. if err != nil {
  51. fmt.Println("get操作失败", err)
  52. return
  53. }
  54. fmt.Println("val2 =", val)
  55. }