增加熔断策略
This commit is contained in:
@@ -221,6 +221,43 @@ func (cb *CircuitBreakerInfo) updateStateMetrics(state CircuitBreakerState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getCircuitBreakerInfoAndConfig 获取熔断器信息和配置
|
||||||
|
func getCircuitBreakerInfoAndConfig(serviceName string) (*CircuitBreakerInfo, *CircuitBreakerConfig) {
|
||||||
|
cbInfoVal, ok := circuitBreakers.Load(serviceName)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cbInfo, ok := cbInfoVal.(*CircuitBreakerInfo)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbInfo, cbInfo.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateResponseTimeStats 更新响应时间统计
|
||||||
|
func updateResponseTimeStats(cbInfo *CircuitBreakerInfo, duration time.Duration, config *CircuitBreakerConfig) {
|
||||||
|
durationNs := duration.Nanoseconds()
|
||||||
|
cbInfo.Metrics.TotalResponseTime.Add(durationNs)
|
||||||
|
|
||||||
|
// 原子更新最小和最大响应时间
|
||||||
|
atomicUpdateMin(&cbInfo.Metrics.MinResponseTime, durationNs)
|
||||||
|
atomicUpdateMax(&cbInfo.Metrics.MaxResponseTime, durationNs)
|
||||||
|
|
||||||
|
if duration > config.SlowRequestThresholdParsed {
|
||||||
|
cbInfo.Metrics.SlowRequests.Add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatUnixTime 格式化Unix时间戳
|
||||||
|
func formatUnixTime(timestamp int64) string {
|
||||||
|
if timestamp > 0 {
|
||||||
|
return time.Unix(timestamp, 0).Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// InitCircuitBreaker 初始化Sentinel熔断器
|
// InitCircuitBreaker 初始化Sentinel熔断器
|
||||||
func InitCircuitBreaker() error {
|
func InitCircuitBreaker() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -398,14 +435,24 @@ func atomicUpdateMax(maxValue *atomic.Int64, newValue int64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAllowedIPs 获取允许的IP列表(带锁保护)
|
// getAllowedIPsAndCIDRs 获取允许的IP和CIDR列表(带锁保护)
|
||||||
|
func getAllowedIPsAndCIDRs() (map[string]bool, []*net.IPNet) {
|
||||||
|
allowedAdminIPsMutex.RLock()
|
||||||
|
allowedAdminCIDRsMutex.RLock()
|
||||||
|
defer allowedAdminIPsMutex.RUnlock()
|
||||||
|
defer allowedAdminCIDRsMutex.RUnlock()
|
||||||
|
|
||||||
|
return allowedAdminIPsMap, allowedAdminCIDRs
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAllowedIPs 获取允许的IP列表(带锁保护,兼容旧代码)
|
||||||
func getAllowedIPs() map[string]bool {
|
func getAllowedIPs() map[string]bool {
|
||||||
allowedAdminIPsMutex.RLock()
|
allowedAdminIPsMutex.RLock()
|
||||||
defer allowedAdminIPsMutex.RUnlock()
|
defer allowedAdminIPsMutex.RUnlock()
|
||||||
return allowedAdminIPsMap
|
return allowedAdminIPsMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAllowedCIDRs 获取允许的CIDR列表(带锁保护)
|
// getAllowedCIDRs 获取允许的CIDR列表(带锁保护,兼容旧代码)
|
||||||
func getAllowedCIDRs() []*net.IPNet {
|
func getAllowedCIDRs() []*net.IPNet {
|
||||||
allowedAdminCIDRsMutex.RLock()
|
allowedAdminCIDRsMutex.RLock()
|
||||||
defer allowedAdminCIDRsMutex.RUnlock()
|
defer allowedAdminCIDRsMutex.RUnlock()
|
||||||
@@ -495,41 +542,57 @@ func (cb *CircuitBreakerInfo) updateWindowStats(isSuccess bool, ctx context.Cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateInRange 验证值是否在指定范围内
|
||||||
|
func validateInRange(name string, value, min, max int) error {
|
||||||
|
if value < min || value > max {
|
||||||
|
return fmt.Errorf("%s必须在%d-%d之间", name, min, max)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateFloatInRange 验证浮点数值是否在指定范围内
|
||||||
|
func validateFloatInRange(name string, value, min, max float64) error {
|
||||||
|
if value < min || value > max {
|
||||||
|
return fmt.Errorf("%s必须在%.1f-%.1f之间", name, min, max)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// validateCircuitBreakerConfig 验证配置
|
// validateCircuitBreakerConfig 验证配置
|
||||||
func validateCircuitBreakerConfig(config *CircuitBreakerConfig) error {
|
func validateCircuitBreakerConfig(config *CircuitBreakerConfig) error {
|
||||||
if config.MaxFailures <= 0 {
|
if config.MaxFailures <= 0 {
|
||||||
return fmt.Errorf("maxFailures必须大于0")
|
return fmt.Errorf("maxFailures必须大于0")
|
||||||
}
|
}
|
||||||
if config.FailureRateThreshold < 0 || config.FailureRateThreshold > 1 {
|
if err := validateFloatInRange("failureRateThreshold", config.FailureRateThreshold, 0.0, 1.0); err != nil {
|
||||||
return fmt.Errorf("failureRateThreshold必须在0.0-1.0之间")
|
return err
|
||||||
}
|
}
|
||||||
if len(config.SuccessStatusCodes) == 0 {
|
if len(config.SuccessStatusCodes) == 0 {
|
||||||
return fmt.Errorf("successStatusCodes不能为空")
|
return fmt.Errorf("successStatusCodes不能为空")
|
||||||
}
|
}
|
||||||
if config.RequestTimeout < 0 || config.RequestTimeout > 300000 {
|
if err := validateInRange("requestTimeout", config.RequestTimeout, 0, 300000); err != nil {
|
||||||
return fmt.Errorf("requestTimeout必须在0-300000毫秒之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.DistributedTTL < 0 || config.DistributedTTL > 3600 {
|
if err := validateInRange("distributedTTL", config.DistributedTTL, 0, 3600); err != nil {
|
||||||
return fmt.Errorf("distributedTTL必须在0-3600秒之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.StatIntervalMs < 100 || config.StatIntervalMs > 60000 {
|
if err := validateInRange("statIntervalMs", config.StatIntervalMs, 100, 60000); err != nil {
|
||||||
return fmt.Errorf("statIntervalMs必须在100-60000毫秒之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.MinRequestAmount < 1 || config.MinRequestAmount > 10000 {
|
if err := validateInRange("minRequestAmount", config.MinRequestAmount, 1, 10000); err != nil {
|
||||||
return fmt.Errorf("minRequestAmount必须在1-10000之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.HalfOpenMaxRequests < 1 || config.HalfOpenMaxRequests > 100 {
|
if err := validateInRange("halfOpenMaxRequests", config.HalfOpenMaxRequests, 1, 100); err != nil {
|
||||||
return fmt.Errorf("halfOpenMaxRequests必须在1-100之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.HalfOpenSuccessThreshold < 0 || config.HalfOpenSuccessThreshold > 1 {
|
if err := validateFloatInRange("halfOpenSuccessThreshold", config.HalfOpenSuccessThreshold, 0.0, 1.0); err != nil {
|
||||||
return fmt.Errorf("halfOpenSuccessThreshold必须在0.0-1.0之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.EnableAdaptiveThreshold {
|
if config.EnableAdaptiveThreshold {
|
||||||
if config.AdaptiveMinThreshold < 0 || config.AdaptiveMinThreshold > 1 {
|
if err := validateFloatInRange("adaptiveMinThreshold", config.AdaptiveMinThreshold, 0.0, 1.0); err != nil {
|
||||||
return fmt.Errorf("adaptiveMinThreshold必须在0.0-1.0之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.AdaptiveMaxThreshold < 0 || config.AdaptiveMaxThreshold > 1 {
|
if err := validateFloatInRange("adaptiveMaxThreshold", config.AdaptiveMaxThreshold, 0.0, 1.0); err != nil {
|
||||||
return fmt.Errorf("adaptiveMaxThreshold必须在0.0-1.0之间")
|
return err
|
||||||
}
|
}
|
||||||
if config.AdaptiveMinThreshold >= config.AdaptiveMaxThreshold {
|
if config.AdaptiveMinThreshold >= config.AdaptiveMaxThreshold {
|
||||||
return fmt.Errorf("adaptiveMinThreshold必须小于adaptiveMaxThreshold")
|
return fmt.Errorf("adaptiveMinThreshold必须小于adaptiveMaxThreshold")
|
||||||
@@ -618,19 +681,8 @@ func CircuitBreakerMiddleware(r *ghttp.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cbInfoVal, ok := circuitBreakers.Load(serviceName)
|
cbInfo, config := getCircuitBreakerInfoAndConfig(serviceName)
|
||||||
if !ok {
|
if cbInfo == nil || config == nil || !config.Enabled {
|
||||||
r.Middleware.Next()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cbInfo, ok := cbInfoVal.(*CircuitBreakerInfo)
|
|
||||||
if !ok {
|
|
||||||
r.Middleware.Next()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
config := cbInfo.Config
|
|
||||||
if !config.Enabled {
|
|
||||||
r.Middleware.Next()
|
r.Middleware.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -718,16 +770,7 @@ func CircuitBreakerMiddleware(r *ghttp.Request) {
|
|||||||
duration := time.Since(startTime)
|
duration := time.Since(startTime)
|
||||||
|
|
||||||
// 记录响应时间统计
|
// 记录响应时间统计
|
||||||
durationNs := duration.Nanoseconds()
|
updateResponseTimeStats(cbInfo, duration, config)
|
||||||
cbInfo.Metrics.TotalResponseTime.Add(durationNs)
|
|
||||||
|
|
||||||
// 原子更新最小和最大响应时间
|
|
||||||
atomicUpdateMin(&cbInfo.Metrics.MinResponseTime, durationNs)
|
|
||||||
atomicUpdateMax(&cbInfo.Metrics.MaxResponseTime, durationNs)
|
|
||||||
|
|
||||||
if duration > config.SlowRequestThresholdParsed {
|
|
||||||
cbInfo.Metrics.SlowRequests.Add(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
isSuccess := isSuccessStatusCode(cbInfo, statusCode)
|
isSuccess := isSuccessStatusCode(cbInfo, statusCode)
|
||||||
|
|
||||||
@@ -1036,23 +1079,10 @@ func CircuitBreakerHealthCheckHandler(r *ghttp.Request) {
|
|||||||
halfOpenServices++
|
halfOpenServices++
|
||||||
}
|
}
|
||||||
|
|
||||||
lastResetTime := cbInfo.Metrics.LastResetTime.Load()
|
// 格式化时间字符串
|
||||||
var lastResetTimeStr string
|
lastResetTimeStr := formatUnixTime(cbInfo.Metrics.LastResetTime.Load())
|
||||||
if lastResetTime > 0 {
|
lastOpenTimeStr := formatUnixTime(cbInfo.Metrics.LastOpenTime.Load())
|
||||||
lastResetTimeStr = time.Unix(lastResetTime, 0).Format("2006-01-02 15:04:05")
|
nextRetryTimeStr := formatUnixTime(cbInfo.Metrics.NextRetryTime.Load())
|
||||||
}
|
|
||||||
|
|
||||||
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{}{
|
status[serviceName] = map[string]interface{}{
|
||||||
"resource": cbInfo.ResourceName,
|
"resource": cbInfo.ResourceName,
|
||||||
@@ -1084,8 +1114,8 @@ func isAdminIP(r *ghttp.Request) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedIPs := getAllowedIPs()
|
// 一次性获取IP和CIDR列表,减少锁操作
|
||||||
allowedCIDRs := getAllowedCIDRs()
|
allowedIPs, allowedCIDRs := getAllowedIPsAndCIDRs()
|
||||||
|
|
||||||
// 如果没有任何限制,允许访问
|
// 如果没有任何限制,允许访问
|
||||||
if len(allowedIPs) == 0 && len(allowedCIDRs) == 0 {
|
if len(allowedIPs) == 0 && len(allowedCIDRs) == 0 {
|
||||||
@@ -1098,8 +1128,7 @@ func isAdminIP(r *ghttp.Request) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查CIDR白名单
|
// 检查CIDR白名单
|
||||||
clientNetIP := net.ParseIP(clientIP)
|
if clientNetIP := net.ParseIP(clientIP); clientNetIP != nil {
|
||||||
if clientNetIP != nil {
|
|
||||||
for _, cidrNet := range allowedCIDRs {
|
for _, cidrNet := range allowedCIDRs {
|
||||||
if cidrNet.Contains(clientNetIP) {
|
if cidrNet.Contains(clientNetIP) {
|
||||||
return true
|
return true
|
||||||
|
|||||||
Reference in New Issue
Block a user