go-redis
GitHub概要
スター21,594
ウォッチ259
フォーク2,508
作成日:2012年7月25日
言語:Go
ライセンス:BSD 2-Clause "Simplified" License
トピックス
gogolangredisredis-clientredis-cluster
スター履歴
データ取得日時: 2025/10/22 08:07
キャッシュライブラリ
go-redis
概要
go-redis(redis/go-redis)は、Go用のRedisクライアントライブラリです。高性能で豊富な機能を持ち、Redisサーバーとの接続、データ操作、高度なRedis機能の活用を可能にします。Redis Cluster、Sentinel、各種Redisモジュールをサポートし、OpenTelemetryによる計測機能も提供します。
詳細
go-redisは、基本的なkey-value操作からソート済みセット、ハッシュ、リスト、ストリーム、Pub/Subまで、Redisの全機能をサポートしています。RESP2とRESP3プロトコルに対応し、コネクションプーリング、自動再接続、フェイルオーバー機能を内蔵しています。
OpenTelemetryによるトレーシングとメトリクス、Prometheusメトリクス、Redis Searchなどの拡張機能も利用でき、エンタープライズレベルのアプリケーションにも対応します。context.Contextを全面的にサポートし、タイムアウトやキャンセレーション処理が適切に行えます。
メリット・デメリット
メリット
- Redis機能の完全サポート(Cluster, Sentinel, Modules等)
- 高性能なコネクションプーリングと並行処理
- RESP2/RESP3プロトコル対応
- OpenTelemetryによる包括的な計測機能
- context.Contextの全面サポート
- 自動再接続とフェイルオーバー機能
- 豊富なRedis拡張機能(Search, Bloom等)のサポート
- エンタープライズレベルの信頼性
デメリット
- Redisサーバーが必要(インフラ依存)
- 単純なインメモリキャッシュとしては過剰な場合もある
- Redis特有の概念(データ型、コマンド等)の学習が必要
- ネットワーク経由のため、純粋なインメモリキャッシュより遅い
- Redis設定とチューニングの知識が必要
参考ページ
書き方の例
基本的なセットアップ
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func main() {
// 基本的なRedisクライアント作成
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // パスワードなし
DB: 0, // デフォルトDB
})
// 接続確認
pong, err := rdb.Ping(ctx).Result()
if err != nil {
panic(err)
}
fmt.Println("Connected to Redis:", pong)
}
基本的なSet/Get操作
// 文字列の保存
err := rdb.Set(ctx, "user:name", "John Doe", 0).Err()
if err != nil {
panic(err)
}
// 値の取得
val, err := rdb.Get(ctx, "user:name").Result()
if err == redis.Nil {
fmt.Println("key does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("user:name", val)
}
// 有効期限付きで保存
err = rdb.Set(ctx, "session:123", "active", 30*time.Minute).Err()
if err != nil {
panic(err)
}
URL接続と設定オプション
// URLを使用した接続
url := "redis://user:password@localhost:6379/0?protocol=3"
opts, err := redis.ParseURL(url)
if err != nil {
panic(err)
}
rdb := redis.NewClient(opts)
// 高度な設定オプション
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "mypassword",
DB: 0,
PoolSize: 10, // コネクションプール数
MinIdleConns: 5, // 最小アイドル接続数
MaxIdleTime: 5 * time.Minute, // アイドルタイムアウト
DialTimeout: 5 * time.Second, // 接続タイムアウト
ReadTimeout: 3 * time.Second, // 読み取りタイムアウト
WriteTimeout: 3 * time.Second, // 書き込みタイムアウト
Protocol: 3, // RESP3プロトコル使用
})
高度なRedis操作
// ハッシュ操作
err := rdb.HSet(ctx, "user:123", map[string]interface{}{
"name": "John Doe",
"email": "[email protected]",
"age": 30,
}).Err()
userInfo := rdb.HGetAll(ctx, "user:123").Val()
fmt.Printf("User info: %v\n", userInfo)
// リスト操作
rdb.LPush(ctx, "tasks", "task1", "task2", "task3")
tasks := rdb.LRange(ctx, "tasks", 0, -1).Val()
fmt.Printf("Tasks: %v\n", tasks)
// ソート済みセット操作
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 100, Member: "player1"})
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 85, Member: "player2"})
// トップ10を取得
topPlayers := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Val()
for _, player := range topPlayers {
fmt.Printf("Player: %s, Score: %.0f\n", player.Member, player.Score)
}
パイプライン処理
// パイプラインを使用した一括処理
pipe := rdb.Pipeline()
incr := pipe.Incr(ctx, "counter")
pipe.Expire(ctx, "counter", time.Hour)
// パイプライン実行
_, err := pipe.Exec(ctx)
if err != nil {
panic(err)
}
// 結果の取得
fmt.Println("Counter value:", incr.Val())
トランザクション(MULTI/EXEC)
// トランザクションの実行
err := rdb.Watch(ctx, func(tx *redis.Tx) error {
// 現在の値を取得
currentVal := tx.Get(ctx, "balance").Val()
balance, _ := strconv.Atoi(currentVal)
if balance < 100 {
return fmt.Errorf("insufficient balance")
}
// トランザクション開始
_, err := tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
pipe.Decr(ctx, "balance")
pipe.Incr(ctx, "spent")
return nil
})
return err
}, "balance")
if err != nil {
fmt.Printf("Transaction failed: %v\n", err)
}
Pub/Sub機能
// パブリッシャー
func publisher(rdb *redis.Client) {
for i := 0; i < 10; i++ {
message := fmt.Sprintf("Message %d", i)
err := rdb.Publish(ctx, "notifications", message).Err()
if err != nil {
panic(err)
}
time.Sleep(1 * time.Second)
}
}
// サブスクライバー
func subscriber(rdb *redis.Client) {
pubsub := rdb.Subscribe(ctx, "notifications")
defer pubsub.Close()
ch := pubsub.Channel()
for msg := range ch {
fmt.Printf("Received: %s\n", msg.Payload)
}
}
Redis Cluster接続
// Clusterクライアント
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
"localhost:7000",
"localhost:7001",
"localhost:7002",
},
Password: "cluster-password",
})
// 通常の操作と同じAPIを使用
err := rdb.Set(ctx, "cluster-key", "cluster-value", 0).Err()
if err != nil {
panic(err)
}
OpenTelemetry統合
import (
"github.com/redis/go-redis/v9"
"github.com/redis/go-redis/extra/redisotel/v9"
)
// OpenTelemetryインストルメンテーション
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
// トレーシングとメトリクスを有効化
err := redisotel.InstrumentTracing(rdb)
if err != nil {
panic(err)
}
err = redisotel.InstrumentMetrics(rdb)
if err != nil {
panic(err)
}
エラーハンドリングと再試行
// カスタム再試行設定
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
MaxRetries: 3,
MinRetryBackoff: 8 * time.Millisecond,
MaxRetryBackoff: 512 * time.Millisecond,
})
// エラーハンドリング
val, err := rdb.Get(ctx, "nonexistent").Result()
switch {
case err == redis.Nil:
fmt.Println("Key does not exist")
case err != nil:
fmt.Printf("Error occurred: %v\n", err)
default:
fmt.Printf("Value: %s\n", val)
}