package redis import ( "context" "fmt" "log" "sync" "time" "github.com/redis/go-redis/v9" ) var ( Client *redis.Client Enabled bool memoryStore sync.Map // Redis 不可用时的内存降级存储 ) // Config Redis 配置 type Config struct { Host string Port string Password string DB int } // Init 初始化 Redis 连接,未开启或连接失败则降级为内存模式 func Init(cfg Config) { if cfg.Host == "" { log.Printf("[redis] Redis 未配置,已降级为内存模式运行") Enabled = false Client = nil return } Client = redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%s", cfg.Host, cfg.Port), Password: cfg.Password, DB: cfg.DB, DialTimeout: 2 * time.Second, }) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() if err := Client.Ping(ctx).Err(); err != nil { log.Printf("[redis] Redis 没开或连接失败 (%v),已降级为内存模式运行", err) Enabled = false Client = nil return } Enabled = true log.Printf("[redis] Redis 连接成功: %s:%s (db=%d)", cfg.Host, cfg.Port, cfg.DB) } // Set 设置键值(带过期时间,0=不过期) func Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error { if Enabled && Client != nil { return Client.Set(ctx, key, value, expiration).Err() } // 内存降级 memoryStore.Store(key, memoryItem{value: value, expireAt: time.Now().Add(expiration)}) return nil } // Get 获取值 func Get(ctx context.Context, key string) (string, error) { if Enabled && Client != nil { return Client.Get(ctx, key).Result() } // 内存降级 v, ok := memoryStore.Load(key) if !ok { return "", redis.Nil } item := v.(memoryItem) if time.Now().After(item.expireAt) { memoryStore.Delete(key) return "", redis.Nil } return fmt.Sprintf("%v", item.value), nil } // Del 删除键 func Del(ctx context.Context, key string) error { if Enabled && Client != nil { return Client.Del(ctx, key).Err() } memoryStore.Delete(key) return nil } // Exists 检查键是否存在 func Exists(ctx context.Context, key string) (int64, error) { if Enabled && Client != nil { return Client.Exists(ctx, key).Result() } _, ok := memoryStore.Load(key) if ok { return 1, nil } return 0, nil } // Incr 自增 func Incr(ctx context.Context, key string) (int64, error) { if Enabled && Client != nil { return Client.Incr(ctx, key).Result() } // 内存降级(简单实现) v, _ := Get(ctx, key) var n int64 fmt.Sscanf(v, "%d", &n) n++ Set(ctx, key, n, 0) return n, nil } // memoryItem 内存存储项 type memoryItem struct { value interface{} expireAt time.Time }