zcache

package
v0.30.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2026 License: Apache-2.0 Imports: 20 Imported by: 2

README

zcache Package

Overview

The zcache package provides an abstraction layer over Redis, allowing easy integration of caching mechanisms into Go applications. It simplifies interacting with Redis by offering a common interface for various caching operations.

Table of Contents

  1. Features
  2. Installation
  3. Usage
  4. Configuration
  5. Mocking Support

Features

  • Unified Caching Interface: Offers a consistent API for common caching operations, abstracting the complexity of direct Redis interactions.
  • Distributed Mutex Locks: Supports distributed synchronization using Redis-based mutex locks, crucial for concurrent operations.
  • Extensibility: Easy to extend with additional methods for more Redis operations.
  • Serialization and Deserialization: Automatically handles the conversion of Go data structures to and from Redis storage formats.
  • Mocking for Testing: Includes mock implementations for easy unit testing without a live Redis instance.
  • Connection Pool Management: Efficiently handles Redis connection pooling.
  • Supported Operations: Includes a variety of caching operations like Set, Get, Delete, as well as more advanced operations like Incr, Decr, and others.

Installation

go get github.com/zondax/golem/pkg/zcache

Usage Remote cache - Redis

import (
    "github.com/zondax/golem/pkg/zcache"
    "context"
    "time"
)

func main() {
    config := zcache.RemoteConfig{Addr: "localhost:6379"}
    cache := zcache.NewRemoteCache(config)
    ctx := context.Background()

    // Set a value
    cache.Set(ctx, "key1", "value1", 10*time.Minute)

    // Get a value
    if value, err := cache.Get(ctx, "key1"); err == nil {
        fmt.Println("Retrieved value:", value)
    }

    // Delete a value
    cache.Delete(ctx, "key1")
}

Usage Local cache - Ristretto

The LocalConfig for zcache provides configuration for the Ristretto cache. Ristretto is a high-performance memory-bound cache with built-in metrics and automatic memory management.

It's important to note that MetricServer is a mandatory configuration field in LocalConfig to facilitate the monitoring of cache operations and errors.

func main() {
    config := zcache.LocalConfig{
        // Ristretto cache configuration
        NumCounters: 1e7,         // Number of keys to track frequency (default: 10M)
        MaxCostMB:   1024,        // Maximum cost of cache in MB (default: 1024MB/1GB)
        BufferItems: 64,          // Number of keys per Get buffer (default: 64)
        
        // Metrics are required
        MetricServer: metricServer, 
    }
    
    cache, err := zcache.NewLocalCache(&config)
    if err != nil {
        // Handle error
    }
    
    ctx := context.Background()
    
    cache.Set(ctx, "key1", "value1", 10*time.Minute)
    if value, err := cache.Get(ctx, "key1"); err == nil {
        fmt.Println("Retrieved value:", value)
    }
    cache.Delete(ctx, "key1")
}

Usage Combined cache - Local and Remote

func main() {
    localConfig := zcache.LocalConfig{
        // Ristretto cache configuration
        NumCounters: 1e7,          // Number of keys to track (default: 10M)
        MaxCostMB:   512,          // Max memory usage - 512MB
        BufferItems: 64,           // Size of Get buffer
        
        // Metrics are required
        MetricServer: metricServer,
    }
    remoteConfig := zcache.RemoteConfig{Addr: "localhost:6379"}
    config := zcache.CombinedConfig{Local: localConfig, Remote: remoteConfig, isRemoteBestEffort: false}
    cache, err := zcache.NewCombinedCache(config)
    if err != nil {
        // Handle error
    }
    
    ctx := context.Background()
    
    cache.Set(ctx, "key1", "value1", 10*time.Minute)
    if value, err := cache.Get(ctx, "key1"); err == nil {
        fmt.Println("Retrieved value:", value)
    }
    cache.Delete(ctx, "key1")
}


Configuration

Configure zcache using the Config struct, which includes network settings, server address, timeouts, and other connection parameters. This struct allows you to customize the behavior of your cache and mutex instances to fit your application's needs.

type Config struct {
    Addr             string        // Redis server address
    Password         string        // Redis server password
    DB               int           // Redis database
    DialTimeout      time.Duration // Timeout for connecting to Redis
    ReadTimeout      time.Duration // Timeout for reading from Redis
    WriteTimeout     time.Duration // Timeout for writing to Redis
    PoolSize         int           // Number of connections in the pool
    MinIdleConns     int           // Minimum number of idle connections
    IdleTimeout      time.Duration // Timeout for idle connections
}

Working with mutex

func main() {
    cache := zcache.NewCache(zcache.Config{Addr: "localhost:6379"})
    mutex := cache.NewMutex("mutex_name", 2*time.Minute)

    // Acquire lock
    if err := mutex.Lock(); err != nil {
        log.Fatalf("Failed to acquire mutex: %v", err)
    }

    // Perform operations under lock
    // ...

    // Release lock
    if ok, err := mutex.Unlock(); !ok || err != nil {
        log.Fatalf("Failed to release mutex: %v", err)
    }
}

Mocking support

Use MockZCache and MockZMutex for unit testing.

func TestCacheOperation(t *testing.T) {
    mockCache := new(zcache.MockZCache)
    mockCache.On("Get", mock.Anything, "key1").Return("value1", nil)
    // Use mockCache in your tests
}

func TestSomeFunctionWithMutex(t *testing.T) {
    mockMutex := new(zcache.MockZMutex)
    mockMutex.On("Lock").Return(nil)
    mockMutex.On("Unlock").Return(true, nil)
    mockMutex.On("Name").Return("myMutex")
    
    result, err := SomeFunctionThatUsesMutex(mockMutex)
    assert.NoError(t, err)
    assert.Equal(t, expectedResult, result)
    
    mockMutex.AssertExpectations(t)
}

Best Practices - Ristretto Cache

Memory Management

When using the local cache (Ristretto), memory is managed efficiently:

  1. Memory Control:

    • Ristretto uses precise memory tracking with a cost-based system
    • Items are evicted based on cost, access frequency, and recency
    • Built-in admission policy prevents low-value items from entering the cache
  2. Configuration Parameters:

    • NumCounters: Number of keys to track (default: 1e7 or 10 million)
    • MaxCostMB: Maximum memory in MB (default: 1024MB or 1GB)
    • BufferItems: Size of the Get buffer for handling concurrent operations (default: 64)
  3. TTL Behavior:

    • TTL is handled internally by Ristretto
    • Setting ttl <= 0 in the API means the item never expires
    • Ristretto automatically removes expired items
Memory Monitoring

Monitor cache performance through Ristretto metrics. The following metrics are available:

  • localCacheHitsMetricName: Number of cache hits
  • localCacheMissesMetricName: Number of cache misses
  • localCacheDelHitsMetricName: Number of successful deletions
  • localCacheDelMissesMetricName: Number of failed deletions
  • localCacheCollisionsMetricName: Number of key collisions

For Redis metrics:

  • remoteCachePoolHitsMetricName: Free connection found in the pool
  • remoteCachePoolMissesMetricName: Free connection not found in the pool
  • remoteCachePoolTimeoutsMetricName: Wait timeout occurrences
  • remoteCachePoolTotalConnsMetricName: Total connections in the pool
  • remoteCachePoolIdleConnsMetricName: Idle connections in the pool
  • remoteCachePoolStaleConnsMetricName: Stale connections removed
Best Practices
  1. Memory Configuration:

    • Set appropriate NumCounters based on expected number of keys (~10x the items)
    • Configure MaxCostMB based on available system memory (in megabytes)
    • Adjust BufferItems for high concurrency scenarios (default 64 is suitable for most cases)
  2. Production Recommendations:

    • Use Combined Cache with Redis for persistence
    • Monitor hit ratios through the exposed metrics
    • Set appropriate TTLs for data freshness
    • For critical production systems, implement fallback mechanisms
  3. Cache Tuning:

    • For high-throughput systems, increase BufferItems
    • For memory-constrained environments, decrease MaxCostMB appropriately
    • Keep NumCounters at approximately 10x your expected item count for optimal hit ratio
Notes
  • Ristretto provides better memory management than the previously used BigCache
  • No known memory leak issues or required manual cleanup processes
  • Predictable memory usage with automatic item eviction
  • Better performance under high load with concurrent operations
  • Cost-based eviction allows prioritizing important cache items

Documentation

Index

Constants

View Source
const (
	// Default Ristretto cache config
	DefaultNumCounters = int64(1e7)  // 10M keys
	DefaultMaxCostMB   = int64(1024) // 1GB
	DefaultBufferItems = int64(64)
)
View Source
const KeySplitter = "/"

Variables

This section is empty.

Functions

This section is empty.

Types

type CacheItem added in v0.14.0

type CacheItem struct {
	Value     []byte `json:"value"`
	ExpiresAt int64  `json:"expires_at"`
}

func NewCacheItem added in v0.14.0

func NewCacheItem(value []byte, ttl time.Duration) CacheItem

func (CacheItem) IsExpired added in v0.14.0

func (item CacheItem) IsExpired() bool

type CombinedCache added in v0.11.0

type CombinedCache interface {
	ZCache
}

func NewCombinedCache added in v0.11.0

func NewCombinedCache(combinedConfig *CombinedConfig) (CombinedCache, error)

type CombinedConfig added in v0.11.0

type CombinedConfig struct {
	Local              *LocalConfig
	Remote             *RemoteConfig
	GlobalLogger       *logger.Logger
	GlobalPrefix       string
	GlobalMetricServer metrics.TaskMetrics
	GlobalStatsMetrics StatsMetrics
	IsRemoteBestEffort bool
}

type CustomZ added in v0.17.0

type CustomZ struct {
	Score  float64
	Member interface{}
}

type LocalCache added in v0.10.1

type LocalCache interface {
	ZCache
}

func NewLocalCache added in v0.10.1

func NewLocalCache(config *LocalConfig) (LocalCache, error)

type LocalConfig added in v0.10.1

type LocalConfig struct {
	Prefix       string
	Logger       *logger.Logger
	MetricServer metrics.TaskMetrics
	StatsMetrics StatsMetrics

	// Add Ristretto cache configuration
	NumCounters int64 `json:"num_counters"` // default: 1e7
	MaxCostMB   int64 `json:"max_cost_mb"`  // in MB, default: 1024 (1GB)
	BufferItems int64 `json:"buffer_items"` // default: 64
}

func (*LocalConfig) ToRistrettoConfig added in v0.21.0

func (c *LocalConfig) ToRistrettoConfig() *ristretto.Config

type MockZCache

type MockZCache struct {
	mock.Mock
}

func (*MockZCache) Client added in v0.29.0

func (m *MockZCache) Client() *redis.Client

func (*MockZCache) Decr

func (m *MockZCache) Decr(ctx context.Context, key string) (int64, error)

func (*MockZCache) DecrBy added in v0.29.0

func (m *MockZCache) DecrBy(ctx context.Context, key string, value int64) (int64, error)

func (*MockZCache) Delete

func (m *MockZCache) Delete(ctx context.Context, key string) error

func (*MockZCache) DeleteMulti added in v0.29.0

func (m *MockZCache) DeleteMulti(ctx context.Context, keys ...string) error

func (*MockZCache) Exists

func (m *MockZCache) Exists(ctx context.Context, keys ...string) (int64, error)

func (*MockZCache) Expire added in v0.17.0

func (m *MockZCache) Expire(ctx context.Context, key string, ttl time.Duration) (bool, error)

func (*MockZCache) FlushAll

func (m *MockZCache) FlushAll(ctx context.Context) error

func (*MockZCache) Get

func (m *MockZCache) Get(ctx context.Context, key string, data interface{}) error

func (*MockZCache) GetStats added in v0.14.2

func (m *MockZCache) GetStats() ZCacheStats

func (*MockZCache) HExists added in v0.29.0

func (m *MockZCache) HExists(ctx context.Context, key, field string) (bool, error)

func (*MockZCache) HGet

func (m *MockZCache) HGet(ctx context.Context, key, field string) (string, error)

func (*MockZCache) HGetAll added in v0.29.0

func (m *MockZCache) HGetAll(ctx context.Context, key string) (map[string]string, error)

func (*MockZCache) HIncrBy added in v0.29.0

func (m *MockZCache) HIncrBy(ctx context.Context, key, field string, incr int64) (int64, error)

func (*MockZCache) HSet

func (m *MockZCache) HSet(ctx context.Context, key string, values ...interface{}) (int64, error)

func (*MockZCache) HSetNX added in v0.29.0

func (m *MockZCache) HSetNX(ctx context.Context, key, field string, value interface{}) (bool, error)

func (*MockZCache) Incr

func (m *MockZCache) Incr(ctx context.Context, key string) (int64, error)

func (*MockZCache) IncrBy added in v0.29.0

func (m *MockZCache) IncrBy(ctx context.Context, key string, value int64) (int64, error)

func (*MockZCache) IsNotFoundError added in v0.14.2

func (m *MockZCache) IsNotFoundError(err error) bool

func (*MockZCache) Keys added in v0.29.0

func (m *MockZCache) Keys(ctx context.Context, pattern string) ([]string, error)

func (*MockZCache) LPush

func (m *MockZCache) LPush(ctx context.Context, key string, values ...interface{}) (int64, error)

func (*MockZCache) NewMutex added in v0.29.0

func (m *MockZCache) NewMutex(name string, expiry time.Duration) ZMutex

func (*MockZCache) Pipeline added in v0.29.0

func (m *MockZCache) Pipeline() RedisPipeline

func (*MockZCache) RPush

func (m *MockZCache) RPush(ctx context.Context, key string, values ...interface{}) (int64, error)

func (*MockZCache) SAdd

func (m *MockZCache) SAdd(ctx context.Context, key string, members ...interface{}) (int64, error)

func (*MockZCache) SMembers

func (m *MockZCache) SMembers(ctx context.Context, key string) ([]string, error)

func (*MockZCache) Set

func (m *MockZCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error

func (*MockZCache) SetNX added in v0.28.0

func (m *MockZCache) SetNX(ctx context.Context, key string, value interface{}, ttl time.Duration) (bool, error)

func (*MockZCache) SetupAndMonitorMetrics added in v0.14.2

func (m *MockZCache) SetupAndMonitorMetrics(appName string, metricsServer metrics.TaskMetrics, updateInterval time.Duration) []error

func (*MockZCache) TTL added in v0.15.4

func (m *MockZCache) TTL(ctx context.Context, key string) (time.Duration, error)

func (*MockZCache) TxPipeline added in v0.29.0

func (m *MockZCache) TxPipeline() RedisPipeline

func (*MockZCache) ZIncrBy added in v0.17.0

func (m *MockZCache) ZIncrBy(ctx context.Context, key string, member string, increment float64) (float64, error)

func (*MockZCache) ZRevRangeWithScores added in v0.17.0

func (m *MockZCache) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) ([]CustomZ, error)

type MockZMutex

type MockZMutex struct {
	mock.Mock
}

func (*MockZMutex) Lock

func (m *MockZMutex) Lock() error

func (*MockZMutex) Name

func (m *MockZMutex) Name() string

func (*MockZMutex) Unlock

func (m *MockZMutex) Unlock() (bool, error)

type RedisPipeline added in v0.29.0

type RedisPipeline interface {
	IncrBy(ctx context.Context, key string, value int64) *redis.IntCmd
	HIncrBy(ctx context.Context, key, field string, incr int64) *redis.IntCmd
	HSet(ctx context.Context, key string, values ...interface{}) *redis.IntCmd
	HSetNX(ctx context.Context, key, field string, value interface{}) *redis.BoolCmd
	HExists(ctx context.Context, key, field string) *redis.BoolCmd
	HGetAll(ctx context.Context, key string) *redis.StringStringMapCmd
	Expire(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd
	Del(ctx context.Context, keys ...string) *redis.IntCmd
	Exec(ctx context.Context) ([]redis.Cmder, error)
}

RedisPipeline provides pipelined execution of Redis commands

type RedisStats added in v0.11.0

type RedisStats struct {
	Pool *redis.PoolStats
}

type RemoteCache added in v0.10.1

type RemoteCache interface {
	ZCache
	SetNX(ctx context.Context, key string, value interface{}, ttl time.Duration) (bool, error)
	Incr(ctx context.Context, key string) (int64, error)
	Decr(ctx context.Context, key string) (int64, error)
	LPush(ctx context.Context, key string, values ...interface{}) (int64, error)
	RPush(ctx context.Context, key string, values ...interface{}) (int64, error)
	SMembers(ctx context.Context, key string) ([]string, error)
	SAdd(ctx context.Context, key string, members ...interface{}) (int64, error)
	HSet(ctx context.Context, key string, values ...interface{}) (int64, error)
	HGet(ctx context.Context, key, field string) (string, error)
	ZIncrBy(ctx context.Context, key string, member string, increment float64) (float64, error)
	ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) ([]CustomZ, error)
	FlushAll(ctx context.Context) error
	Exists(ctx context.Context, keys ...string) (int64, error)
	Expire(ctx context.Context, key string, ttl time.Duration) (bool, error)
	TTL(ctx context.Context, key string) (time.Duration, error)

	// Extended Redis operations
	IncrBy(ctx context.Context, key string, value int64) (int64, error)
	DecrBy(ctx context.Context, key string, value int64) (int64, error)
	HIncrBy(ctx context.Context, key, field string, incr int64) (int64, error)
	HSetNX(ctx context.Context, key, field string, value interface{}) (bool, error)
	HExists(ctx context.Context, key, field string) (bool, error)
	HGetAll(ctx context.Context, key string) (map[string]string, error)
	Keys(ctx context.Context, pattern string) ([]string, error)
	DeleteMulti(ctx context.Context, keys ...string) error

	// Pipeline support
	Pipeline() RedisPipeline
	TxPipeline() RedisPipeline

	// Distributed mutex
	NewMutex(name string, expiry time.Duration) ZMutex

	// Underlying client access (use with caution - prefer interface methods)
	Client() *redis.Client
}

func NewRemoteCache added in v0.10.1

func NewRemoteCache(config *RemoteConfig) (RemoteCache, error)

type RemoteConfig added in v0.10.1

type RemoteConfig struct {
	Network            string
	Addr               string
	Password           string
	DB                 int
	DialTimeout        time.Duration
	ReadTimeout        time.Duration
	WriteTimeout       time.Duration
	PoolSize           int
	MinIdleConns       int
	MaxConnAge         time.Duration
	PoolTimeout        time.Duration
	IdleTimeout        time.Duration
	IdleCheckFrequency time.Duration
	Prefix             string
	Logger             *logger.Logger
	MetricServer       metrics.TaskMetrics
	StatsMetrics       StatsMetrics

	// TLS Configuration
	TLSEnabled         bool   // Enable TLS connection
	TLSCertPath        string // Path to client TLS certificate (optional, for mTLS)
	TLSKeyPath         string // Path to client TLS key (optional, for mTLS)
	TLSCAPath          string // Path to CA certificate (optional)
	InsecureSkipVerify bool   // Skip TLS verification (dev only)
}

func (*RemoteConfig) GetHost added in v0.29.0

func (c *RemoteConfig) GetHost() string

GetHost returns the host portion of Addr. Properly handles IPv6 addresses (e.g., "[::1]:6379").

func (*RemoteConfig) GetPort added in v0.29.0

func (c *RemoteConfig) GetPort() int

GetPort returns the port portion of Addr, or 0 if not set or invalid. Properly handles IPv6 addresses (e.g., "[::1]:6379").

func (*RemoteConfig) SetAddr added in v0.29.0

func (c *RemoteConfig) SetAddr(host string, port int)

SetAddr sets Addr from separate host and port values. Properly handles IPv6 addresses by using net.JoinHostPort.

func (*RemoteConfig) ToRedisConfig added in v0.10.1

func (c *RemoteConfig) ToRedisConfig() (*redis.Options, error)

type StatsMetrics added in v0.17.1

type StatsMetrics struct {
	Enable         bool
	UpdateInterval time.Duration
}

type ZCache

type ZCache interface {
	Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error
	Get(ctx context.Context, key string, data interface{}) error
	Delete(ctx context.Context, key string) error
	GetStats() ZCacheStats
	IsNotFoundError(err error) bool
}

type ZCacheStats added in v0.11.0

type ZCacheStats struct {
	Local  *ristretto.Metrics
	Remote *RedisStats
}

type ZMutex

type ZMutex interface {
	Lock() error
	Unlock() (bool, error)
	Name() string
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL