From a4a999b6449daad6761d4c70a08717002fa7fc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Thu, 1 Jan 2026 12:05:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=86=94=E6=96=AD=E7=AD=96?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- middleware/circuit_breaker.go | 444 ++++++++++++++++++++++++++-------- 1 file changed, 343 insertions(+), 101 deletions(-) diff --git a/middleware/circuit_breaker.go b/middleware/circuit_breaker.go index 36c1832..4ca4f0e 100644 --- a/middleware/circuit_breaker.go +++ b/middleware/circuit_breaker.go @@ -3,6 +3,7 @@ package middleware import ( "context" "fmt" + "net" "strings" "sync" "sync/atomic" @@ -22,6 +23,35 @@ const ( StateOpen CircuitBreakerState = "open" // 开启:熔断状态 ) +// 熔断器状态常量(用于atomic.Int64) +const ( + stateClosed int64 = 0 + stateOpen int64 = 1 +) + +// getState 获取熔断器状态字符串 +func (cb *CircuitBreakerInfo) getState() CircuitBreakerState { + if cb.State.Load() == stateOpen { + return StateOpen + } + return StateClosed +} + +// setState 设置熔断器状态(atomic操作,无锁) +func (cb *CircuitBreakerInfo) setState(state CircuitBreakerState) CircuitBreakerState { + var newState int64 + if state == StateOpen { + newState = stateOpen + } else { + newState = stateClosed + } + oldState := cb.State.Swap(newState) + if oldState == stateOpen { + return StateOpen + } + return StateClosed +} + // CircuitBreakerConfig 熔断器配置 type CircuitBreakerConfig struct { Enabled bool // 是否启用熔断器 @@ -40,6 +70,9 @@ type CircuitBreakerConfig struct { AdminIPs []string // 允许重置熔断器的管理员IP列表 StatIntervalMs int // 统计窗口时长(毫秒),默认1000ms MinRequestAmount int // 最小请求数量,默认与MaxFailures相同 + AdminCIDRs []string // 允许重置熔断器的管理员CIDR列表(P0:支持IP段) + // P1:预编译的CIDR网络掩码(性能优化) + CIDRNetMasks []*net.IPNet } // CircuitBreakerMetrics 熔断器指标 @@ -48,19 +81,24 @@ type CircuitBreakerMetrics struct { PassRequests atomic.Int64 // 通过请求数 BlockRequests atomic.Int64 // 阻塞请求数 FailureRequests atomic.Int64 // 失败请求数 + SlowRequests atomic.Int64 // 慢请求数(P2:可观测性) OpenCount atomic.Int64 // 熔断开启次数 LastResetTime atomic.Int64 // 上次重置时间(Unix时间戳) + // 使用atomic.Int64实现简单的时间戳存储,避免使用mutex + LastOpenTime atomic.Int64 // 上次熔断时间(Unix时间戳) + NextRetryTime atomic.Int64 // 下次重试时间(Unix时间戳) } // CircuitBreakerInfo 熔断器信息 type CircuitBreakerInfo struct { - ResourceName string `json:"resourceName"` // 资源名称 - State CircuitBreakerState `json:"state"` // 当前状态 - Config *CircuitBreakerConfig `json:"config"` // 配置信息 - LastOpenTime time.Time `json:"lastOpenTime"` // 上次熔断时间 - NextRetryTime time.Time `json:"nextRetryTime"` // 下次重试时间 - Metrics *CircuitBreakerMetrics `json:"metrics"` // 指标统计 - mu sync.RWMutex // 保护状态更新 + ResourceName string `json:"resourceName"` // 资源名称 + State atomic.Int64 `json:"state"` // 当前状态(0:closed, 1:open),使用atomic避免mutex + Config *CircuitBreakerConfig `json:"config"` // 配置信息 + Metrics *CircuitBreakerMetrics `json:"metrics"` // 指标统计 + // 预编译的成功状态码集合(P1:性能优化) + SuccessCodeMap map[int]bool + // P1:预编译的CIDR网络掩码(避免重复解析) + CIDRNetMasks []*net.IPNet } var ( @@ -74,10 +112,16 @@ var ( stateChangeListeners sync.Map // stateChangeListenersRegistered 默认监听器是否已注册 stateChangeListenersRegistered sync.Map - // allowedAdminIPsCache 缓存的所有管理员IP白名单(性能优化) - allowedAdminIPsCache []string - // allowedAdminIPsCacheMutex 保护白名单缓存的并发访问 - allowedAdminIPsCacheMutex sync.RWMutex + // P1:使用map代替slice优化IP查找性能 + allowedAdminIPsMap map[string]bool + // allowedAdminIPsMutex 保护白名单缓存的并发访问 + allowedAdminIPsMutex sync.RWMutex + // P1:预编译的CIDR网络掩码列表 + allowedAdminCIDRs []*net.IPNet + // allowedAdminCIDRsMutex 保护CIDR列表的并发访问 + allowedAdminCIDRsMutex sync.RWMutex + // totalServicesCount 缓存总服务数(P1:性能优化) + totalServicesCount atomic.Int64 ) // InitCircuitBreaker 初始化Sentinel熔断器 @@ -95,9 +139,6 @@ func InitCircuitBreaker() error { g.Log().Infof(ctx, "Sentinel熔断器初始化成功") - // 更新管理员IP白名单缓存 - updateAdminIPsCache() - // 扫描配置文件中所有配置了熔断器的服务 services := g.Cfg().MustGet(ctx, "circuitBreaker").Map() @@ -109,6 +150,9 @@ func InitCircuitBreaker() error { return nil } + // P1:缓存总服务数 + totalServicesCount.Store(int64(len(serviceNames))) + // 为每个服务创建熔断器 enabledCount := 0 for _, serviceName := range serviceNames { @@ -127,6 +171,9 @@ func InitCircuitBreaker() error { } } + // P1:更新管理员IP白名单缓存(在所有服务配置加载完成后) + updateAdminIPsCache() + g.Log().Infof(ctx, "共初始化 %d 个服务熔断器,其中 %d 个已启用", len(serviceNames), enabledCount) return nil } @@ -170,12 +217,13 @@ func loadServiceCircuitBreakerConfig(serviceName string) *CircuitBreakerConfig { requestTimeout := g.Cfg().MustGet(ctx, key+".requestTimeout", 30000).Int() distributedTTL := g.Cfg().MustGet(ctx, key+".distributedTTL", 300).Int() adminIPs := g.Cfg().MustGet(ctx, key+".adminIPs", "").String() + adminCIDRs := g.Cfg().MustGet(ctx, key+".adminCIDRs", "").String() // P0:支持CIDR statIntervalMs := g.Cfg().MustGet(ctx, key+".statIntervalMs", 1000).Int() minRequestAmount := g.Cfg().MustGet(ctx, key+".minRequestAmount", 0).Int() - // 解析成功状态码 + // 解析成功状态码(使用map用于快速查找) successCodes := g.Cfg().MustGet(ctx, key+".successStatusCodes", "200,201,204").String() - statusCodes := parseStatusCodes(successCodes) + statusCodes := parseStatusCodesSlice(successCodes) // 解析时间(缓存结果,性能优化) timeoutParsed, err := time.ParseDuration(timeout) @@ -193,6 +241,13 @@ func loadServiceCircuitBreakerConfig(serviceName string) *CircuitBreakerConfig { // 解析管理员IP列表 adminIPList := parseAdminIPs(adminIPs) + // P1:预编译CIDR为net.IPNet(支持IPv4和IPv6) + cidrNets, err := parseAdminCIDRs(adminCIDRs) + if err != nil { + g.Log().Warningf(ctx, "服务 %s 的 adminCIDRs 解析失败: %v", serviceName, err) + cidrNets = nil + } + // 如果minRequestAmount未配置,则使用maxFailures作为默认值 if minRequestAmount == 0 { minRequestAmount = maxFailures @@ -213,13 +268,27 @@ func loadServiceCircuitBreakerConfig(serviceName string) *CircuitBreakerConfig { RequestTimeout: requestTimeout, DistributedTTL: distributedTTL, AdminIPs: adminIPList, + CIDRNetMasks: cidrNets, // P1:预编译的CIDR网络掩码 StatIntervalMs: statIntervalMs, MinRequestAmount: minRequestAmount, } } -// parseStatusCodes 解析HTTP状态码 -func parseStatusCodes(str string) []int { +// parseStatusCodes 解析HTTP状态码(返回map用于快速查找) +func parseStatusCodes(str string) map[int]bool { + parts := strings.Split(str, ",") + codeMap := make(map[int]bool, len(parts)) + for _, part := range parts { + var code int + if _, err := fmt.Sscanf(strings.TrimSpace(part), "%d", &code); err == nil { + codeMap[code] = true + } + } + return codeMap +} + +// parseStatusCodesSlice 解析HTTP状态码(返回切片用于配置) +func parseStatusCodesSlice(str string) []int { parts := strings.Split(str, ",") codes := make([]int, 0, len(parts)) for _, part := range parts { @@ -231,29 +300,68 @@ func parseStatusCodes(str string) []int { return codes } -// updateAdminIPsCache 更新管理员IP白名单缓存(性能优化) +// parseAdminCIDRs 解析管理员CIDR列表(P1:预编译为net.IPNet,P0:支持IPv6) +func parseAdminCIDRs(str string) ([]*net.IPNet, error) { + if str == "" { + return nil, nil + } + parts := strings.Split(str, ",") + nets := make([]*net.IPNet, 0, len(parts)) + for _, part := range parts { + cidr := strings.TrimSpace(part) + if cidr != "" { + // 使用net.ParseCIDR解析CIDR(支持IPv4和IPv6) + _, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("解析CIDR失败: %s, error: %v", cidr, err) + } + nets = append(nets, ipNet) + } + } + return nets, nil +} + +// updateAdminIPsCache 更新管理员IP白名单缓存(P1:使用map优化性能,P1:预编译CIDR) func updateAdminIPsCache() { - var ipList []string - ipSet := make(map[string]bool) + ipMap := make(map[string]bool) + cidrNets := make([]*net.IPNet, 0) // 收集所有服务的adminIPs配置 circuitBreakerConfigs.Range(func(key, value interface{}) bool { config := value.(*CircuitBreakerConfig) if len(config.AdminIPs) > 0 { for _, ip := range config.AdminIPs { - if !ipSet[ip] { - ipSet[ip] = true - ipList = append(ipList, ip) + if !ipMap[ip] { + ipMap[ip] = true } } } + // P1:使用预编译的CIDR网络掩码 + if len(config.CIDRNetMasks) > 0 { + for _, cidrNet := range config.CIDRNetMasks { + cidrNets = append(cidrNets, cidrNet) + } + } return true }) // 更新缓存 - allowedAdminIPsCacheMutex.Lock() - allowedAdminIPsCache = ipList - allowedAdminIPsCacheMutex.Unlock() + allowedAdminIPsMutex.Lock() + allowedAdminIPsMap = ipMap + allowedAdminIPsMutex.Unlock() + + allowedAdminCIDRsMutex.Lock() + allowedAdminCIDRs = cidrNets + allowedAdminCIDRsMutex.Unlock() +} + +// isIPInCIDR 检查IP是否在CIDR范围内(P1:使用预编译的net.IPNet,P0:支持IPv6) +func isIPInCIDR(ipStr string, cidrNet *net.IPNet) bool { + ip := net.ParseIP(ipStr) + if ip == nil { + return false + } + return cidrNet.Contains(ip) } // parseAdminIPs 解析管理员IP列表 @@ -341,13 +449,20 @@ func initServiceCircuitBreaker(serviceName string, config *CircuitBreakerConfig) return fmt.Errorf("加载熔断规则失败: %v", err) } - // 初始化熔断器信息 - cbInfo := &CircuitBreakerInfo{ - ResourceName: resourceName, - State: StateClosed, - Config: config, - Metrics: &CircuitBreakerMetrics{}, + // 初始化熔断器信息(P1:直接从slice构建map,避免重复解析) + successCodeMap := make(map[int]bool, len(config.SuccessStatusCodes)) + for _, code := range config.SuccessStatusCodes { + successCodeMap[code] = true } + + cbInfo := &CircuitBreakerInfo{ + ResourceName: resourceName, + Config: config, + Metrics: &CircuitBreakerMetrics{}, + SuccessCodeMap: successCodeMap, + CIDRNetMasks: config.CIDRNetMasks, + } + cbInfo.State.Store(stateClosed) cbInfo.Metrics.LastResetTime.Store(time.Now().Unix()) circuitBreakers.Store(serviceName, cbInfo) @@ -367,39 +482,32 @@ func CircuitBreakerMiddleware(r *ghttp.Request) { startTime := time.Now() ctx := r.GetCtx() - // 从URL路径提取服务名(改进提取逻辑) + // 从URL路径提取服务名并获取配置(P1:合并重复验证) serviceName := extractServiceName(r.URL.Path) if serviceName == "" { r.Middleware.Next() return } - // 获取熔断器配置 - val, ok := circuitBreakerConfigs.Load(serviceName) + // 获取熔断器信息(包含配置) + cbInfoVal, ok := circuitBreakers.Load(serviceName) if !ok { // 未配置熔断器,直接放行 r.Middleware.Next() return } - config := val.(*CircuitBreakerConfig) + cbInfo := cbInfoVal.(*CircuitBreakerInfo) + config := cbInfo.Config if !config.Enabled { // 熔断器未启用,直接放行 r.Middleware.Next() return } - - // 获取熔断器信息 - cbInfoVal, ok := circuitBreakers.Load(serviceName) - if !ok { - r.Middleware.Next() - return - } - cbInfo := cbInfoVal.(*CircuitBreakerInfo) cbInfo.Metrics.TotalRequests.Add(1) // 提前构造resourceName(性能优化) - resourceName := fmt.Sprintf("service:%s", serviceName) + resourceName := cbInfo.ResourceName // 设置请求超时(使用服务独立配置) if config.RequestTimeout > 0 { @@ -426,18 +534,15 @@ func CircuitBreakerMiddleware(r *ghttp.Request) { cbInfo.Metrics.OpenCount.Add(1) g.Log().Warningf(ctx, "熔断触发: %s, reason: %v", resourceName, blockError) - // 更新熔断器状态 - cbInfo.mu.Lock() - oldState := cbInfo.State - cbInfo.State = StateOpen - cbInfo.LastOpenTime = time.Now() - // 使用缓存的时间值(性能优化) - cbInfo.NextRetryTime = time.Now().Add(config.TimeoutParsed) - cbInfo.mu.Unlock() + // 使用atomic更新状态(无锁) + oldStateStr := cbInfo.setState(StateOpen) + now := time.Now() + cbInfo.Metrics.LastOpenTime.Store(now.Unix()) + cbInfo.Metrics.NextRetryTime.Store(now.Add(config.TimeoutParsed).Unix()) // 通知状态变化(如果状态改变) - if oldState != StateOpen { - notifyStateChange(serviceName, oldState, StateOpen) + if oldStateStr != StateOpen { + notifyStateChange(serviceName, oldStateStr, StateOpen) } // 同步到分布式存储 @@ -456,30 +561,37 @@ func CircuitBreakerMiddleware(r *ghttp.Request) { statusCode := r.Response.Status duration := time.Since(startTime) - // 使用提前获取的config判断状态码(性能优化) - if !isSuccessStatusCode(config, statusCode) { + // 判断是否为慢请求(P2:可观测性) + if duration > config.SlowRequestThresholdParsed { + cbInfo.Metrics.SlowRequests.Add(1) + } + + // 使用cbInfo.SuccessCodeMap判断状态码(性能优化) + if !isSuccessStatusCode(cbInfo, statusCode) { // 记录异常 cbInfo.Metrics.FailureRequests.Add(1) api.TraceError(entry, fmt.Errorf("request failed with status: %d", statusCode)) g.Log().Debugf(ctx, "服务 %s 请求失败: status=%d, duration=%v", serviceName, statusCode, duration) } else { cbInfo.Metrics.PassRequests.Add(1) - // 更新状态为关闭(如果之前是开启状态) - cbInfo.mu.Lock() - oldState := cbInfo.State - if cbInfo.State != StateClosed { - cbInfo.State = StateClosed - notifyStateChange(serviceName, oldState, StateClosed) + // 更新状态为关闭(如果之前是开启状态,使用atomic操作) + if cbInfo.getState() != StateClosed { + oldStateStr := cbInfo.setState(StateClosed) + if oldStateStr != StateClosed { + notifyStateChange(serviceName, oldStateStr, StateClosed) + } } - cbInfo.mu.Unlock() } // 退出Sentinel资源 entry.Exit() } -// sendFallbackResponse 发送降级响应 +// sendFallbackResponse 发送降级响应(P0:添加日志记录) func sendFallbackResponse(r *ghttp.Request, serviceName string, config *CircuitBreakerConfig, reason string) { + // P0:记录降级日志,便于问题排查 + g.Log().Warningf(r.GetCtx(), "熔断器降级: service=%s, reason=%s, clientIP=%s", serviceName, reason, r.GetClientIp()) + if config.EnableFallback && config.FallbackMessage != "" { // 自定义降级消息 r.Response.WriteStatusExit(503, config.FallbackMessage) @@ -496,21 +608,16 @@ func sendFallbackResponse(r *ghttp.Request, serviceName string, config *CircuitB } } -// isSuccessStatusCode 判断HTTP状态码是否成功 -func isSuccessStatusCode(config *CircuitBreakerConfig, statusCode int) bool { - if len(config.SuccessStatusCodes) > 0 { - for _, code := range config.SuccessStatusCodes { - if statusCode == code { - return true - } - } - return false +// isSuccessStatusCode 判断HTTP状态码是否成功(使用cbInfo.SuccessCodeMap优化性能) +func isSuccessStatusCode(cbInfo *CircuitBreakerInfo, statusCode int) bool { + if cbInfo.SuccessCodeMap != nil && len(cbInfo.SuccessCodeMap) > 0 { + return cbInfo.SuccessCodeMap[statusCode] } // 默认:2xx状态码为成功 return statusCode >= 200 && statusCode < 300 } -// extractServiceName 从URL路径提取服务名(改进提取逻辑) +// extractServiceName 从URL路径提取服务名(P0:添加URL编码处理) func extractServiceName(path string) string { // 去除首尾斜杠并分割 path = strings.Trim(path, "/") @@ -523,6 +630,19 @@ func extractServiceName(path string) string { } serviceName := parts[0] + // P0:处理URL编码,将 %2F 等转义字符还原 + // 注意:在goframe的网关中间件中,路径通常已经被框架处理过 + // 但为了安全性,这里对包含%的情况进行简单处理 + if strings.Contains(serviceName, "%") { + // 尝试解码URL编码的字符串 + // 使用path.Unescape而不是url.QueryUnescape,因为我们处理的是路径片段 + decoded, err := pathUnescape(serviceName) + if err == nil { + serviceName = decoded + } + // 如果解码失败,继续使用原始serviceName + } + // 验证服务名是否在已配置的熔断器中 if _, ok := circuitBreakerConfigs.Load(serviceName); ok { return serviceName @@ -530,6 +650,56 @@ func extractServiceName(path string) string { return "" } +// pathUnescape 路径片段的URL解码(P0:安全性改进) +// 注意:Go 1.8+ 可以使用 path.Unescape,这里提供兼容实现 +func pathUnescape(s string) (string, error) { + // 使用strings.Builder优化性能 + var builder strings.Builder + builder.Grow(len(s)) + + for i := 0; i < len(s); i++ { + switch s[i] { + case '%': + // 处理百分号编码 + if i+2 >= len(s) { + // 不完整的编码,保留原样 + builder.WriteByte(s[i]) + continue + } + // 解析十六进制数字 + high := hexDigit(s[i+1]) + low := hexDigit(s[i+2]) + if high == 0xFF || low == 0xFF { + // 无效的十六进制,保留原样 + builder.WriteByte(s[i]) + continue + } + builder.WriteByte((high << 4) | low) + i += 2 + case '+': + // 路径片段中的+通常不需要解码为空格 + builder.WriteByte('+') + default: + builder.WriteByte(s[i]) + } + } + return builder.String(), nil +} + +// hexDigit 将十六进制字符转换为对应的数值 +func hexDigit(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + default: + return 0xFF // 无效字符 + } +} + // isCircuitBreakerOpenInDistributed 检查分布式熔断状态 func isCircuitBreakerOpenInDistributed(ctx context.Context, resourceName string) bool { key := fmt.Sprintf("circuit_breaker:%s:state", resourceName) @@ -651,45 +821,95 @@ func notifyStateChange(serviceName string, fromState, toState CircuitBreakerStat }) } -// CircuitBreakerHealthCheckHandler 熔断器健康检查接口 +// CircuitBreakerHealthCheckHandler 熔断器健康检查接口(P0:添加IP白名单验证,P1:添加分页支持,P1:优化性能) func CircuitBreakerHealthCheckHandler(r *ghttp.Request) { + // P0:权限验证 + if !isAdminIP(r) { + r.Response.WriteJsonExit(ghttp.DefaultHandlerResponse{ + Code: 403, + Message: "权限不足,禁止访问", + }) + return + } + status := make(map[string]interface{}) totalServices := 0 openServices := 0 - // 遍历所有熔断器 + // P1:分页参数 + page := r.Get("page").Int() + size := r.Get("size").Int() + if page < 0 { + page = 0 + } + if size <= 0 || size > 100 { + size = 20 // 默认20条,最多100条 + } + + // P1:使用缓存的totalServicesCount避免每次遍历 + total := int(totalServicesCount.Load()) + start := page * size + + // P1:只遍历分页范围内的服务(通过计数跳过) + end := start + size + if end > total { + end = total + } + + current := 0 circuitBreakers.Range(func(key, value interface{}) bool { + // 跳过前面的页 + if current < start { + current++ + return true + } + // 只处理当前页 + if current >= end { + return false + } + serviceName := key.(string) cbInfo := value.(*CircuitBreakerInfo) totalServices++ - cbInfo.mu.RLock() - isOpen := cbInfo.State == StateOpen + isOpen := cbInfo.getState() == StateOpen if isOpen { openServices++ } - // 从Metrics中读取数据(修复数据准确性问题) + // 从Metrics中读取数据(使用atomic) lastResetTime := cbInfo.Metrics.LastResetTime.Load() var lastResetTimeStr string if lastResetTime > 0 { lastResetTimeStr = time.Unix(lastResetTime, 0).Format("2006-01-02 15:04:05") } + lastOpenTime := cbInfo.Metrics.LastOpenTime.Load() + var lastOpenTimeStr string + if lastOpenTime > 0 { + lastOpenTimeStr = time.Unix(lastOpenTime, 0).Format("2006-01-02 15:04:05") + } + + nextRetryTime := cbInfo.Metrics.NextRetryTime.Load() + var nextRetryTimeStr string + if nextRetryTime > 0 { + nextRetryTimeStr = time.Unix(nextRetryTime, 0).Format("2006-01-02 15:04:05") + } + status[serviceName] = map[string]interface{}{ "resource": cbInfo.ResourceName, - "state": string(cbInfo.State), - "lastOpenTime": cbInfo.LastOpenTime, - "nextRetryTime": cbInfo.NextRetryTime, + "state": string(cbInfo.getState()), + "lastOpenTime": lastOpenTimeStr, + "nextRetryTime": nextRetryTimeStr, "totalRequests": cbInfo.Metrics.TotalRequests.Load(), "passRequests": cbInfo.Metrics.PassRequests.Load(), "blockRequests": cbInfo.Metrics.BlockRequests.Load(), "failureRequests": cbInfo.Metrics.FailureRequests.Load(), + "slowRequests": cbInfo.Metrics.SlowRequests.Load(), "openCount": cbInfo.Metrics.OpenCount.Load(), "lastResetTime": lastResetTimeStr, } - cbInfo.mu.RUnlock() - + current++ return true }) @@ -705,31 +925,54 @@ func CircuitBreakerHealthCheckHandler(r *ghttp.Request) { Data: map[string]interface{}{ "summary": summary, "services": status, + "page": page, + "size": size, + "total": total, }, }) } -// isAdminIP 检查请求IP是否在管理员白名单中(使用缓存优化性能) +// isAdminIP 检查请求IP是否在管理员白名单中(P1:使用map优化性能,P0:支持IPv6 CIDR) func isAdminIP(r *ghttp.Request) bool { clientIP := r.GetClientIp() if clientIP == "" { return false } - // 读取缓存的白名单(性能优化) - allowedAdminIPsCacheMutex.RLock() - allowedIPs := allowedAdminIPsCache - allowedAdminIPsCacheMutex.RUnlock() + // 读取缓存的IP白名单(P1:使用map实现O(1)查找) + allowedAdminIPsMutex.RLock() + allowedIPs := allowedAdminIPsMap + allowedAdminIPsMutex.RUnlock() // 如果没有配置白名单,允许所有IP(向后兼容) if len(allowedIPs) == 0 { + allowedAdminCIDRsMutex.RLock() + hasCIDRs := len(allowedAdminCIDRs) > 0 + allowedAdminCIDRsMutex.RUnlock() + // 如果也没有CIDR,则允许所有IP + if !hasCIDRs { + return true + } + } + + // 精确IP匹配(P1:map查找O(1)) + if allowedIPs[clientIP] { return true } - // 检查IP是否在白名单中 - for _, allowedIP := range allowedIPs { - if clientIP == allowedIP { - return true + // P1:使用预编译的CIDR网络掩码匹配(支持IPv4和IPv6) + allowedAdminCIDRsMutex.RLock() + cidrNets := allowedAdminCIDRs + allowedAdminCIDRsMutex.RUnlock() + + if len(cidrNets) > 0 { + clientNetIP := net.ParseIP(clientIP) + if clientNetIP != nil { + for _, cidrNet := range cidrNets { + if cidrNet.Contains(clientNetIP) { + return true + } + } } } @@ -787,21 +1030,20 @@ func CircuitBreakerResetHandler(r *ghttp.Request) { } } - // 更新内存状态并重置指标 + // 更新内存状态并重置指标(使用atomic操作) if val, ok := circuitBreakers.Load(serviceName); ok { cbInfo := val.(*CircuitBreakerInfo) - cbInfo.mu.Lock() - cbInfo.State = StateClosed - cbInfo.LastOpenTime = time.Time{} - cbInfo.NextRetryTime = time.Time{} + cbInfo.State.Store(stateClosed) + cbInfo.Metrics.LastOpenTime.Store(0) + cbInfo.Metrics.NextRetryTime.Store(0) // 重置指标 cbInfo.Metrics.TotalRequests.Store(0) cbInfo.Metrics.PassRequests.Store(0) cbInfo.Metrics.BlockRequests.Store(0) cbInfo.Metrics.FailureRequests.Store(0) + cbInfo.Metrics.SlowRequests.Store(0) cbInfo.Metrics.OpenCount.Store(0) cbInfo.Metrics.LastResetTime.Store(time.Now().Unix()) - cbInfo.mu.Unlock() } // 重置分布式状态(如果启用)