1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-22 10:01:50 +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

809 lines
21 KiB
Markdown

# 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:
```go
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
```go
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
```go
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
```go
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:
```go
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:
```go
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:
```go
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:
```go
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:
```go
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
```go
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
```go
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:
```go
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:
```go
// 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:
```go
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.