1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-20 22:42:59 +03:00
Files
go-redis/docs/general_architecture.md
Nedyalko Dyakov f316244da4 docs(devdocs): Add generated dev documentation
Add AI generated dev documentation in the `docs` folder.
2025-04-29 23:37:03 +03:00

21 KiB

Redis Client Architecture

Overview

This document provides a comprehensive description of the Redis client implementation architecture, focusing on the relationships between different components, their responsibilities, and implementation details.

Core Components

1. Connection Management

Conn Struct

The Conn struct represents a single Redis connection and is defined in internal/pool/conn.go. It contains:

type Conn struct {
    usedAt  int64 // atomic
    netConn net.Conn
    rd *proto.Reader
    bw *bufio.Writer
    wr *proto.Writer
    Inited    bool
    pooled    bool
    createdAt time.Time
}
Detailed Field Descriptions
  • usedAt (int64, atomic)

    • Tracks the last usage timestamp of the connection
    • Uses atomic operations for thread-safe access
    • Helps in connection health checks and idle timeout management
    • Updated via SetUsedAt() and retrieved via UsedAt()
  • netConn (net.Conn)

    • The underlying network connection
    • Handles raw TCP communication
    • Supports both TCP and Unix domain socket connections
    • Can be updated via SetNetConn() which also resets the reader and writer
  • rd (*proto.Reader)

    • Redis protocol reader
    • Handles RESP (REdis Serialization Protocol) parsing
    • Manages read buffers and protocol state
    • Created with proto.NewReader()
  • bw (*bufio.Writer)

    • Buffered writer for efficient I/O
    • Reduces system calls by batching writes
    • Configurable buffer size based on workload
    • Created with bufio.NewWriter()
  • wr (*proto.Writer)

    • Redis protocol writer
    • Handles RESP serialization
    • Manages write buffers and protocol state
    • Created with proto.NewWriter()
  • Inited (bool)

    • Indicates if the connection has been initialized
    • Set after successful authentication and protocol negotiation
    • Prevents re-initialization of established connections
    • Used in connection pool management
  • pooled (bool)

    • Indicates if the connection is part of a connection pool
    • Affects connection lifecycle management
    • Determines if connection should be returned to pool
    • Set during connection creation
  • createdAt (time.Time)

    • Records connection creation time
    • Used for connection lifetime management
    • Helps in detecting stale connections
    • Used in isHealthyConn() checks

Connection Lifecycle Methods

Creation and Initialization
func NewConn(netConn net.Conn) *Conn {
    cn := &Conn{
        netConn:   netConn,
        createdAt: time.Now(),
    }
    cn.rd = proto.NewReader(netConn)
    cn.bw = bufio.NewWriter(netConn)
    cn.wr = proto.NewWriter(cn.bw)
    cn.SetUsedAt(time.Now())
    return cn
}
Usage Tracking
func (cn *Conn) UsedAt() time.Time {
    unix := atomic.LoadInt64(&cn.usedAt)
    return time.Unix(unix, 0)
}

func (cn *Conn) SetUsedAt(tm time.Time) {
    atomic.StoreInt64(&cn.usedAt, tm.Unix())
}
Network Operations
func (cn *Conn) WithReader(
    ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error,
) error {
    if timeout >= 0 {
        if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil {
            return err
        }
    }
    return fn(cn.rd)
}

func (cn *Conn) WithWriter(
    ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error,
) error {
    if timeout >= 0 {
        if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil {
            return err
        }
    }

    if cn.bw.Buffered() > 0 {
        cn.bw.Reset(cn.netConn)
    }

    if err := fn(cn.wr); err != nil {
        return err
    }

    return cn.bw.Flush()
}

Connection Pools

1. ConnPool (internal/pool/pool.go)

Detailed implementation:

type ConnPool struct {
    cfg *Options

    dialErrorsNum uint32 // atomic
    lastDialError atomic.Value

    queue chan struct{}

    connsMu   sync.Mutex
    conns     []*Conn
    idleConns []*Conn

    poolSize     int
    idleConnsLen int

    stats Stats

    _closed uint32 // atomic
}

Key Features:

  • Thread-safe connection management using mutexes and atomic operations
  • Configurable pool size and idle connections
  • Connection health monitoring with isHealthyConn()
  • Automatic connection cleanup
  • Connection reuse optimization
  • Error handling and recovery
  • FIFO/LIFO connection management based on PoolFIFO option
  • Minimum idle connections maintenance
  • Maximum active connections enforcement
  • Connection lifetime and idle timeout management

Pool Management:

  • Get() - Retrieves a connection from the pool or creates a new one
  • Put() - Returns a connection to the pool
  • Remove() - Removes a connection from the pool
  • Close() - Closes the pool and all connections
  • NewConn() - Creates a new connection
  • CloseConn() - Closes a specific connection
  • Len() - Returns total number of connections
  • IdleLen() - Returns number of idle connections
  • Stats() - Returns pool statistics
2. SingleConnPool (internal/pool/pool_single.go)

Implementation:

type SingleConnPool struct {
    pool      Pooler
    cn        *Conn
    stickyErr error
}

Use Cases:

  • Single connection scenarios
  • Transaction operations
  • Pub/Sub subscriptions
  • Pipeline operations
  • Maintains a single connection with error state tracking
3. StickyConnPool (internal/pool/pool_sticky.go)

Implementation:

type StickyConnPool struct {
    pool   Pooler
    shared int32 // atomic
    state  uint32 // atomic
    ch     chan *Conn
    _badConnError atomic.Value
}

Features:

  • Connection stickiness for consistent connection usage
  • State management (default, initialized, closed)
  • Error handling with BadConnError
  • Thread safety with atomic operations
  • Connection sharing support
  • Automatic error recovery

2. Client Types

Base Client

Detailed implementation:

type baseClient struct {
    opt      *Options
    connPool pool.Pooler
    onClose func() error // hook called when client is closed
}

Responsibilities:

  1. Connection Management

    • Pool initialization
    • Connection acquisition
    • Connection release
    • Health monitoring
    • Error handling
  2. Command Execution

    • Protocol handling
    • Response parsing
    • Error handling
    • Retry logic with configurable backoff
  3. Lifecycle Management

    • Initialization
    • Cleanup
    • Resource management
    • Connection state tracking

Client Types

1. Client (redis.go)

Features:

  • Connection pooling with configurable options
  • Command execution with retry support
  • Pipeline support for batch operations
  • Transaction support with MULTI/EXEC
  • Error handling and recovery
  • Resource management
  • Hooks system for extensibility
  • Timeout management
  • Connection health monitoring
2. Conn (redis.go)

Features:

  • Single connection management
  • Direct command execution
  • No pooling overhead
  • Dedicated connection
  • Transaction support
  • Pipeline support
  • Error handling
  • Connection state tracking
3. PubSub (pubsub.go)

Features:

  • Subscription management
  • Message handling
  • Reconnection logic
  • Channel management
  • Pattern matching
  • Thread safety for subscription operations
  • Automatic resubscription on reconnection
  • Message channel management

3. Error Handling and Cleanup

Error Types

Detailed error handling:

var (
    ErrClosed = errors.New("redis: client is closed")
    ErrPoolExhausted = errors.New("redis: connection pool exhausted")
    ErrPoolTimeout = errors.New("redis: connection pool timeout")
)

type BadConnError struct {
    wrapped error
}

Error Recovery Strategies:

  1. Connection Errors

    • Automatic reconnection
    • Backoff strategies
    • Health checks
    • Error state tracking
  2. Protocol Errors

    • Response parsing
    • Protocol validation
    • Error propagation
    • Recovery mechanisms
  3. Resource Errors

    • Cleanup procedures
    • Resource release
    • State management
    • Error reporting

Cleanup Process

Detailed cleanup:

  1. Connection Cleanup

    func (p *ConnPool) Close() error {
        if !atomic.CompareAndSwapUint32(&p._closed, 0, 1) {
            return ErrClosed
        }
        // Cleanup implementation
    }
    
  2. Resource Management

    • Connection closure
    • Buffer cleanup
    • State reset
    • Error handling
    • Resource tracking

4. Hooks System

Implementation Details

type hooksMixin struct {
    hooksMu sync.RWMutex
    current hooks
}

type hooks struct {
    dial       DialHook
    process    ProcessHook
    pipeline   ProcessPipelineHook
    txPipeline ProcessTxPipelineHook
}

Hook Types and Usage:

  1. dialHook

    • Connection establishment
    • Authentication
    • Protocol negotiation
    • Error handling
  2. processHook

    • Command execution
    • Response handling
    • Error processing
    • Metrics collection
  3. processPipelineHook

    • Pipeline execution
    • Batch processing
    • Response aggregation
    • Error handling
  4. processTxPipelineHook

    • Transaction management
    • Command grouping
    • Atomic execution
    • Error recovery

5. Configuration

Options Structure

Detailed configuration:

type Options struct {
    // Network settings
    Network string
    Addr string
    Dialer func(ctx context.Context, network, addr string) (net.Conn, error)

    // Authentication
    Username string
    Password string
    CredentialsProvider func() (username string, password string)

    // Timeouts
    DialTimeout time.Duration
    ReadTimeout time.Duration
    WriteTimeout time.Duration

    // Pool settings
    PoolSize int
    MinIdleConns int
    MaxIdleConns int
    MaxActiveConns int
    PoolTimeout time.Duration

    // TLS
    TLSConfig *tls.Config

    // Protocol
    Protocol int
    ClientName string
}

Configuration Management:

  1. Default Values

    • Network: "tcp"
    • Protocol: 3
    • PoolSize: 10 * runtime.GOMAXPROCS
    • PoolTimeout: ReadTimeout + 1 second
    • MinIdleConns: 0
    • MaxIdleConns: 0
    • MaxActiveConns: 0 (unlimited)
  2. Validation

    • Parameter bounds checking
    • Required field validation
    • Type validation
    • Value validation
  3. Dynamic Updates

    • Runtime configuration changes
    • Connection pool adjustments
    • Timeout modifications
    • Protocol version updates
  4. Environment Integration

    • URL-based configuration
    • Environment variable support
    • Configuration file support
    • Command-line options

6. Monitoring and Instrumentation

OpenTelemetry Integration

The client provides comprehensive monitoring capabilities through OpenTelemetry integration:

// Enable tracing instrumentation
if err := redisotel.InstrumentTracing(rdb); err != nil {
    panic(err)
}

// Enable metrics instrumentation
if err := redisotel.InstrumentMetrics(rdb); err != nil {
    panic(err)
}

Features:

  • Distributed tracing
  • Performance metrics
  • Connection monitoring
  • Error tracking
  • Command execution timing
  • Resource usage monitoring
  • Pool statistics
  • Health checks

Custom Hooks

The client supports custom hooks for monitoring and instrumentation:

type redisHook struct{}

func (redisHook) DialHook(hook redis.DialHook) redis.DialHook {
    return func(ctx context.Context, network, addr string) (net.Conn, error) {
        // Custom monitoring logic
        return hook(ctx, network, addr)
    }
}

func (redisHook) ProcessHook(hook redis.ProcessHook) redis.ProcessHook {
    return func(ctx context.Context, cmd redis.Cmder) error {
        // Custom monitoring logic
        return hook(ctx, cmd)
    }
}

func (redisHook) ProcessPipelineHook(hook redis.ProcessPipelineHook) redis.ProcessPipelineHook {
    return func(ctx context.Context, cmds []redis.Cmder) error {
        // Custom monitoring logic
        return hook(ctx, cmds)
    }
}

Usage:

  • Performance monitoring
  • Debugging
  • Custom metrics
  • Error tracking
  • Resource usage
  • Connection health
  • Command patterns

Best Practices

1. Connection Management

Detailed guidelines:

  • Pool sizing based on workload

    • Consider concurrent operations
    • Account for peak loads
    • Monitor pool statistics
    • Adjust based on metrics
  • Connection monitoring

    • Track connection health
    • Monitor pool statistics
    • Watch for errors
    • Log connection events
  • Health checks

    • Regular connection validation
    • Error detection
    • Automatic recovery
    • State monitoring
  • Resource limits

    • Set appropriate pool sizes
    • Configure timeouts
    • Monitor resource usage
    • Implement circuit breakers
  • Timeout configuration

    • Set appropriate timeouts
    • Consider network conditions
    • Account for operation types
    • Monitor timeout events

2. Error Handling

Implementation strategies:

  • Error recovery

    • Automatic retries
    • Backoff strategies
    • Error classification
    • Recovery procedures
  • Retry logic

    • Configurable attempts
    • Exponential backoff
    • Error filtering
    • State preservation
  • Circuit breakers

    • Error threshold monitoring
    • State management
    • Recovery procedures
    • Health checks
  • Monitoring

    • Error tracking
    • Performance metrics
    • Resource usage
    • Health status
  • Logging

    • Error details
    • Context information
    • Stack traces
    • Performance data

3. Resource Cleanup

Cleanup procedures:

  • Connection closure

    • Proper cleanup
    • Error handling
    • State management
    • Resource release
  • Resource release

    • Memory cleanup
    • File handle closure
    • Network cleanup
    • State reset
  • State management

    • Connection state
    • Pool state
    • Error state
    • Resource state
  • Error handling

    • Error propagation
    • Cleanup on error
    • State recovery
    • Resource cleanup
  • Monitoring

    • Resource usage
    • Cleanup events
    • Error tracking
    • Performance impact

4. Performance Optimization

Optimization techniques:

  • Connection pooling

    • Efficient reuse
    • Load balancing
    • Health monitoring
    • Resource management
  • Pipeline usage

    • Batch operations
    • Reduced round trips
    • Improved throughput
    • Resource efficiency
  • Batch operations

    • Command grouping
    • Reduced overhead
    • Improved performance
    • Resource efficiency
  • Resource management

    • Efficient allocation
    • Proper cleanup
    • Monitoring
    • Optimization
  • Monitoring

    • Performance metrics
    • Resource usage
    • Bottleneck detection
    • Optimization opportunities

Diagrams

Connection Pool Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Client    │────▶│  ConnPool   │────▶│    Conn     │
└─────────────┘     └─────────────┘     └─────────────┘
                           │
                           ▼
                    ┌─────────────┐
                    │  PoolStats  │
                    └─────────────┘

Error Handling Flow

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Command   │────▶│  Execution  │────▶│ Error Check │
└─────────────┘     └─────────────┘     └─────────────┘
                           │                    │
                           ▼                    ▼
                    ┌─────────────┐     ┌─────────────┐
                    │  Success    │     │  Recovery   │
                    └─────────────┘     └─────────────┘

Hook System

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Client    │────▶│  Hooks      │────▶│  Execution  │
└─────────────┘     └─────────────┘     └─────────────┘
                           │
                           ▼
                    ┌─────────────┐
                    │  Custom     │
                    │  Behavior   │
                    └─────────────┘

Connection Lifecycle

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Creation    │────▶│  Active     │────▶│  Cleanup    │
└─────────────┘     └─────────────┘     └─────────────┘
      │                    │                    │
      ▼                    ▼                    ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Init       │     │  Usage      │     │  Release    │
└─────────────┘     └─────────────┘     └─────────────┘

Pool Management

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Get        │────▶│  Use        │────▶│  Put        │
└─────────────┘     └─────────────┘     └─────────────┘
      │                    │                    │
      ▼                    ▼                    ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Checkout   │     │  Monitor    │     │  Return     │
└─────────────┘     └─────────────┘     └─────────────┘

Known Issues and Areas of Improvement

1. Performance Considerations

Potential Performance Bottlenecks

  1. Connection Pool Management

    • Lock contention in connection pool operations
    • Inefficient connection reuse strategies
    • Suboptimal pool sizing algorithms
    • High overhead in connection health checks
  2. Memory Management

    • Buffer allocation/deallocation overhead
    • Memory fragmentation in long-running applications
    • Inefficient buffer reuse strategies
    • Potential memory leaks in edge cases
  3. Protocol Handling

    • RESP parsing overhead
    • Inefficient command serialization
    • Suboptimal batch processing
    • Redundant protocol validations
  4. Concurrency Issues

    • Lock contention in shared resources
    • Inefficient atomic operations
    • Suboptimal goroutine management
    • Race conditions in edge cases

2. Known Issues

  1. Connection Management

    • Occasional connection leaks under high load
    • Suboptimal connection reuse in certain scenarios
    • Race conditions in connection pool management
    • Inefficient connection cleanup in edge cases
  2. Error Handling

    • Overly aggressive error recovery
    • Suboptimal retry strategies
    • Incomplete error context propagation
    • Inconsistent error handling patterns
  3. Resource Management

    • Memory usage spikes under certain conditions
    • Suboptimal buffer management
    • Inefficient resource cleanup
    • Potential resource leaks in edge cases
  4. Protocol Implementation

    • Inefficient command serialization
    • Suboptimal response parsing
    • Redundant protocol validations
    • Incomplete protocol feature support

3. Areas for Improvement

  1. Performance Optimization

    • Implement connection pooling optimizations
    • Optimize buffer management
    • Improve protocol handling efficiency
    • Enhance concurrency patterns
  2. Resource Management

    • Implement more efficient memory management
    • Optimize resource cleanup
    • Improve connection reuse strategies
    • Enhance buffer reuse patterns
  3. Error Handling

    • Implement more sophisticated retry strategies
    • Improve error context propagation
    • Enhance error recovery mechanisms
    • Standardize error handling patterns
  4. Protocol Implementation

    • Optimize command serialization
    • Improve response parsing efficiency
    • Reduce protocol validation overhead
    • Enhance protocol feature support
  5. Monitoring and Diagnostics

    • Implement comprehensive metrics
    • Enhance logging capabilities
    • Improve debugging support
    • Add performance profiling tools

Conclusion

While the current implementation provides a robust and feature-rich Redis client, there are several areas where performance and reliability can be improved. The focus should be on:

  1. Optimizing critical paths
  2. Improving resource management
  3. Enhancing error handling
  4. Implementing better monitoring
  5. Reducing overhead in common operations

These improvements will help make the client more competitive with other implementations while maintaining its current strengths in reliability and feature completeness.