Skip to content

A Golang Redis fallback solution that automatically downgrades to local storage when connections are unavailable and implements automatic recovery when connections are restored.

License

Notifications You must be signed in to change notification settings

pardnchiu/go-redis-fallback

Repository files navigation

Note

This content is translated by LLM. Original text can be found here

Redis Fallback (Golang)

A Golang Redis fallback solution that automatically downgrades to local storage when connections are unavailable and implements automatic recovery when connections are restored.
Extended from the integrated concepts of php-redis, php-cache-fallback, and php-session-fallback, providing a unified solution for Golang.

license version readme

Three Core Features

Three-Tier Storage Architecture

Memory cache + Redis + Local file storage with automatic fault tolerance

Graceful Degradation with Auto Recovery

During degradation, Redis health status is monitored periodically, automatically syncing data and cleaning local files when connection is restored

Data Integrity Assurance

Data is stored as JSON files during fallback mode to prevent loss, with TTL support

Flow Chart

Click to view
flowchart TD
  A[Initialize] --> B{Check Redis Connection}
  
  B -->|Connection Failed| B_0[Start Health Check Scheduler]
  B_0 --> B_0_0[Fallback Mode]
  
  subgraph "Initialization"
    B -->|Connection Success| B_1{Check Unsynced Files}
    B_1 -->|Exists| B_1_1[Sync Data to Redis]
  end
  
  subgraph "Normal Mode"
    
    subgraph "Normal Mode Read"
    C --> D{Query Redis}
    D -->|Found| D_1[Update Memory Cache]
    D -->|Not Found| D_0{Check Memory Cache}
    
    D_0 -->|Found| D_0_1[Sync to Redis]
    end
    
    subgraph "Normal Mode Write"
    E --> F{Write to Redis}
    F -->|Success| F_1[Write to Memory]
    F -->|Failed| F_0{Check Redis Connection}

    F_0 -->|Connected, Retry <= 3| E
    end
  end

  D_1 --> ReturnResult[Return Result]
  D_0 -->|Not Found| ReturnResult
  D_0_1 --> ReturnResult

  I_0 -->|Not Found| ReturnResult[Return null]
  I_0_1 --> ReturnResult[Return Result]

  B_1_1 --> B_1_0
  B_1 -->|Not Exists| B_1_0[Normal Mode]
  B_1_0 --> C[Read Request]
  B_1_0 --> E[Write Request]

  F_0 -->|Failed| O
  F_0 --> B_0[Start Health Check Scheduler]
  
  B_0_0 --> J{Check Redis Connection/Every ? seconds}
  B_0_0 --> N[Write Request]

  subgraph "Fallback Mode"
    subgraph "Fallback Mode Read"
    B_0_0 --> H[Read Request]
    I_0 -->|Found| I_0_1[Update Memory Cache]
    end
    
    subgraph "Fallback Mode Monitoring"
    J -->|Recovered| J_1[Execute Recovery Process]
    J -->|Not Recovered| J_0[Continue Fallback Mode]
    J_0 --> J

    J_1 --> K[Sync Memory Data to Redis]
    K --> L[Sync JSON to Redis]
    L --> M{Sync Status}
    M -->|Failed, Retry <= 3| J_1
    end

    subgraph "Fallback Mode Write"
    N--> O[Update Memory Cache]
    O --> P{Database Folder Exists?}
    P --> |Yes| P_1[Write Individual File]
    P --> |No| P_0[Create Database Folder]
    P_0 --> P_1
    end
  end
    
  M -->|Success| B_1_0

  H --> Q{Query Memory Cache}
  S -->|Not Found| I_0{Check JSON Exists}

  subgraph "Memory Process"
    subgraph "Memory Read"
    Q{Check Expiration} -->|Expired| Q_1[Remove Cache and Delete JSON]
    Q_1 --> |null| S
    Q --> |Not Expired| S[Return Result]
    end 

    subgraph "Memory Cleanup"
    T[Memory Cleanup/Every ? seconds] --> U[Clean Memory Data]
    U --> V[Remove JSON]
    V --> T
    end 
  end
Loading

Dependencies

Usage

Installation

go get github.com/pardnchiu/go-redis-fallback

Initialization

package main

import (
  "log"
  "time"
  
  rf "github.com/pardnchiu/go-redis-fallback"
)

func main() {
  config := rf.Config{
    Redis: &rf.Redis{
      Host:     "localhost",
      Port:     6379,
      Password: "",
      DB:       0,
    },
  }

  // Initialize
  client, err := rf.New(config)
  if err != nil {
    log.Fatal(err)
  }
  defer client.Close()

  // Store data (with TTL support)
  err = client.Set("user:1", map[string]string{
    "name":  "John",
    "email": "[email protected]",
  }, 5*time.Minute)

  // Get data
  value, err := client.Get("user:1")
  if err == nil {
    log.Printf("Value: %v", value)
  }

  // Delete data
  err = client.Del("user:1")
}

Configuration

type Config struct {
  Redis   *Redis   // Redis configuration (required)
  Log     *Log     // Log configuration (optional)
  Options *Options // System parameters and fallback settings (optional)
}

type Redis struct {
  Host     string // Redis server host address (required)
  Port     int    // Redis server port number (required)
  Password string // Redis authentication password (optional, empty means no auth)
  DB       int    // Redis database index (required, usually 0-15)
}

type Log struct {
  Path      string // Log directory path (default: ./logs/redisFallback)
  Stdout    bool   // Enable console log output (default: false)
  MaxSize   int64  // Maximum size before log file rotation (bytes) (default: 16MB)
  MaxBackup int    // Number of rotated log files to retain (default: 5)
  Type      string // Output format: "json" for slog standard, "text" for tree format (default: "text")
}

type Options struct {
  DBPath      string        // File storage path (default: ./files/redisFallback/db)
  MaxRetry    int           // Redis retry count (default: 3)
  MaxQueue    int           // Write queue size (default: 1000)
  TimeToWrite time.Duration // Batch write interval (default: 3 seconds)
  TimeToCheck time.Duration // Health check interval (default: 1 minute)
}

Available Functions

Instance Management

  • New - Create new fallback instance

    client, err := rf.New(config)
    • Initialize Redis connection
    • Setup logging system
    • Check for unsynced files
  • Close - Close Redis fallback client

    err := client.Close()
    • Close Redis connection
    • Clear pending writes
    • Release system resources

Data Management

  • Set - Insert data, automatically switch to local storage when Redis fails

    err := client.Set("key", value, ttl)
  • Get - Get data, memory cache as first layer, Redis as second layer, local files as fallback

    value, err := client.Get("key")
  • Del - Delete data

    err := client.Del("key")

Storage Modes

// Normal Mode - Redis available
// 1. Write to Redis first
// 2. Update memory cache after success
// 3. Background sync ensures consistency

// Fallback Mode - Redis unavailable
// 1. Immediately update memory cache
// 2. Add write operations to queue
// 3. Batch write to local files
// 4. Monitor Redis health status

Fallback Process

  • Health Monitoring - Periodically check Redis connection status

    // Automatically executed every TimeToCheck interval
    // Attempt recovery when Redis is available
  • Batch Operations - Optimize performance during fallback

    // Queue writes in memory
    // Batch write to files every TimeToWrite interval
    // Batch sync to Redis during recovery
  • Data Persistence - Layered file storage using MD5 encoding

    // Files stored in nested directories based on key hash
    // JSON format contains metadata: key, data, type, timestamp, TTL

File Storage Structure

Using MD5 encoding for layered directories:

{DBPath}/db/
├── 0/                   # Redis database number
│   ├── ab/              # First 2 characters of MD5
│   │   ├── cd/          # 3rd-4th characters of MD5
│   │   │   ├── ef/      # 5th-6th characters of MD5
│   │   │   │   └── abcdef1234567890abcdef1234567890.json

File content format:

{
  "key": "original key value",
  "data": "actual stored data",
  "type": "interface {}",
  "timestamp": 1234567890,
  "ttl": 300
}

Feature Progress

Continuously improving

  • General Operations

    • Get - Get data
    • Set - Store data
    • Del - Delete key-value
    • Exists - Check if key exists
    • Expire/ExpireAt - Set expiration time
    • TTL - Get remaining time to live
    • Keys - Find keys matching pattern
    • Scan - Iterate keys
    • Pipeline - Batch commands
    • TxPipeline - Transaction batch
  • String Operations

    • SetNX - Set if not exists
    • SetEX - Set with expiration
    • Incr/IncrBy - Increment number
    • Decr/DecrBy - Decrement number
    • MGet/MSet - Batch get/set multiple keys
  • Hash Operations

    • HSet/HGet - Set/get hash field
    • HGetAll - Get all fields and values
    • HKeys/HVals - Get all field names/values
    • HDel - Delete hash field
    • HExists - Check if field exists
  • List Operations

    • LPush/RPush - Add elements from left/right
    • LPop/RPop - Remove elements from left/right
    • LRange - Get range elements
    • LLen - Get list length
  • Set Operations

    • SAdd - Add element to set
    • SMembers - Get all set members
    • SRem - Remove element from set
    • SCard - Get set cardinality
    • SIsMember - Check if element is in set

Features Not Supported in Fallback Mode

  • Blocking Operations

    • BLPop/BRPop - Blocking left/right pop
  • Sorted Set Operations

    • ZAdd - Add element to sorted set
    • ZRange/ZRevRange - Get range by score
    • ZRank/ZRevRank - Get element rank
    • ZScore - Get element score
    • ZRem - Remove element
  • Pub/Sub

    • Publish - Publish message
    • Subscribe - Subscribe to channel
  • Lua Scripts

    • Eval/EvalSha - Execute Lua script

License

This source code project is licensed under the MIT license.

Author

邱敬幃 Pardn Chiu


©️ 2025 邱敬幃 Pardn Chiu

About

A Golang Redis fallback solution that automatically downgrades to local storage when connections are unavailable and implements automatic recovery when connections are restored.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages