当前位置:网站首页>go-redis之初始化連接
go-redis之初始化連接
2022-07-06 09:08:00 【~龐貝】
目錄
go-redis之初始化連接
安裝
如果您使用的是Redis 6,請安裝 go-redis/ v8:
go get github.com/go-redis/redis/v8
如果您使用的是Redis 7,請安裝 go-redis/ v9(目前處於測試階段):
go get github.com/go-redis/redis/v9
連接到 Redis 服務器
要連接到 Redis 服務器:
import "github.com/go-redis/redis/v8"
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
另一種流行的方法是使用連接字符串:
opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")
if err != nil {
panic(err)
}
rdb := redis.NewClient(opt)
使用 TLS
要啟用 TLS/SSL,您需要提供一個空的tls.Config
. 如果您使用的是私有證書,則需要指定在新窗口中打開他們在tls.Config
.
rdb := redis.NewClient(&redis.Options{
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
//Certificates: []tls.Certificate{cert}
},
})
如果您得到x509: cannot validate certificate for xxx.xxx.xxx.xxx because it doesn't contain any IP SANs
,請嘗試設置ServerName
選項:
rdb := redis.NewClient(&redis.Options{
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: "your.domain.com",
},
})
通過 SSH
通過 SSH 通道連接:
sshConfig := &ssh.ClientConfig{
User: "root",
Auth: []ssh.AuthMethod{
ssh.Password("password")},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 15 * time.Second,
}
sshClient, err := ssh.Dial("tcp", "remoteIP:22", sshConfig)
if err != nil {
panic(err)
}
rdb := redis.NewClient(&redis.Options{
Addr: net.JoinHostPort("127.0.0.1", "6379"),
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
return sshClient.Dial(network, addr)
},
// Disable timeouts, because SSH does not support deadlines.
ReadTimeout: -1,
WriteTimeout: -1,
})
dial tcp: i/o timeout
當 go-redis 無法連接到 Redis 服務器時,您會收到dial tcp: i/o timeout
錯誤消息,例如,當服務器關閉或端口受防火牆保護時。要檢查 Redis 服務器是否正在偵聽端口,請在運行 go-redis 客戶端的主機上運行 telnet 命令:
telnet localhost 6379
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
如果您使用 Docker、Istio 或任何其他服務網格/sidecar,請確保應用程序在容器完全可用後啟動,例如,通過配置健康檢查在新窗口中打開使用 Docker 和holdApplicationUntilProxyStarts
Istio。
Context
每個 Redis 命令都接受一個上下文,您可以使用它來設置超時或傳播一些信息,例如跟踪上下文。
ctx := context.Background()
執行命令
執行命令:
val, err := rdb.Get(ctx, "key").Result()
fmt.Println(val)
或者,您可以保存命令並稍後分別訪問值和錯誤:
get := rdb.Get(ctx, "key")
fmt.Println(get.Val(), get.Err())
執行不支持的命令
要執行任意/自定義命令:
val, err := rdb.Do(ctx, "get", "key").Result()
if err != nil {
if err == redis.Nil {
fmt.Println("key does not exists")
return
}
panic(err)
}
fmt.Println(val.(string))
Do
返回一個Cmd在新窗口中打開有一堆助手可以處理interface{}
價值:
// Text is a shortcut for get.Val().(string) with proper error handling.
val, err := rdb.Do(ctx, "get", "key").Text()
fmt.Println(val, err)
助手的完整列錶:
s, err := cmd.Text()
flag, err := cmd.Bool()
num, err := cmd.Int()
num, err := cmd.Int64()
num, err := cmd.Uint64()
num, err := cmd.Float32()
num, err := cmd.Float64()
ss, err := cmd.StringSlice()
ns, err := cmd.Int64Slice()
ns, err := cmd.Uint64Slice()
fs, err := cmd.Float32Slice()
fs, err := cmd.Float64Slice()
bs, err := cmd.BoolSlice()
redis.Nil
go-redis 導出redis.Nil
錯誤並在 Redis 服務器響應時返回它(nil)
。您可以使用 redis-cli 檢查 Redis 返回的響應。
在下面的示例中,我們使用redis.Nil
來區分空字符串回複和 nil 回複(key 不存在):
val, err := rdb.Get(ctx, "key").Result()
switch {
case err == redis.Nil:
fmt.Println("key does not exist")
case err != nil:
fmt.Println("Get failed", err)
case val == "":
fmt.Println("value is empty")
}
GET
例如,不是唯一返回 nil 回複的命令,BLPOP
也ZSCORE
可以返回redis.Nil
.
Conn
Conn 錶示單個 Redis 連接,而不是連接池。除非特別需要連續的單個 Redis 連接,否則首選從客戶端運行命令。
cn := rdb.Conn(ctx)
defer cn.Close()
if err := cn.ClientSetName(ctx, "myclient").Err(); err != nil {
panic(err)
}
name, err := cn.ClientGetName(ctx).Result()
if err != nil {
panic(err)
}
fmt.Println("client name", name)
redis集群
go-redis 自帶Redis Cluster客戶端在新窗口中打開. 下面,redis.ClusterClient
用於redis.Client
與集群中的每個節點進行通信。每個都redis.Client
維護一個單獨的連接池。
要連接到 Redis 集群:
import "github.com/go-redis/redis/v8"
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
// To route commands by latency or randomly, enable one of the following.
//RouteByLatency: true,
//RouteRandomly: true,
})
迭代分片:
err := rdb.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error {
return shard.Ping(ctx).Err()
})
if err != nil {
panic(err)
}
要迭代主節點,請使用ForEachMaster
. 要遍曆從節點,請使用ForEachSlave
.
要更改某些分片的選項:
rdb := redis.NewClusterClient(&redis.ClusterOptions{
NewClient: func(opt *redis.Options) *redis.NewClient {
user, pass := userPassForAddr(opt.Addr)
opt.Username = user
opt.Password = pass
return redis.NewClient(opt)
},
})
redis哨兵
Redis 服務器客戶端
連接到由Redis Sentinel管理的 Redis 服務器在新窗口中打開:
import "github.com/go-redis/redis/v8"
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "master-name",
SentinelAddrs: []string{
":9126", ":9127", ":9128"},
})
從 v8 開始,您可以使用實驗NewFailoverClusterClient
將只讀命令路由到從節點:
import "github.com/go-redis/redis/v8"
rdb := redis.NewFailoverClusterClient(&redis.FailoverOptions{
MasterName: "master-name",
SentinelAddrs: []string{
":9126", ":9127", ":9128"},
// To route commands by latency or randomly, enable one of the following.
//RouteByLatency: true,
//RouteRandomly: true,
})
Redis 哨兵客戶端
要連接到 Redis Sentinel 本身:
import "github.com/go-redis/redis/v8"
sentinel := redis.NewSentinelClient(&redis.Options{
Addr: ":9126",
})
addr, err := sentinel.GetMasterAddrByName(ctx, "master-name").Result()
redis環
介紹
Ring 是一個 Redis 客戶端,它使用一致的哈希在多個 Redis 服務器(分片)之間分配密鑰。多個 goroutine 並發使用是安全的。
Ring 監控每個分片的狀態並從環中删除死分片。當一個分片上線時,它會被添加回環中。這實現了最大的可用性和分區容錯性,但不同分片甚至客戶端之間沒有一致性。每個客戶端使用客戶端可用的分片,並且在分片狀態更改時不與其他客戶端進行任何協調。
當您需要多個 Redis 服務器進行緩存並且可以容忍其中一個服務器死機時丟失數據時,應該使用 Ring。否則你應該使用Redis Cluster或Redis Server。
快速開始
創建一個包含 3 個分片的 Ring 集群:
import "github.com/go-redis/redis/v8"
rdb := redis.NewRing(&redis.RingOptions{
Addrs: map[string]string{
"shard1": ":7000",
"shard2": ":7001",
"shard3": ":7002",
},
})
然後客戶端可以像往常一樣使用:
if err := rdb.Set(ctx, "foo", "bar", 0).Err(); err != nil {
panic(err)
}
迭代分片:
err := rdb.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error {
return shard.Ping(ctx).Err()
})
if err != nil {
panic(err)
}
每個分片選項
要更改分片連接選項:
rdb := redis.NewRing(&redis.RingOptions{
NewClient: func(opt *redis.Options) *redis.NewClient {
user, pass := userPassForAddr(opt.Addr)
opt.Username = user
opt.Password = pass
return redis.NewClient(opt)
},
})
密鑰分配
默認情况下,Ring 使用Rendezvous在新窗口中打開散列在多個分片上分配密鑰。但是您可以更改默認的一致哈希實現:
import "github.com/golang/groupcache/consistenthash"
ring := redis.NewRing(&redis.RingOptions{
NewConsistentHash: func() {
return consistenthash.New(100, crc32.ChecksumIEEE)
},
})
Redis 通用客戶端
UniversalClient
是一個抽象客戶端,基於提供的選項,代錶 a ClusterClient
、 aFailoverClient
或 single-node Client
。這對於在本地測試特定於集群的應用程序或在不同環境中具有不同客戶端非常有用。
NewUniversalClient
返回一個新的多客戶端。返回客戶端的類型取决於以下條件:
- 如果指定了該選項,則返回
MasterName
哨兵支持。FailoverClient
- 如果數量
Addrs
為 2 或更多,ClusterClient
則返回 a。 - 否則,返回單節點
Client
。
// rdb is *redis.Client.
rdb := NewUniversalClient(&redis.UniversalOptions{
Addrs: []string{
":6379"},
})
// rdb is *redis.ClusterClient.
rdb := NewUniversalClient(&redis.UniversalOptions{
Addrs: []string{
":6379", ":6380"},
})
// rdb is *redis.FailoverClient.
rdb := NewUniversalClient(&redis.UniversalOptions{
Addrs: []string{
":6379"},
MasterName: "mymaster",
})
Golang Redis 管道、WATCH 和事務
使用管道加速 Redis
Redis 管道允許通過使用單個客戶端-服務器-客戶端往返執行多個命令來提高性能。您可以將命令排在管道中,然後像單個命令一樣使用單個寫入 + 讀取操作執行排隊的命令,而不是一個一個地執行 100 個命令。
要使用單個寫入 + 讀取操作執行多個命令:
pipe := rdb.Pipeline()
incr := pipe.Incr(ctx, "pipeline_counter")
pipe.Expire(ctx, "pipeline_counter", time.Hour)
cmds, err := pipe.Exec(ctx)
if err != nil {
panic(err)
}
// The value is available only after Exec is called.
fmt.Println(incr.Val())
或者,您可以在函數退出時使用Pipelined
which 調用:Exec
var incr *redis.IntCmd
cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
incr = pipe.Incr(ctx, "pipelined_counter")
pipe.Expire(ctx, "pipelined_counter", time.Hour)
return nil
})
if err != nil {
panic(err)
}
// The value is available only after the pipeline is executed.
fmt.Println(incr.Val())
管道還返回執行的命令,因此可以遍曆它們以檢索結果:
cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
for i := 0; i < 100; i++ {
pipe.Get(ctx, fmt.Sprintf("key%d", i))
}
return nil
})
if err != nil {
panic(err)
}
for _, cmd := range cmds {
fmt.Println(cmd.(*redis.StringCmd).Val())
}
Transactions 和Watch
使用 Redis事務在新窗口中打開,您可以觀察鍵的變化並僅在觀察的鍵沒有被另一個客戶端更改時才執行管道。這種沖突解决方法也稱為樂觀鎖定
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
TxPipelined
您可以使用and包裝帶有 MULTI 和 EXEC 命令的管道TxPipeline
,但它本身並不是很有用:
cmds, err := rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
for i := 0; i < 100; i++ {
pipe.Get(ctx, fmt.Sprintf("key%d", i))
}
return nil
})
if err != nil {
panic(err)
}
// MULTI
// GET key0
// GET key1
// ...
// GET key99
// EXEC
相反,您應該使用Watch處理事務管道在新窗口中打開,例如,我們可以正確實現INCR在新窗口中打開使用GET
,SET
和WATCH
的命令 請注意我們如何使用redis.TxFailedErr
來檢查事務是否失敗。
// Redis transactions use optimistic locking.
const maxRetries = 1000
// Increment transactionally increments the key using GET and SET commands.
func increment(key string) error {
// Transactional function.
txf := func(tx *redis.Tx) error {
// Get the current value or zero.
n, err := tx.Get(ctx, key).Int()
if err != nil && err != redis.Nil {
return err
}
// Actual operation (local in optimistic lock).
n++
// Operation is commited only if the watched keys remain unchanged.
_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
pipe.Set(ctx, key, n, 0)
return nil
})
return err
}
// Retry if the key has been changed.
for i := 0; i < maxRetries; i++ {
err := rdb.Watch(ctx, txf, key)
if err == nil {
// Success.
return nil
}
if err == redis.TxFailedErr {
// Optimistic lock lost. Retry.
continue
}
// Return any other error.
return err
}
return errors.New("increment reached maximum number of retries")
}
Redis 發布訂閱
go-redis 允許發布消息和訂閱頻道。當出現網絡錯誤時,它還會自動重新連接到 Redis Server。
要發布消息:
err := rdb.Publish(ctx, "mychannel1", "payload").Err()
if err != nil {
panic(err)
}
訂閱頻道:
// There is no error because go-redis automatically reconnects on error.
pubsub := rdb.Subscribe(ctx, "mychannel1")
// Close the subscription when we are done.
defer pubsub.Close()
要接收消息:
for {
msg, err := pubsub.ReceiveMessage(ctx)
if err != nil {
panic(err)
}
fmt.Println(msg.Channel, msg.Payload)
}
但最簡單的方法是使用與訂閱一起關閉的 Go 頻道:
ch := pubsub.Channel()
for msg := range ch {
fmt.Println(msg.Channel, msg.Payload)
}
边栏推荐
- opencv+dlib实现给蒙娜丽莎“配”眼镜
- [MySQL] limit implements paging
- What is an R-value reference and what is the difference between it and an l-value?
- 一改测试步骤代码就全写 为什么不试试用 Yaml实现数据驱动?
- Guangzhou will promote the construction of a child friendly city, and will explore the establishment of a safe area 200 meters around the school
- LeetCode:673. 最长递增子序列的个数
- Philosophical enlightenment from single point to distributed
- LeetCode:673. Number of longest increasing subsequences
- LeetCode:41. 缺失的第一个正数
- Leetcode: Jianzhi offer 03 Duplicate numbers in array
猜你喜欢
LeetCode:236. The nearest common ancestor of binary tree
Different data-driven code executes the same test scenario
LeetCode41——First Missing Positive——hashing in place & swap
Advance Computer Network Review(1)——FatTree
Mongodb installation and basic operation
Intel Distiller工具包-量化实现2
[OC]-<UI入门>--常用控件的学习
Chapter 1 :Application of Artificial intelligence in Drug Design:Opportunity and Challenges
A convolution substitution of attention mechanism
Using C language to complete a simple calculator (function pointer array and callback function)
随机推荐
[OC foundation framework] - string and date and time >
Selenium+Pytest自动化测试框架实战(下)
To effectively improve the quality of software products, find a third-party software evaluation organization
Using C language to complete a simple calculator (function pointer array and callback function)
KDD 2022论文合集(持续更新中)
[text generation] recommended in the collection of papers - Stanford researchers introduce time control methods to make long text generation more smooth
[sword finger offer] serialized binary tree
Leetcode刷题题解2.1.1
Pytorch view tensor memory size
Using label template to solve the problem of malicious input by users
LeetCode:673. 最长递增子序列的个数
What is the role of automated testing frameworks? Shanghai professional third-party software testing company Amway
postman之参数化详解
A convolution substitution of attention mechanism
LeetCode:劍指 Offer 42. 連續子數組的最大和
数字人主播618手语带货,便捷2780万名听障人士
不同的数据驱动代码执行相同的测试场景
Niuke winter vacation training 6 maze 2
UML图记忆技巧
How to effectively conduct automated testing?