增加熔断策略

This commit is contained in:
2026-01-01 12:05:12 +08:00
parent 1e88347e2c
commit a4a999b644

View File

@@ -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.IPNetP0支持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.IPNetP0支持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匹配P1map查找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()
}
// 重置分布式状态(如果启用)