golang redis連接池的使用

作爲一個phper,第一次聽到連接池還有點蒙圈,轉golang開發後連接池的概念會經常使用。

一、連接池是什麼

連接池是什麼?一個服務端資源的連接數量都是有限的,每次初始化時他建一定數量的連接,先把所有連接存起來,誰要用則從裏面取,用完後放回去。如果超出連接池容量,要是排隊等着或麼直接丟棄。

比如我們做開發中常用的mysq,redis,php-fpm的配置
1,redis服務端設置
maxclients 最大連接數設置
2, mysql服務端設置
max_connections 最大連接數
3,PHP-FPM 服務端設置
max_children 最大子進程數
start_servers 起始進程數

我們golang開發時連接redis用到自己設計的連接池概念,想要達到的效果是什麼?
1,最大的連接數,最大是爲了控制整個系統連接redis服務端的總數。超過個數量不再與reids進行連接。
2,最大的空閒連接數,最大空閒是想在沒有redis操作時還可以保持的連接個數,這些連接會一直保持與redis服務端的連接(當然如果redis服務端設置了timeout非0,或是你在代碼中手動設置了空閒連接超時間除外)。

二、如何使用Redis連接池

關於go的redis包github裏常用的有兩個:
github.com/gomodule/redigo/redis
github.com/go-redis/redis

“github.com/go-redis/redis” 這個包裏的連接池使用有些模糊,作爲一個golang新手不太建議使用這個包來做連接池的使用。

例子1:go-redis/redis 這個包的簡單使用
package main
import (
	"fmt"
	"github.com/go-redis/redis"
	"time"
)

func main() {
	var addr = "127.0.0.1:6379"
	var password = ""

	c := redis.NewClient(&redis.Options{
		Addr:     addr,
		Password: password,
	})
	p, err := c.Ping().Result()
	if err != nil {
		fmt.Println("redis kill")
	}
	fmt.Println(p)
	c.Do("SET", "key", "duzhenxun")
	rs := c.Do("GET", "key").Val()
	fmt.Println(rs)
	c.Close()
}

例子2: “github.com/gomodule/redigo/redis” 這個包中有連接池的Api,非常好用
package main
import (
	"fmt"
	redigo "github.com/gomodule/redigo/redis"
	"time"
)

func main() {
	var addr = "127.0.0.1:6379"
	var password = ""

	pool := PoolInitRedis(addr, password)
	c1 := pool.Get()
	c2:=pool.Get()
	c3:=pool.Get()
	c4:=pool.Get()
	c5:=pool.Get()
	fmt.Println(c,c2,c3,c4,c5)
	time.Sleep(time.Second * 5)//redis一共有多少個連接??
	c1.Close()
	c2.Close()
	c3.Close()
	c4.Close()
	c5.Close()
	time.Sleep(time.Second*5) //redis一共有多少個連接??

	//下次是怎麼取出來的??
	b1:=pool.Get()
	b2:=pool.Get()
	b3:=pool.Get()
	fmt.Println(b1,b2,b3)
	time.Sleep(time.Second*5)
	b1.Close()
	b2.Close()
	b3.Close()

	//redis目前一共有多少個連接??
	for{
		fmt.Println("主程序運行中....")
		time.Sleep(time.Second*1) 
	}
}

// redis pool
func PoolInitRedis(server string, password string) *redigo.Pool {
	return &redigo.Pool{
		MaxIdle:     2,//空閒數
		IdleTimeout: 240 * time.Second,
		MaxActive:   3,//最大數
		Dial: func() (redigo.Conn, error) {
			c, err := redigo.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redigo.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

三、參數配置說明

MaxIdle:最大空閒連接數,沒有redis操作進依然可以保持這個連接數量
MaxActive:最大連接數。同一時間最多有這麼多的連接

一般go程序運行時選設置redis連接池的初始化。假如我們設置MaxIdle:2,MaxActive:3時。
連接時:調用pool.Get()時,先從MaxIdle中取出可用連接,如果失敗,則看當前設置的MaxActive是否有超出最大數,沒有超出則創建一個新的連接。
斷開時:調用c.Close() 後,看當前連接數,如果比MaxIdle設置的數量大,則關閉redis連接。反之將連接放回到連接池中。大體如下流程圖所示:
圖1 獲取redis連接

圖2 關閉redis連接

四、分析與實驗

例子2中,程序啓動時休息的5秒裏,我們先看一下redis中的當前的連接數,當前連接數只有1個,這個是當前cli的連接。說明go還沒有和redis進行連接。我們可以通過info clients 或client list來查看當前redis連接情況。

redis-cli
//當前客戶端連接數
127.0.0.1:6379> info clients
# Clients
connected_clients:1

我們get了5次,想是取出5個連接,但我們所設置的MaxActive是3,那redis最大連接數只有3個:

c1 :=pool.Get()
c2:=pool.Get()
c3:=pool.Get()
c4:=pool.Get()
c5:=pool.Get()

可以在redis中使用 info clients 命令查看

127.0.0.1:6379> info clients
# Clients
connected_clients:4 (這裏顯示4個是因爲本身自己的cli連接redis時會有一個連接)

調用關閉接口,發現雖然是關閉了5次。但最終還有2個連接沒有關閉。因爲我們設置的MaxIdle是2

c1.Close()
c2.Close()
c3.Close()
c4.Close()
c5.Close()

可以在redis中使用 info clients 命令查看

127.0.0.1:6379> info clients
# Clients
connected_clients:3 (這裏顯示3個是因爲本身自己的cli連接redis時會有一個連接)

以上就是我對redis連接池的使用筆記,由於初次嘗試使用可能有的地方講的不對,還請多多指教。微信號:5552123

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章