Go Redis

Go Redis

Go語言連接Redis庫,常用的庫 redisgogo-redis

https://github.com/gomodule/redigo

https://github.com/go-redis/redis

新項目更建議直接使用go-redis,它對集羣和哨兵模式支持更好

gorm

http://gorm.book.jasperxu.com/crud.html#c

redigo 基本使用

# 安裝redigo
go get github.com/gomodule/redigo/redis

連接redis

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
)

func main() {
	conn,err := redis.Dial("tcp","127.0.0.1:6379")
	if err != nil{
		fmt.Println("connect redis error:",err.Error())
		return
	}

	fmt.Println("connect redis success  ...")
	defer conn.Close()


}

redigo 操作

conn.Do(redis命令),它的命令與redis命令行一致,只要知道redis如何操作,填入Do中即可。

比如

redis> SET name “sun”

go> conn.Do(“SET”, “name”, “sun”)

獲取到的值,使用redis.String()轉換一下,如果是其他類型,也使用redis.StringMap redis.Int64

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
)

func main() {
	conn,err := redis.Dial("tcp","127.0.0.1:6379")
	if err != nil{
		fmt.Println("connect redis error:",err.Error())
		return
	}

	fmt.Println("connect redis success  ...")
	defer conn.Close()

	_, err = conn.Do("SET", "name", "sun")
	if err != nil{
		fmt.Println("redis set error",err.Error())
		return
	}

	name,err := redis.String(conn.Do("GET", "name"))
	if err != nil{
		fmt.Println("redis get error",err.Error())
		return
	} else {
		fmt.Println("redis get name",name)
	}

}

pipeline

管道批量操作

conn.Send(command1)

conn.Send(command1)

conn.Send(command1)

conn.Flush()

res1,err := conn.Receive()

res2,err := conn.Receive()

res3,err := conn.Receive()

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
)

func main() {
	conn,err := redis.Dial("tcp","127.0.0.1:6379")
	if err != nil{
		fmt.Println("connect redis error:",err.Error())
		return
	}

	fmt.Println("connect redis success  ...")
	defer conn.Close()

	_, err = conn.Do("SET", "name", "sun")
	if err != nil{
		fmt.Println("redis set error",err.Error())
		return
	}

    conn.Send("HSET","user","name","sun","age","30")
    conn.Send("HSET","user","sex","female")
    conn.Send("HGET","user",'age')
    conn.Flush()
    res1,err := conn.Receive()
    fmt.Printf("Receive res:%v\n",res1)
    res2,err := conn.Receive()
    fmt.Printf("Receive res:%v\n",res2)
    res3,err := conn.Receive()
    fmt.Printf("Receive res:%v\n",res3)

}

如果檢查命令沒有問題,可能是redis版本過低,請升級版本。

ERR wrong number of arguments for 'hset' command

發佈/訂閱模式

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
	"time"
)

// 訂閱,接收消息
func Subscribe()  {

	// 連接redis
	conn,err := redis.Dial("tcp","127.0.0.1:6379")
	if err != nil{
		fmt.Println("connect redis error:",err.Error())
		return
	}
	defer conn.Close()

	psc := redis.PubSubConn{conn}
	psc.Subscribe("channel001") //訂閱channel001頻道
	for {
		switch v:=psc.Receive().(type) {
		case redis.Message:
			msg := string(v.Data)
			fmt.Println("redis.message",v.Channel,msg)
		case redis.Subscription:
			fmt.Println("redis.Subscription",v.Channel,v.Kind,v.Count)
		case error:
			fmt.Println(v)
			return
		}
	}
}

// 發佈者,發送消息
func Push(message string){
	conn,_ := redis.Dial("tcp","127.0.0.1:6379")
	defer conn.Close()
	_,err := conn.Do("PUBLISH","channel001",message)
	if err != nil {
		fmt.Println("push err",err.Error())
		return
	}
}


func main() {
	go Subscribe()
	time.Sleep(time.Second * 2) // 這裏是防止訂閱者啓動比發佈者慢,啓動後已經沒有push發佈了。
	go Push("this is a message,one .")
	go Push("this is a message,two .")
	time.Sleep(time.Second * 3 )
}

事務操作

MULTI 開啓事務

EXEC 執行事務

DISCARD 取消事務

WATCH 監控事務中的變化,一旦有變化則取消事務

c.Send("MULTI") // 開啓事務
c.Send("INCR", "foo")
c.Send("INCR", "bar")
r, err := c.Do("EXEC") // 執行事務

補充:

https://blog.csdn.net/sxj6977380/article/details/80794256

事務開啓和提交,事務開始和取消,提交後的事務沒有取消的操作。

事務提交後失敗的情況有2種,語法檢測沒通過,則會直接取消

語法檢測通過,但是中間過程報錯,比如字符串的key,用hash的操作,那麼後面的的還會正常執行

watch 監聽某個值,在開啓事務之前,提交/取消後,這個監聽也消失了。

使用連接池

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
	"time"
)


var Pool redis.Pool

func init() {
	Pool = redis.Pool {
		MaxIdle: 16,// 最大空閒連接數
		MaxActive: 16,// 最大激活連接數
		IdleTimeout: 120, //空間連接時間,超過就會斷開
		Dial: func() (redis.Conn, error) {//連接的函數
			c,err := redis.Dial("tcp","127.0.0.1:6379",
				redis.DialConnectTimeout(30 * time.Millisecond),
				redis.DialReadTimeout(50 * time.Millisecond), // 5
				redis.DialWriteTimeout(50 * time.Millisecond))  // 5
			if err != nil{
				fmt.Println(err)
				return nil,err
			}
			return c,nil
		},

	}
}

func do_something(){
	conn := Pool.Get()
	defer conn.Close()

	res,err := conn.Do("HSET","user","like","ball")
	fmt.Println(res,err)

	res1,err := redis.String(conn.Do("HGET","user","like"))
	fmt.Println(res1,err)
}

func main() {
	do_something()
}

數據庫認真/切換/連接檢測

c.Do("AUTH",password)
c.Do("SELECT",dbnum)
c.Do("PING")

go-redis

注意:哨兵和集羣是go-redis的,不是上面的redigo

https://github.com/go-redis/redis

哨兵模式

https://blog.csdn.net/busai2/article/details/81449422

集羣模式

16384個槽,爲什麼?

Redis 應用

ZSET : 榜單,排行榜,定時任務

INCR : 點贊

LIST : 管理後臺發送通知郵件短信

SET :去重

緩存:緩存熱點數據,緩存擊穿/雪崩/穿透

更多應用場景,推薦書籍 <Redis開發與運維> <Redis實戰>

緩存穿透:
查詢的數據 redis沒有,mysql也沒有,導致每次請求都會達到mysql
查詢爲空也短暫緩存 + 布隆過濾器



緩存雪崩
同一時間,大量redis-key過期,導致請求到達mysql
key的過期時間隨機波動性



緩存擊穿
大量請求 正好訪問一個恰巧過期的key
限流,二級緩存

優化技巧

  • key 儘量都要有過期時間
  • 一級key不要太多
  • big key 儘量少
  • key 分級 shop:userinfo:1000 shop:userinfo:2000
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章