go中redis使用的示例代碼
在Go語言中使用Redis進行數(shù)據(jù)存儲和管理可以帶來高效和靈活的優(yōu)勢。下面的講解包括單機模式、哨兵模式和集群模式的部署及使用。
一、Redis 簡介
Redis是一個高性能的內存數(shù)據(jù)庫,支持多種數(shù)據(jù)結構,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(ZSet)等。它還支持事務、批量操作和流式數(shù)據(jù)處理。Redis常用于緩存、實時數(shù)據(jù)處理、計數(shù)器、消息隊列等場景。
二、Go中Redis的使用
1. 安裝Go Redis包
推薦使用github.com/go-redis/redis/v9,它支持單機、哨兵和集群模式。
安裝命令:
go get github.com/go-redis/redis/v9
2. 單機模式
特點:單一Redis實例,簡單易用,適合開發(fā)和測試環(huán)境。
連接示例
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
)
func main() {
ctx := context.Background()
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
pong, err := client.Ping(ctx).Result()
if err != nil {
fmt.Printf("連接失?。?v\n", err)
return
}
fmt.Println(pong) // 輸出:PONG
// 示例:設置和獲取值
if err := client.Set(ctx, "key", "value", 0).Err(); err != nil {
fmt.Printf("設置失?。?v\n", err)
return
}
val, err := client.Get(ctx, "key").Result()
if err != nil {
fmt.Printf("獲取失?。?v\n", err)
return
}
fmt.Printf("值:%v\n", val)
}
說明:
- 使用
redis.NewClient創(chuàng)建客戶端。 - 使用
Ping測試連接。 Set設置鍵值,Get讀取值。
3. 哨兵模式
特點:提供高可用性,當主庫故障時,自動故障轉移。
依賴
- 必須安裝Redis哨兵服務。
連接示例
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
)
func main() {
ctx := context.Background()
client := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"localhost:26379", "localhost:26380", "localhost:26381"},
})
pong, err := client.Ping(ctx).Result()
if err != nil {
fmt.Printf("連接失?。?v\n", err)
return
}
fmt.Println(pong)
// 示例:設置和獲取值
if err := client.Set(ctx, "key", "value", 0).Err(); err != nil {
fmt.Printf("設置失?。?v\n", err)
return
}
val, err := client.Get(ctx, "key").Result()
if err != nil {
fmt.Printf("獲取失?。?v\n", err)
return
}
fmt.Printf("值:%v\n", val)
}
說明:
- 使用
redis.NewFailoverClient創(chuàng)建客戶端。 - 指定主庫名稱
MasterName和哨兵地址。 - 當主庫故障時,哨兵會自動將從庫提升為主庫。
三、Redis集群
1. 集群模式
特點:通過分片實現(xiàn)水平擴展,每個節(jié)點處理一部分數(shù)據(jù),適合高并發(fā)場景。
集群部署
部署結構
- 6節(jié)點:3主3從,每個主節(jié)點負責一個分片。
- 每個分片有1主1從。
使用redis-cli創(chuàng)建集群
- 啟動6個Redis實例,分別指定不同端口。
- 使用
redis-cli命令創(chuàng)建集群。
創(chuàng)建集局腳本:例如 start_cluster.sh
# 啟動6個節(jié)點,端口分別為30001到30006
for port in {30001..30006}; do
redis-server --cluster-enabled yes --cluster-config-file node-${port}.conf --port ${port} --daemonize yes
done
# 創(chuàng)建集群
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1
在上面的腳本中,node-${port}.conf 是 Redis 集群模式下每個節(jié)點的配置文件,用于指定節(jié)點的運行參數(shù)。如果這些配置文件不存在,Redis 會自動生成一個默認的配置文件,但為了確保集群部署的正確性,最好手動創(chuàng)建這些配置文件。
例如:
# node-30001.conf cluster-enabled yes port 30001 bind 127.0.0.1 daemonize yes logfile /var/log/redis/redis_30001.log dir ./data/30001 save 60 1 appendonly yes
解釋:
cluster-enabled yes: 啟用集群模式。port: 指定當前節(jié)點的端口。bind: 綁定主機地址。daemonize yes: 后臺運行。logfile: 指定日志文件路徑。dir: 指定數(shù)據(jù)文件存儲路徑。save: 配置數(shù)據(jù)持久化策略。appendonly: 啟用 AOF 持久化。
然后給腳本賦予執(zhí)行權限并運行:
chmod +x start_cluster.sh ./start_cluster.sh
連接示例
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
)
func main() {
// 集群節(jié)點地址
addresses := []string{
"localhost:30001",
"localhost:30002",
"localhost:30003",
"localhost:30004",
"localhost:30005",
"localhost:30006",
}
clusterClient := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: addresses,
})
pong, err := clusterClient.Ping(context.Background()).Result()
if err != nil {
fmt.Printf("連接失?。?v\n", err)
return
}
fmt.Println(pong)
// 設置鍵值對
if err := clusterClient.Set(context.Background(), "key", "value", 0).Err(); err != nil {
fmt.Printf("設置失敗:%v\n", err)
return
}
// 獲取值
val, err := clusterClient.Get(context.Background(), "key").Result()
if err != nil {
fmt.Printf("獲取失?。?v\n", err)
return
}
fmt.Printf("值:%v\n", val)
}
說明:
- 使用
redis.NewClusterClient創(chuàng)建集群客戶端。 - 初始化時提供所有節(jié)點地址。
- 集群模式下,Redis自動處理數(shù)據(jù)分片和請求路由。
四、常用數(shù)據(jù)結構與操作
1. 字符串(String)
// 設置過期時間 err = client.Set(context.Background(), "key", "value", 10*time.Second).Err() // 遞增計數(shù)器 num, err := client.Incr(context.Background(), "counter").Result() // 遞減計數(shù)器 num, err := client.Decr(context.Background(), "counter").Result()
2. 哈希(Hash)
// 設置字段值 err = client.HSet(context.Background(), "hashKey", "field", "value").Err() // 獲取字段值 value, err := client.HGet(context.Background(), "hashKey", "field").Result()
3. 列表(List)
// 從左邊推入元素 err = client.LPush(context.Background(), "listKey", "value").Err() // 彈出左邊第一個元素 value, err := client.LPop(context.Background(), "listKey").Result()
4. 集合(Set)
// 添加元素 err = client.SAdd(context.Background(), "setKey", "element").Err() // 移除元素 err = client.SRem(context.Background(), "setKey", "element").Err() // 獲取所有元素 members, err := client.SMembers(context.Background(), "setKey").Result()
5. 有序集合(ZSet)
// 添加元素并設置分數(shù)
err = client.ZAdd(context.Background(), "zsetKey", &redis.Z{Member: "element", Score: 100}).Err()
// 獲取元素的分數(shù)
score, err := client.ZScore(context.Background(), "zsetKey", "element").Result()
// 獲取排名
rank, err := client.ZRank(context.Background(), "zsetKey", "element").Result()
五、事務與批量操作
1. 事務
// 開始事務
ctx := context.Background()
tx, err := client.Tx(ctx)
// 執(zhí)行事務中的操作
_, err = tx.Pipeline()(
function(ctx context.Context) (_redis.CMDCb, error) {
_, err := tx.Get(ctx, "balance").Result()
if err != nil {
return nil, err
}
_, err := tx.Incr(ctx, "balance").Result()
if err != nil {
return nil, err
}
return nil, nil
},
)
if err != nil {
fmt.Printf("事務執(zhí)行失?。?v\n", err)
}
2. 管道技術
// 創(chuàng)建管道
pipe := client.Pipeline()
// 執(zhí)行多個命令
cmds, err := pipe.Set(context.Background(), "key1", "value1", 0).
Set(context.Background(), "key2", "value2", 0).
Exec(context.Background())
if err != nil {
fmt.Printf("管道執(zhí)行失敗:%v\n", err)
return
}
// 打印結果
for _, cmd := range cmds {
fmt.Printf("%v\n", cmd)
}
六、高可用性
1. 復制(主從)
- 設置主從復制,確保數(shù)據(jù)安全。
- 主庫寫入,數(shù)據(jù)同步到從庫。
- 從庫可用于讀分離,提高讀性能。
2. 故障轉移
- 使用哨兵模式實現(xiàn)自動故障轉移。
- 集群模式下,節(jié)點故障自動遷移。
3. 連接池
// 配置連接池
pool := &redis.Pool{
Dial: func(context.Context) (redis.Conn, error) {
return client.DialContext(context.Background())
},
MaxActive: 10, // 最大活躍連接數(shù)
MaxIdle: 5, // 最大空閑連接數(shù)
IdleTimeout: 5 * time.Minute,
}
// 使用連接池
conn := pool.Get(context.Background())
defer conn.Close()
七、監(jiān)控與性能調優(yōu)
1. 內置工具
- redis-cli: 命令行工具,執(zhí)行各種Redis命令。
- redis-benchmark: 性能基準測試工具。
# 基準測試 redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 10000 -q
2. 性能指標
- 內存使用: 使用
info memory查看內存狀態(tài)。 - 拒絕策略: 配置
maxmemory-policy避免內存溢出。 - 過期時間: 設置合理的
expire,控制鍵生命周期。
3. 調試
- 使用
slowlog記錄慢查詢。 - 監(jiān)控
blocked clients和master_repl_offset。
八、實際案例
1. 高并發(fā)秒殺系統(tǒng)
需求:在高并發(fā)下,確保商品庫存正確。
解決方案
- 使用Redis的事務和分布鎖。
- 數(shù)據(jù)結構:Hash存儲商品庫存。
package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/go-redis/redis/v9"
)
// 秒殺函數(shù)
func doSecKill(ctx context.Context, client *redis.Client, productId string, userId string) (bool, error) {
// 鎖名稱:秒殺鎖
lockKey := "lock:sec:kill"
// 商品庫存Key
stockKey := "stock:" + productId
// 嘗試獲取鎖,防止超賣
lock, err := client.LockNew(lockKey, 100*time.Millisecond).Acquire(ctx, time.Second*5).Result()
if err != nil {
return false, err
}
defer lock.Release(ctx)
// 檢查庫存是否充足
currentStock, err := client.HGet(ctx, stockKey, "quantity").Int64()
if err != nil || currentStock <= 0 {
return false, fmt.Errorf("庫存不足")
}
// 減少庫存
_, err = client.HIncrBy(ctx, stockKey, "quantity", -1).Result()
if err != nil {
return false, fmt.Errorf("秒殺失敗:%v", err)
}
return true, nil
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(userId int) {
defer wg.Done()
ctx := context.Background()
success, err := doSecKill(ctx, client, "product001", fmt.Sprintf("user%d", userId))
if success {
fmt.Printf("用戶%d秒殺成功\n", userId)
} else {
fmt.Printf("用戶%d秒殺失?。?v\n", userId, err)
}
}(i)
}
wg.Wait()
}
說明
- 使用Redis的分布鎖確保秒殺過程的原子性。
- 使用Hash結構存儲庫存信息,實現(xiàn)并發(fā)安全的扣減操作。
九、最佳實踐
1. 數(shù)據(jù)過期時間
- 為鍵設置合理的TTL,避免內存膨脹。
2. 內存管理
- 監(jiān)控
used_memory,確保內存使用在可控范圍內。 - 配置
maxmemory和maxmemory-policy。
3. 日志配置
- 開啟Redis日志,記錄操作和錯誤信息。
- 使用
slowlog跟蹤慢查詢。
4. 安全性
- 設置強密碼。
- 配置防火墻,限制訪問來源。
5. 監(jiān)控
- 使用Prometheus、Grafana監(jiān)控Redis性能。
- AlertManager配置告警規(guī)則。
6. 備份恢復
- 定期備份RDB或AOF文件。
- 配置主從復制,確保數(shù)據(jù)安全。
7. 連接池管理
- 合理配置連接池參數(shù),避免連接耗盡。
8. 數(shù)據(jù)持久化
- 選擇RDB或AOF,根據(jù)需求配置持久化策略。
十、總結
在Go語言中使用Redis,特別是結合哨兵和集群模式,可以實現(xiàn)高可用和高擴展性的系統(tǒng)。合理選擇數(shù)據(jù)結構,使用事務和管道技術,可以提升性能。同時,注重監(jiān)控和維護,確保Redis的穩(wěn)定運行。
到此這篇關于go中redis使用的示例代碼的文章就介紹到這了,更多相關go redis使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang中的Slice與數(shù)組及區(qū)別詳解
數(shù)組是一種具有固定長度的基本數(shù)據(jù)結構,在golang中與C語言一樣數(shù)組一旦創(chuàng)建了它的長度就不允許改變,數(shù)組的空余位置用0填補,不允許數(shù)組越界。今天小編通過實例代碼操作給大家詳細介紹lang中的Slice與數(shù)組的相關知識,一起看看吧2020-02-02
Go語言實現(xiàn)生產(chǎn)者-消費者模式的方法總結
這篇文章主要介紹了在?Go?語言中實現(xiàn)生產(chǎn)者消費者模式的多種方法,并重點探討了通道、條件變量的適用場景和優(yōu)缺點,需要的可參考一下2023-05-05
golang程序使用alpine編譯出最小arm鏡像實現(xiàn)
這篇文章主要為大家介紹了golang程序使用alpine編譯出最小arm鏡像,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12

