package binanceservice import ( "context" "fmt" "sync" "time" "github.com/go-admin-team/go-admin-core/logger" "github.com/go-redis/redis/v8" ) // LockManagerConfig 锁管理器专用配置 type LockManagerConfig struct { Type LockType `json:"type"` Scope LockScope `json:"scope"` Key string `json:"key"` Expiration time.Duration `json:"expiration"` Timeout time.Duration `json:"timeout"` RetryDelay time.Duration `json:"retry_delay"` } // LockType 锁类型 type LockType string const ( LockTypeLocal LockType = "local" LockTypeDistributed LockType = "distributed" ) // LockScope 锁范围 type LockScope string const ( ScopeOrder LockScope = "order" ScopePosition LockScope = "position" ScopeUser LockScope = "user" ScopeSymbol LockScope = "symbol" ScopeGlobal LockScope = "global" ) // Lock 锁接口 type Lock interface { Lock(ctx context.Context) error Unlock(ctx context.Context) error TryLock(ctx context.Context) (bool, error) IsLocked() bool GetKey() string GetExpiration() time.Duration } // LocalLock 本地锁 type LocalLock struct { key string mu *sync.RWMutex locked bool expiration time.Duration acquiredAt time.Time } // DistributedLock 分布式锁 type DistributedLock struct { key string value string expiration time.Duration redisClient *redis.Client locked bool acquiredAt time.Time refreshTicker *time.Ticker stopRefresh chan struct{} } // LockManager 锁管理器 type LockManager struct { config *OptimizedConfig redisClient *redis.Client localLocks map[string]*LocalLock localMutex sync.RWMutex metrics *MetricsCollector } // LockConfig 已在 config_optimized.go 中定义 // NewLockManager 创建锁管理器 func NewLockManager(config *OptimizedConfig, redisClient *redis.Client, metrics *MetricsCollector) *LockManager { return &LockManager{ config: config, redisClient: redisClient, localLocks: make(map[string]*LocalLock), metrics: metrics, } } // CreateLock 创建锁 func (lm *LockManager) CreateLock(config LockManagerConfig) Lock { switch config.Type { case LockTypeDistributed: return lm.createDistributedLock(config) case LockTypeLocal: return lm.createLocalLock(config) default: // 默认使用分布式锁 return lm.createDistributedLock(config) } } // createLocalLock 创建本地锁 func (lm *LockManager) createLocalLock(config LockManagerConfig) *LocalLock { lm.localMutex.Lock() defer lm.localMutex.Unlock() key := lm.buildLockKey(config.Scope, config.Key) if lock, exists := lm.localLocks[key]; exists { return lock } lock := &LocalLock{ key: key, mu: &sync.RWMutex{}, expiration: config.Expiration, } lm.localLocks[key] = lock return lock } // createDistributedLock 创建分布式锁 func (lm *LockManager) createDistributedLock(config LockManagerConfig) *DistributedLock { key := lm.buildLockKey(config.Scope, config.Key) value := fmt.Sprintf("%d_%s", time.Now().UnixNano(), generateRandomString(8)) return &DistributedLock{ key: key, value: value, expiration: config.Expiration, redisClient: lm.redisClient, stopRefresh: make(chan struct{}), } } // buildLockKey 构建锁键名 func (lm *LockManager) buildLockKey(scope LockScope, key string) string { return fmt.Sprintf("lock:%s:%s", scope, key) } // AcquireLock 获取锁(带超时和重试) func (lm *LockManager) AcquireLock(ctx context.Context, config LockManagerConfig) (Lock, error) { lock := lm.CreateLock(config) startTime := time.Now() // 设置超时上下文 lockCtx := ctx if config.Timeout > 0 { var cancel context.CancelFunc lockCtx, cancel = context.WithTimeout(ctx, config.Timeout) defer cancel() } // 重试获取锁 for { select { case <-lockCtx.Done(): waitTime := time.Since(startTime) if lm.metrics != nil { lm.metrics.RecordLockOperation(false, waitTime) } return nil, fmt.Errorf("获取锁超时: %s", config.Key) default: err := lock.Lock(lockCtx) if err == nil { waitTime := time.Since(startTime) if lm.metrics != nil { lm.metrics.RecordLockOperation(true, waitTime) } return lock, nil } // 等待重试 select { case <-lockCtx.Done(): return nil, lockCtx.Err() case <-time.After(config.RetryDelay): continue } } } } // ReleaseLock 释放锁 func (lm *LockManager) ReleaseLock(ctx context.Context, lock Lock) error { if lock == nil { return nil } return lock.Unlock(ctx) } // WithLock 使用锁执行操作 func (lm *LockManager) WithLock(ctx context.Context, config LockManagerConfig, operation func() error) error { lock, err := lm.AcquireLock(ctx, config) if err != nil { return fmt.Errorf("获取锁失败: %w", err) } defer func() { if unlockErr := lm.ReleaseLock(ctx, lock); unlockErr != nil { logger.Errorf("释放锁失败 [%s]: %v", config.Key, unlockErr) } }() return operation() } // CleanupExpiredLocks 清理过期的本地锁 func (lm *LockManager) CleanupExpiredLocks() { lm.localMutex.Lock() defer lm.localMutex.Unlock() now := time.Now() for key, lock := range lm.localLocks { if lock.locked && lock.expiration > 0 && now.Sub(lock.acquiredAt) > lock.expiration { lock.locked = false logger.Warnf("本地锁已过期并被清理: %s", key) } } } // GetLockStatus 获取锁状态 func (lm *LockManager) GetLockStatus() map[string]interface{} { lm.localMutex.RLock() defer lm.localMutex.RUnlock() status := make(map[string]interface{}) localLocks := make(map[string]interface{}) for key, lock := range lm.localLocks { localLocks[key] = map[string]interface{}{ "locked": lock.locked, "acquired_at": lock.acquiredAt, "expiration": lock.expiration, } } status["local_locks"] = localLocks status["total_local_locks"] = len(lm.localLocks) return status } // LocalLock 实现 // Lock 获取本地锁 func (ll *LocalLock) Lock(ctx context.Context) error { ll.mu.Lock() defer ll.mu.Unlock() if ll.locked { return fmt.Errorf("锁已被占用: %s", ll.key) } ll.locked = true ll.acquiredAt = time.Now() return nil } // Unlock 释放本地锁 func (ll *LocalLock) Unlock(ctx context.Context) error { ll.mu.Lock() defer ll.mu.Unlock() if !ll.locked { return fmt.Errorf("锁未被占用: %s", ll.key) } ll.locked = false return nil } // TryLock 尝试获取本地锁 func (ll *LocalLock) TryLock(ctx context.Context) (bool, error) { ll.mu.Lock() defer ll.mu.Unlock() if ll.locked { return false, nil } ll.locked = true ll.acquiredAt = time.Now() return true, nil } // IsLocked 检查本地锁是否被占用 func (ll *LocalLock) IsLocked() bool { ll.mu.RLock() defer ll.mu.RUnlock() return ll.locked } // GetKey 获取锁键名 func (ll *LocalLock) GetKey() string { return ll.key } // GetExpiration 获取过期时间 func (ll *LocalLock) GetExpiration() time.Duration { return ll.expiration } // DistributedLock 实现 // Lock 获取分布式锁 func (dl *DistributedLock) Lock(ctx context.Context) error { // 使用 SET key value EX seconds NX 命令 result := dl.redisClient.SetNX(ctx, dl.key, dl.value, dl.expiration) if result.Err() != nil { return fmt.Errorf("获取分布式锁失败: %w", result.Err()) } if !result.Val() { return fmt.Errorf("分布式锁已被占用: %s", dl.key) } dl.locked = true dl.acquiredAt = time.Now() // 启动锁续期 dl.startRefresh() return nil } // Unlock 释放分布式锁 func (dl *DistributedLock) Unlock(ctx context.Context) error { if !dl.locked { return fmt.Errorf("分布式锁未被占用: %s", dl.key) } // 停止续期 dl.stopRefreshProcess() // 使用 Lua 脚本确保只删除自己的锁 luaScript := ` if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end ` result := dl.redisClient.Eval(ctx, luaScript, []string{dl.key}, dl.value) if result.Err() != nil { return fmt.Errorf("释放分布式锁失败: %w", result.Err()) } dl.locked = false return nil } // TryLock 尝试获取分布式锁 func (dl *DistributedLock) TryLock(ctx context.Context) (bool, error) { result := dl.redisClient.SetNX(ctx, dl.key, dl.value, dl.expiration) if result.Err() != nil { return false, fmt.Errorf("尝试获取分布式锁失败: %w", result.Err()) } if result.Val() { dl.locked = true dl.acquiredAt = time.Now() dl.startRefresh() return true, nil } return false, nil } // IsLocked 检查分布式锁是否被占用 func (dl *DistributedLock) IsLocked() bool { return dl.locked } // GetKey 获取锁键名 func (dl *DistributedLock) GetKey() string { return dl.key } // GetExpiration 获取过期时间 func (dl *DistributedLock) GetExpiration() time.Duration { return dl.expiration } // startRefresh 启动锁续期 func (dl *DistributedLock) startRefresh() { if dl.expiration <= 0 { return } // 每隔过期时间的1/3进行续期 refreshInterval := dl.expiration / 3 dl.refreshTicker = time.NewTicker(refreshInterval) go func() { defer dl.refreshTicker.Stop() for { select { case <-dl.stopRefresh: return case <-dl.refreshTicker.C: if !dl.locked { return } // 使用 Lua 脚本续期 luaScript := ` if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("expire", KEYS[1], ARGV[2]) else return 0 end ` ctx := context.Background() result := dl.redisClient.Eval(ctx, luaScript, []string{dl.key}, dl.value, int(dl.expiration.Seconds())) if result.Err() != nil { logger.Errorf("分布式锁续期失败 [%s]: %v", dl.key, result.Err()) return } if result.Val().(int64) == 0 { logger.Warnf("分布式锁已被其他进程占用,停止续期 [%s]", dl.key) dl.locked = false return } } } }() } // stopRefreshProcess 停止续期进程 func (dl *DistributedLock) stopRefreshProcess() { if dl.refreshTicker != nil { close(dl.stopRefresh) dl.refreshTicker.Stop() dl.refreshTicker = nil dl.stopRefresh = make(chan struct{}) } } // 辅助函数 // generateRandomString 生成随机字符串 func generateRandomString(length int) string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, length) for i := range b { b[i] = charset[time.Now().UnixNano()%int64(len(charset))] } return string(b) } // 预定义的锁配置 // GetOrderLockConfig 获取订单锁配置 func GetOrderLockConfig(orderID string) LockManagerConfig { return LockManagerConfig{ Type: LockTypeDistributed, Scope: ScopeOrder, Key: orderID, Expiration: 30 * time.Second, Timeout: 5 * time.Second, RetryDelay: 100 * time.Millisecond, } } // GetPositionLockConfig 获取持仓锁配置 func GetPositionLockConfig(userID, symbol string) LockManagerConfig { return LockManagerConfig{ Type: LockTypeDistributed, Scope: ScopePosition, Key: fmt.Sprintf("%s_%s", userID, symbol), Expiration: 60 * time.Second, Timeout: 10 * time.Second, RetryDelay: 200 * time.Millisecond, } } // GetUserLockConfig 获取用户锁配置 func GetUserLockConfig(userID string) LockManagerConfig { return LockManagerConfig{ Type: LockTypeLocal, Scope: ScopeUser, Key: userID, Expiration: 30 * time.Second, Timeout: 3 * time.Second, RetryDelay: 50 * time.Millisecond, } } // GetSymbolLockConfig 获取交易对锁配置 func GetSymbolLockConfig(symbol string) LockManagerConfig { return LockManagerConfig{ Type: LockTypeLocal, Scope: ScopeSymbol, Key: symbol, Expiration: 15 * time.Second, Timeout: 2 * time.Second, RetryDelay: 25 * time.Millisecond, } } // GetGlobalLockConfig 获取全局锁配置 func GetGlobalLockConfig(operation string) LockManagerConfig { return LockManagerConfig{ Type: LockTypeDistributed, Scope: ScopeGlobal, Key: operation, Expiration: 120 * time.Second, Timeout: 30 * time.Second, RetryDelay: 500 * time.Millisecond, } } // 全局锁管理器实例 var GlobalLockManager *LockManager // InitLockManager 初始化锁管理器 func InitLockManager(config *OptimizedConfig, redisClient *redis.Client, metrics *MetricsCollector) { GlobalLockManager = NewLockManager(config, redisClient, metrics) // 启动清理过期锁的定时任务 go func() { ticker := time.NewTicker(time.Minute) defer ticker.Stop() for range ticker.C { GlobalLockManager.CleanupExpiredLocks() } }() } // GetLockManager 获取全局锁管理器 func GetLockManager() *LockManager { return GlobalLockManager } // WithOrderLock 使用订单锁执行操作 func WithOrderLock(ctx context.Context, orderID string, operation func() error) error { if GlobalLockManager == nil { return operation() } config := GetOrderLockConfig(orderID) return GlobalLockManager.WithLock(ctx, config, operation) } // WithPositionLock 使用持仓锁执行操作 func WithPositionLock(ctx context.Context, userID, symbol string, operation func() error) error { if GlobalLockManager == nil { return operation() } config := GetPositionLockConfig(userID, symbol) return GlobalLockManager.WithLock(ctx, config, operation) } // WithUserLock 使用用户锁执行操作 func WithUserLock(ctx context.Context, userID string, operation func() error) error { if GlobalLockManager == nil { return operation() } config := GetUserLockConfig(userID) return GlobalLockManager.WithLock(ctx, config, operation) }