今天要進入到,web屆,講到快取一定會提到的 redis 。 redis 真的是一種通用武器,不管你後端用什麼語言,還真沒看過沒人不會用 redis ,那當然我們就要介紹一下 redis 的基礎使用。

gomodule/redigo

這個套件,是我從寫 go 以來,只要是用碰到 redis 的相關應用,我一定會使用的第三方套件,它的主要維護者 Gary Burd,也是我前幾天介紹的 gorilla/mux的 gorilla 團隊另一個套件 gorilla/websocket 主要貢獻者,這個套件後面章節會介紹,我們接下來介紹他的基礎使用方式。

建構 connection pool

func main() {
	pool := &redis.Pool{
		// 連線的 callback 定義
		Dial: func() (redis.Conn, error) {

			//建構一條連線
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}

			//在這邊可以做連線池初始化 選擇 redis db的動作
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				return nil, err
			}
			return c, nil
		},

		//定期對 redis server 做 ping/pong 測試
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
	}

}

使用連線

func main() {
	pool := &redis.Pool{
		// 連線的 callback 定義
		Dial: func() (redis.Conn, error) {

			//建構一條連線
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}

			//在這邊可以做連線池初始化 選擇 redis db的動作
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				return nil, err
			}
			return c, nil
		},

		//定期對 redis server 做 ping/pong 測試
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
	}

	//這邊要非常注意,redis用完連線,請一定要做close的動作,否則有機會造成 memory leak

	// close完的連線,會回到 connection pool
	conn := pool.Get()
	defer conn.Close()

	var value1 int
	var value2 string

	//這是package 提供的 helper
	reply, err := redis.Values(conn.Do("MGET", "key1", "key2"))
	if err != nil {
		// handle error
	}

	//這是package提供的helper 幫助可以scan 相關數值
	if _, err := redis.Scan(reply, &value1, &value2); err != nil {
		// handle error
	}

}

上面範例只有一個重點,請大家多多使用 redigo 提供的 connection pool,可以幫助你控管連線,而且也要記得每次使用完 conn ,也都要記得做 close,釋放連線。

pub/sub

在 redis 裡面,如果善用這個功能,就可以做到 event trigger 這個模式,而不是透過傳統輪詢的方式,來關注你的服務狀態是否已經改變。後面章節,會有一篇分享,我運用 redis 在架構面的設計。

func main() {
	pool := &redis.Pool{
		// 連線的 callback 定義
		Dial: func() (redis.Conn, error) {

			//建構一條連線
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}

			//在這邊可以做連線池初始化 選擇 redis db的動作
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				return nil, err
			}
			return c, nil
		},

		//定期對 redis server 做 ping/pong 測試
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
	}

	//這邊要非常注意,redis用完連線,請一定要做close的動作,否則有機會造成 memory leak

	// close完的連線,會回到 connection pool
	conn := pool.Get()
	defer conn.Close()

	//這邊運用 pub/sub helper
	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("example")
	for {
		switch v := psc.Receive().(type) {
		case redis.Message:
			fmt.Printf("%s: message: %s\n", v.Channel, v.Data)
		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)
		case error:
			return v
		}
	}

}

這邊只是做基礎的 redis 應用介紹,需要更多說明,請到官方文件