From 9194e497e08dbcd3de5bd3284ecd27a0cc6b8d47 Mon Sep 17 00:00:00 2001 From: undertaker86001 Date: Fri, 15 Aug 2025 17:05:57 +0800 Subject: [PATCH] [issue-275](https://github.com/iohao/ioGame/issues/275) add apadtive ratelimit --- .../core/config/ExternalGlobalConfig.java | 39 ++ .../core/monitor/SystemResourceMonitor.java | 414 +++++++++++++++++ .../core/protection/TrafficProtector.java | 184 ++++++++ .../core/ratelimit/AbstractRateLimiter.java | 272 +++++++++++ .../core/ratelimit/AdaptiveRateLimiter.java | 437 ++++++++++++++++++ .../core/ratelimit/Gradient2RateLimiter.java | 217 +++++++++ .../external/core/ratelimit/RateLimiter.java | 152 ++++++ .../core/ratelimit/VegasRateLimiter.java | 248 ++++++++++ .../ratelimit/Gradient2RateLimiterTest.java | 246 ++++++++++ .../ratelimit/GradientRateLimiterTest.java | 182 ++++++++ .../ratelimit/RateLimiterIntegrationTest.java | 285 ++++++++++++ .../core/ratelimit/VegasRateLimiterTest.java | 291 ++++++++++++ .../src/test/resources/test-config.properties | 24 + 13 files changed, 2991 insertions(+) create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/monitor/SystemResourceMonitor.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/protection/TrafficProtector.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AbstractRateLimiter.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AdaptiveRateLimiter.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiter.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/RateLimiter.java create mode 100644 external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/VegasRateLimiter.java create mode 100644 external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiterTest.java create mode 100644 external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/GradientRateLimiterTest.java create mode 100644 external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/RateLimiterIntegrationTest.java create mode 100644 external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/VegasRateLimiterTest.java create mode 100644 external/external-core/src/test/resources/test-config.properties diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/config/ExternalGlobalConfig.java b/external/external-core/src/main/java/com/iohao/game/external/core/config/ExternalGlobalConfig.java index 275537d75..e2d1bd22f 100644 --- a/external/external-core/src/main/java/com/iohao/game/external/core/config/ExternalGlobalConfig.java +++ b/external/external-core/src/main/java/com/iohao/game/external/core/config/ExternalGlobalConfig.java @@ -56,4 +56,43 @@ public class CoreOption { /** http 升级 websocket 协议地址 */ public String websocketPath = "/websocket"; } + + /** + * 流量过载保护配置 + */ + @UtilityClass + public class TrafficProtectionOption { + /** 是否启用流量保护功能 */ + public boolean enableTrafficProtection = false; + + /** 最大连接数限制,默认5000 */ + public int maxConnections = 5000; + + /** 是否启用自适应限流 */ + public boolean enableAdaptiveRateLimit = true; + + /** 监控间隔(毫秒),默认1000ms */ + public int monitorInterval = 1000; + + /** 自适应限流窗口大小(秒),默认60秒 */ + public int adaptiveWindowSize = 60; + + /** 最小限流阈值(连接数),默认1000 */ + public int minRateLimitThreshold = 1000; + + /** 最大限流阈值(连接数),默认8000 */ + public int maxRateLimitThreshold = 8000; + + /** CPU使用率阈值(百分比),超过此值将触发限流 */ + public double cpuThreshold = 80.0; + + /** 内存使用率阈值(百分比),超过此值将触发限流 */ + public double memoryThreshold = 85.0; + + /** 是否启用连接拒绝日志 */ + public boolean enableRejectionLog = true; + + /** 是否启用系统资源监控 */ + public boolean enableResourceMonitoring = true; + } } diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/monitor/SystemResourceMonitor.java b/external/external-core/src/main/java/com/iohao/game/external/core/monitor/SystemResourceMonitor.java new file mode 100644 index 000000000..b0031e049 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/monitor/SystemResourceMonitor.java @@ -0,0 +1,414 @@ +/* + * ioGame + * Copyright (C) 2021 - present 渔民小镇 (262610965@qq.com、luoyizhu@gmail.com) . All Rights Reserved. + * # iohao.com . 渔民小镇 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.iohao.game.external.core.monitor; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.OperatingSystemMXBean; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 系统资源监控器 + * 负责监控CPU、内存等系统资源使用情况 + * + * @author undertaker86001 + * @date 2025-08-15 + */ +@Slf4j +public class SystemResourceMonitor { + + /** 单例实例 */ + private static final SystemResourceMonitor INSTANCE = new SystemResourceMonitor(); + + /** 操作系统MXBean */ + private final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + + /** 内存MXBean */ + private final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + + /** 定时任务执行器 */ + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + /** 当前系统资源信息 */ + private final AtomicReference currentInfo = new AtomicReference<>(); + + /** 是否已启动 */ + private volatile boolean started = false; + + /** 私有构造函数 */ + private SystemResourceMonitor() { + // 初始化当前资源信息 + this.currentInfo.set(new SystemResourceInfo()); + } + + /** + * 获取单例实例 + * + * @return SystemResourceMonitor实例 + */ + public static SystemResourceMonitor getInstance() { + return INSTANCE; + } + + /** + * 启动监控 + */ + public void start() { + if (started) { + return; + } + + if (!ExternalGlobalConfig.TrafficProtectionOption.enableResourceMonitoring) { + log.info("系统资源监控已禁用"); + return; + } + + // 立即执行一次监控 + updateResourceInfo(); + + // 启动定时监控任务 + int interval = ExternalGlobalConfig.TrafficProtectionOption.monitorInterval; + scheduler.scheduleAtFixedRate(this::updateResourceInfo, interval, interval, TimeUnit.MILLISECONDS); + + started = true; + log.info("系统资源监控已启动,监控间隔: {}ms", interval); + } + + /** + * 停止监控 + */ + public void stop() { + if (!started) { + return; + } + + scheduler.shutdown(); + try { + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + scheduler.shutdownNow(); + } + } catch (InterruptedException e) { + scheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } + + started = false; + log.info("系统资源监控已停止"); + } + + /** + * 获取当前系统资源信息 + * + * @return 系统资源信息 + */ + public SystemResourceInfo getCurrentInfo() { + return currentInfo.get(); + } + + /** + * 更新系统资源信息 + */ + private void updateResourceInfo() { + try { + SystemResourceInfo info = new SystemResourceInfo(); + + // 获取CPU使用率 + info.setCpuUsage(getCpuUsage()); + + // 获取内存使用率 + info.setMemoryUsage(getMemoryUsage()); + + // 获取系统负载 + info.setSystemLoad(getSystemLoad()); + + // 获取可用内存 + info.setAvailableMemory(getAvailableMemory()); + + // 获取总内存 + info.setTotalMemory(getTotalMemory()); + + // 获取JVM内存使用情况 + info.setJvmMemoryUsage(getJvmMemoryUsage()); + + // 设置时间戳 + info.setTimestamp(System.currentTimeMillis()); + + // 更新当前信息 + currentInfo.set(info); + + // 检查是否需要告警 + checkResourceAlerts(info); + + } catch (Exception e) { + log.error("更新系统资源信息失败", e); + } + } + + /** + * 获取CPU使用率 + * + * @return CPU使用率(百分比) + */ + private double getCpuUsage() { + try { + // 获取系统CPU负载 + double systemLoad = osBean.getSystemLoadAverage(); + + // 如果系统负载不可用,返回0 + if (systemLoad < 0) { + return 0.0; + } + + // 获取CPU核心数 + int cpuCores = osBean.getAvailableProcessors(); + + // 计算CPU使用率(系统负载 / CPU核心数 * 100) + double cpuUsage = (systemLoad / cpuCores) * 100.0; + + // 限制在0-100范围内 + return Math.min(100.0, Math.max(0.0, cpuUsage)); + + } catch (Exception e) { + log.warn("获取CPU使用率失败", e); + return 0.0; + } + } + + /** + * 获取内存使用率 + * + * @return 内存使用率(百分比) + */ + private double getMemoryUsage() { + try { + long totalMemory = getTotalMemory(); + long availableMemory = getAvailableMemory(); + + if (totalMemory <= 0) { + return 0.0; + } + + long usedMemory = totalMemory - availableMemory; + double memoryUsage = ((double) usedMemory / totalMemory) * 100.0; + + return Math.min(100.0, Math.max(0.0, memoryUsage)); + + } catch (Exception e) { + log.warn("获取内存使用率失败", e); + return 0.0; + } + } + + /** + * 获取系统负载 + * + * @return 系统负载 + */ + private double getSystemLoad() { + try { + double load = osBean.getSystemLoadAverage(); + return load < 0 ? 0.0 : load; + } catch (Exception e) { + log.warn("获取系统负载失败", e); + return 0.0; + } + } + + /** + * 获取可用内存 + * + * @return 可用内存(字节) + */ + private long getAvailableMemory() { + try { + return Runtime.getRuntime().freeMemory(); + } catch (Exception e) { + log.warn("获取可用内存失败", e); + return 0L; + } + } + + /** + * 获取总内存 + * + * @return 总内存(字节) + */ + private long getTotalMemory() { + try { + return Runtime.getRuntime().totalMemory(); + } catch (Exception e) { + log.warn("获取总内存失败", e); + return 0L; + } + } + + /** + * 获取JVM内存使用率 + * + * @return JVM内存使用率(百分比) + */ + private double getJvmMemoryUsage() { + try { + long usedMemory = memoryBean.getHeapMemoryUsage().getUsed(); + long maxMemory = memoryBean.getHeapMemoryUsage().getMax(); + + if (maxMemory <= 0) { + return 0.0; + } + + double jvmMemoryUsage = ((double) usedMemory / maxMemory) * 100.0; + return Math.min(100.0, Math.max(0.0, jvmMemoryUsage)); + + } catch (Exception e) { + log.warn("获取JVM内存使用率失败", e); + return 0.0; + } + } + + /** + * 检查资源告警 + * + * @param info 系统资源信息 + */ + private void checkResourceAlerts(SystemResourceInfo info) { + double cpuThreshold = ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold; + double memoryThreshold = ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold; + + // CPU使用率告警 + if (info.getCpuUsage() > cpuThreshold) { + log.warn("CPU使用率过高: {}%, 阈值: {}%", + String.format("%.2f", info.getCpuUsage()), + String.format("%.2f", cpuThreshold)); + } + + // 内存使用率告警 + if (info.getMemoryUsage() > memoryThreshold) { + log.warn("内存使用率过高: {}%, 阈值: {}%", + String.format("%.2f", info.getMemoryUsage()), + String.format("%.2f", memoryThreshold)); + } + + // JVM内存使用率告警 + if (info.getJvmMemoryUsage() > 90.0) { + log.warn("JVM内存使用率过高: {}%", + String.format("%.2f", info.getJvmMemoryUsage())); + } + } + + /** + * 系统资源信息 + */ + @Getter + @Accessors(chain = true) + public static class SystemResourceInfo { + /** CPU使用率(百分比) */ + private double cpuUsage = 0.0; + + /** 内存使用率(百分比) */ + private double memoryUsage = 0.0; + + /** 系统负载 */ + private double systemLoad = 0.0; + + /** 可用内存(字节) */ + private long availableMemory = 0L; + + /** 总内存(字节) */ + private long totalMemory = 0L; + + /** JVM内存使用率(百分比) */ + private double jvmMemoryUsage = 0.0; + + /** 时间戳 */ + private long timestamp = 0L; + + /** + * 设置CPU使用率 + */ + public SystemResourceInfo setCpuUsage(double cpuUsage) { + this.cpuUsage = cpuUsage; + return this; + } + + /** + * 设置内存使用率 + */ + public SystemResourceInfo setMemoryUsage(double memoryUsage) { + this.memoryUsage = memoryUsage; + return this; + } + + /** + * 设置系统负载 + */ + public SystemResourceInfo setSystemLoad(double systemLoad) { + this.systemLoad = systemLoad; + return this; + } + + /** + * 设置可用内存 + */ + public SystemResourceInfo setAvailableMemory(long availableMemory) { + this.availableMemory = availableMemory; + return this; + } + + /** + * 设置总内存 + */ + public SystemResourceInfo setTotalMemory(long totalMemory) { + this.totalMemory = totalMemory; + return this; + } + + /** + * 设置JVM内存使用率 + */ + public SystemResourceInfo setJvmMemoryUsage(double jvmMemoryUsage) { + this.jvmMemoryUsage = jvmMemoryUsage; + return this; + } + + /** + * 设置时间戳 + */ + public SystemResourceInfo setTimestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + @Override + public String toString() { + return String.format( + "SystemResourceInfo{cpuUsage=%.2f%%, memoryUsage=%.2f%%, systemLoad=%.2f, " + + "availableMemory=%d, totalMemory=%d, jvmMemoryUsage=%.2f%%, timestamp=%d}", + cpuUsage, memoryUsage, systemLoad, availableMemory, totalMemory, jvmMemoryUsage, timestamp + ); + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/protection/TrafficProtector.java b/external/external-core/src/main/java/com/iohao/game/external/core/protection/TrafficProtector.java new file mode 100644 index 000000000..3740f0469 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/protection/TrafficProtector.java @@ -0,0 +1,184 @@ +package com.iohao.game.external.core.protection; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.ratelimit.AdaptiveRateLimiter; +import lombok.extern.slf4j.Slf4j; + +/** + * 流量保护器 + * 负责在连接建立时进行流量控制和保护 + * @author undertaker86001 + * @date 2025-08-15 + */ +@Slf4j +public class TrafficProtector { + + private static final TrafficProtector INSTANCE = new TrafficProtector(); + private final AdaptiveRateLimiter rateLimiter = AdaptiveRateLimiter.getInstance(); + + private TrafficProtector() {} + + public static TrafficProtector getInstance() { + return INSTANCE; + } + + /** + * 检查是否允许新连接 + * + * @param clientIp 客户端IP地址 + * @return 连接检查结果 + */ + public ConnectionCheckResult checkConnection(String clientIp) { + // 检查是否启用流量保护 + if (!ExternalGlobalConfig.TrafficProtectionOption.enableTrafficProtection) { + return ConnectionCheckResult.allowed(); + } + + try { + // 尝试获取连接许可 + if (rateLimiter.tryAcquire()) { + // 允许连接,增加连接数 + rateLimiter.incrementConnections(); + + if (ExternalGlobalConfig.TrafficProtectionOption.enableRejectionLog) { + log.info("连接允许 - IP: {}, 当前连接数: {}, 阈值: {}", + clientIp, rateLimiter.getCurrentConnections(), rateLimiter.getCurrentThreshold()); + } + + return ConnectionCheckResult.allowed(); + } else { + // 拒绝连接 + if (ExternalGlobalConfig.TrafficProtectionOption.enableRejectionLog) { + log.warn("连接拒绝 - IP: {}, 当前连接数: {}, 阈值: {}, 原因: 连接数超限", + clientIp, rateLimiter.getCurrentConnections(), rateLimiter.getCurrentThreshold()); + } + + return ConnectionCheckResult.rejected(ConnectionRejectionReason.CONNECTION_LIMIT_EXCEEDED); + } + + } catch (Exception e) { + log.error("流量保护检查失败 - IP: {}", clientIp, e); + + // 发生异常时,为了安全起见,拒绝连接 + return ConnectionCheckResult.rejected(ConnectionRejectionReason.SYSTEM_ERROR); + } + } + + /** + * 连接断开时减少连接数 + */ + public void onConnectionClosed() { + if (ExternalGlobalConfig.TrafficProtectionOption.enableTrafficProtection) { + rateLimiter.decrementConnections(); + } + } + + /** + * 获取当前连接数 + * + * @return 当前连接数 + */ + public int getCurrentConnections() { + return rateLimiter.getCurrentConnections(); + } + + /** + * 获取当前限流阈值 + * + * @return 当前限流阈值 + */ + public int getCurrentThreshold() { + return rateLimiter.getCurrentThreshold(); + } + + /** + * 获取限流统计信息 + * + * @return 限流统计信息 + */ + public AdaptiveRateLimiter.RateLimitStats getRateLimitStats() { + return rateLimiter.getStats(); + } + + /** + * 启动流量保护器 + */ + public void start() { + if (ExternalGlobalConfig.TrafficProtectionOption.enableTrafficProtection) { + rateLimiter.start(); + log.info("流量保护器已启动"); + } + } + + /** + * 停止流量保护器 + */ + public void stop() { + if (ExternalGlobalConfig.TrafficProtectionOption.enableTrafficProtection) { + rateLimiter.stop(); + log.info("流量保护器已停止"); + } + } + + /** + * 连接检查结果 + */ + public static class ConnectionCheckResult { + private final boolean allowed; + private final ConnectionRejectionReason rejectionReason; + private final String errorMessage; + + private ConnectionCheckResult(boolean allowed, ConnectionRejectionReason rejectionReason, String errorMessage) { + this.allowed = allowed; + this.rejectionReason = rejectionReason; + this.errorMessage = errorMessage; + } + + public static ConnectionCheckResult allowed() { + return new ConnectionCheckResult(true, null, null); + } + + public static ConnectionCheckResult rejected(ConnectionRejectionReason reason) { + return new ConnectionCheckResult(false, reason, reason.getMessage()); + } + + public boolean isAllowed() { + return allowed; + } + + public ConnectionRejectionReason getRejectionReason() { + return rejectionReason; + } + + public String getErrorMessage() { + return errorMessage; + } + } + + /** + * 连接拒绝原因 + */ + public enum ConnectionRejectionReason { + CONNECTION_LIMIT_EXCEEDED(1001, "连接数超限"), + SYSTEM_OVERLOAD(1002, "系统负载过高"), + RESOURCE_INSUFFICIENT(1003, "资源不足"), + RATE_LIMIT_TRIGGERED(1004, "限流保护触发"), + SYSTEM_ERROR(1005, "系统错误"); + + private final int errorCode; + private final String message; + + ConnectionRejectionReason(int errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } + + public int getErrorCode() { + return errorCode; + } + + public String getMessage() { + return message; + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AbstractRateLimiter.java b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AbstractRateLimiter.java new file mode 100644 index 000000000..a0f8b37f1 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AbstractRateLimiter.java @@ -0,0 +1,272 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 限流器抽象基类 + * 提供通用的实现逻辑,子类只需要实现具体的限流算法 + * @author undertaker86001 + * @date 2025-08-15 + */ +@Slf4j +public abstract class AbstractRateLimiter implements RateLimiter { + + protected final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + /** 当前限流阈值 */ + protected final AtomicInteger currentLimit = new AtomicInteger(); + + /** 当前连接数 */ + protected final AtomicInteger currentConnections = new AtomicInteger(0); + + /** 被拒绝的连接数 */ + protected final AtomicLong rejectedConnections = new AtomicLong(0); + + /** 总连接请求数 */ + protected final AtomicLong totalRequests = new AtomicLong(0); + + /** 限流统计信息 */ + protected final AtomicReference stats = new AtomicReference<>(); + + /** 是否已启动 */ + protected volatile boolean started = false; + + /** 系统资源监控器 */ + protected final SystemResourceMonitor resourceMonitor = SystemResourceMonitor.getInstance(); + + /** 样本统计 */ + protected final AtomicLong sampleCount = new AtomicLong(0); + protected final AtomicLong totalRtt = new AtomicLong(0); + + protected AbstractRateLimiter() { + int maxConnections = ExternalGlobalConfig.TrafficProtectionOption.maxConnections; + this.currentLimit.set(maxConnections); + this.stats.set(new BaseRateLimitStats()); + } + + @Override + public void start() { + if (started) return; + + if (!ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit) { + log.info("自适应限流已禁用"); + return; + } + + resourceMonitor.start(); + adjustLimit(); + + int interval = ExternalGlobalConfig.TrafficProtectionOption.monitorInterval; + scheduler.scheduleAtFixedRate(this::adjustLimit, interval, interval, TimeUnit.MILLISECONDS); + + started = true; + log.info("{} 自适应限流器已启动,监控间隔: {}ms", getAlgorithmName(), interval); + } + + @Override + public void stop() { + if (!started) return; + + scheduler.shutdown(); + try { + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + scheduler.shutdownNow(); + } + } catch (InterruptedException e) { + scheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } + + resourceMonitor.stop(); + started = false; + log.info("{} 自适应限流器已停止", getAlgorithmName()); + } + + @Override + public boolean tryAcquire() { + totalRequests.incrementAndGet(); + + int limit = currentLimit.get(); + int connections = currentConnections.get(); + + if (connections >= limit) { + rejectedConnections.incrementAndGet(); + return false; + } + + return true; + } + + @Override + public void incrementConnections() { + currentConnections.incrementAndGet(); + } + + @Override + public void decrementConnections() { + currentConnections.decrementAndGet(); + } + + @Override + public int getCurrentConnections() { + return currentConnections.get(); + } + + @Override + public int getCurrentLimit() { + return currentLimit.get(); + } + + @Override + public void recordRtt(double rtt) { + if (rtt <= 0) return; + + sampleCount.incrementAndGet(); + totalRtt.addAndGet((long) (rtt * 1000)); // 转换为微秒 + + // 子类实现具体的RTT更新逻辑 + updateRtt(rtt); + } + + @Override + public RateLimitStats getStats() { + BaseRateLimitStats currentStats = stats.get(); + currentStats.setCurrentConnections(currentConnections.get()); + currentStats.setCurrentLimit(currentLimit.get()); + currentStats.setRejectedConnections(rejectedConnections.get()); + currentStats.setTotalRequests(totalRequests.get()); + currentStats.setTimestamp(System.currentTimeMillis()); + + // 子类实现具体的统计信息更新 + updateStats(currentStats); + + return currentStats; + } + + /** + * 获取算法名称 + */ + protected abstract String getAlgorithmName(); + + /** + * 调整限流阈值 + * 子类实现具体的限流算法 + */ + protected abstract void adjustLimit(); + + /** + * 更新RTT值 + * 子类实现具体的RTT更新逻辑 + */ + protected abstract void updateRtt(double rtt); + + /** + * 更新统计信息 + * 子类实现具体的统计信息更新 + */ + protected abstract void updateStats(BaseRateLimitStats stats); + + /** + * 应用系统资源约束 + */ + protected int applyResourceConstraints(int newLimit, SystemResourceMonitor.SystemResourceInfo resourceInfo) { + double cpuUsage = resourceInfo.getCpuUsage(); + double memoryUsage = resourceInfo.getMemoryUsage(); + + double cpuThreshold = ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold; + double memoryThreshold = ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold; + + // 如果CPU或内存使用率过高,减少limit + if (cpuUsage > cpuThreshold || memoryUsage > memoryThreshold) { + double reductionFactor = 0.8; // 减少20% + newLimit = (int) (newLimit * reductionFactor); + } + + return newLimit; + } + + /** + * 基础限流统计信息 + */ + @Getter + @Accessors(chain = true) + protected static class BaseRateLimitStats implements RateLimitStats { + private int currentConnections = 0; + private int currentLimit = 0; + private long rejectedConnections = 0; + private long totalRequests = 0; + private double cpuUsage = 0.0; + private double memoryUsage = 0.0; + private double systemLoad = 0.0; + private double jvmMemoryUsage = 0.0; + private long timestamp = 0L; + + public BaseRateLimitStats setCurrentConnections(int currentConnections) { + this.currentConnections = currentConnections; + return this; + } + + public BaseRateLimitStats setCurrentLimit(int currentLimit) { + this.currentLimit = currentLimit; + return this; + } + + public BaseRateLimitStats setRejectedConnections(long rejectedConnections) { + this.rejectedConnections = rejectedConnections; + return this; + } + + public BaseRateLimitStats setTotalRequests(long totalRequests) { + this.totalRequests = totalRequests; + return this; + } + + public BaseRateLimitStats setCpuUsage(double cpuUsage) { + this.cpuUsage = cpuUsage; + return this; + } + + public BaseRateLimitStats setMemoryUsage(double memoryUsage) { + this.memoryUsage = memoryUsage; + return this; + } + + public BaseRateLimitStats setSystemLoad(double systemLoad) { + this.systemLoad = systemLoad; + return this; + } + + public BaseRateLimitStats setJvmMemoryUsage(double jvmMemoryUsage) { + this.jvmMemoryUsage = jvmMemoryUsage; + return this; + } + + public BaseRateLimitStats setTimestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + @Override + public double getRejectionRate() { + if (totalRequests == 0) return 0.0; + return ((double) rejectedConnections / totalRequests) * 100.0; + } + + @Override + public double getConnectionRate() { + if (currentLimit == 0) return 0.0; + return ((double) currentConnections / currentLimit) * 100.0; + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AdaptiveRateLimiter.java b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AdaptiveRateLimiter.java new file mode 100644 index 000000000..6490dad11 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/AdaptiveRateLimiter.java @@ -0,0 +1,437 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 基于Netflix Gradient算法的自适应限流器 + * 通过计算无负载时的RTT与当前RTT的比值来判断是否出现请求排队 + * + * 参考:https://gummary.github.io/post/netfix%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95/ + */ +@Slf4j +public class AdaptiveRateLimiter { + + private static final AdaptiveRateLimiter INSTANCE = new AdaptiveRateLimiter(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + /** 当前限流阈值 */ + private final AtomicInteger currentLimit = new AtomicInteger(); + + /** 当前连接数 */ + private final AtomicInteger currentConnections = new AtomicInteger(0); + + /** 被拒绝的连接数 */ + private final AtomicLong rejectedConnections = new AtomicLong(0); + + /** 总连接请求数 */ + private final AtomicLong totalRequests = new AtomicLong(0); + + /** 限流统计信息 */ + private final AtomicReference stats = new AtomicReference<>(); + + /** 是否已启动 */ + private volatile boolean started = false; + + /** 系统资源监控器 */ + private final SystemResourceMonitor resourceMonitor = SystemResourceMonitor.getInstance(); + + /** RTT相关参数 */ + private volatile double rttNoLoad = 0.0; // 无负载时的RTT + private volatile double rttActual = 0.0; // 当前实际RTT + private volatile long lastUpdateTime = 0L; // 上次更新时间 + + /** 自适应参数 */ + private static final double MIN_GRADIENT = 0.5; // 最小梯度值 + private static final double MAX_GRADIENT = 1.0; // 最大梯度值 + private static final double ALPHA = 0.1; // 平滑因子 + private static final int MIN_SAMPLE_SIZE = 10; // 最小样本数 + + /** 样本统计 */ + private final AtomicLong sampleCount = new AtomicLong(0); + private final AtomicLong totalRtt = new AtomicLong(0); + + private AdaptiveRateLimiter() { + int maxConnections = ExternalGlobalConfig.TrafficProtectionOption.maxConnections; + this.currentLimit.set(maxConnections); + this.stats.set(new RateLimitStats()); + + // 初始化RTT值 + this.rttNoLoad = 1.0; // 默认1ms + this.rttActual = 1.0; + } + + public static AdaptiveRateLimiter getInstance() { + return INSTANCE; + } + + public void start() { + if (started) return; + + if (!ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit) { + log.info("自适应限流已禁用"); + return; + } + + resourceMonitor.start(); + adjustLimit(); + + int interval = ExternalGlobalConfig.TrafficProtectionOption.monitorInterval; + scheduler.scheduleAtFixedRate(this::adjustLimit, interval, interval, TimeUnit.MILLISECONDS); + + started = true; + log.info("Gradient自适应限流器已启动,监控间隔: {}ms", interval); + } + + public void stop() { + if (!started) return; + + scheduler.shutdown(); + try { + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + scheduler.shutdownNow(); + } + } catch (InterruptedException e) { + scheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } + + resourceMonitor.stop(); + started = false; + log.info("Gradient自适应限流器已停止"); + } + + public boolean tryAcquire() { + totalRequests.incrementAndGet(); + + int limit = currentLimit.get(); + int connections = currentConnections.get(); + + if (connections >= limit) { + rejectedConnections.incrementAndGet(); + return false; + } + + return true; + } + + public void incrementConnections() { + currentConnections.incrementAndGet(); + } + + public void decrementConnections() { + currentConnections.decrementAndGet(); + } + + /** + * 记录RTT样本 + * + * @param rtt 响应时间(毫秒) + */ + public void recordRtt(double rtt) { + if (rtt <= 0) return; + + sampleCount.incrementAndGet(); + totalRtt.addAndGet((long) (rtt * 1000)); // 转换为微秒 + + // 更新实际RTT(使用指数移动平均) + updateRtt(rtt); + } + + public int getCurrentConnections() { + return currentConnections.get(); + } + + public int getCurrentLimit() { + return currentLimit.get(); + } + + public RateLimitStats getStats() { + RateLimitStats currentStats = stats.get(); + currentStats.setCurrentConnections(currentConnections.get()); + currentStats.setCurrentLimit(currentLimit.get()); + currentStats.setRejectedConnections(rejectedConnections.get()); + currentStats.setTotalRequests(totalRequests.get()); + currentStats.setRttNoLoad(rttNoLoad); + currentStats.setRttActual(rttActual); + currentStats.setGradient(calculateGradient()); + currentStats.setQueueSize(calculateQueueSize()); + currentStats.setTimestamp(System.currentTimeMillis()); + return currentStats; + } + + /** + * 基于Gradient算法调整限流阈值 + */ + private void adjustLimit() { + try { + // 获取系统资源信息 + SystemResourceMonitor.SystemResourceInfo resourceInfo = resourceMonitor.getCurrentInfo(); + + // 获取配置参数 + int maxConnections = ExternalGlobalConfig.TrafficProtectionOption.maxConnections; + int minThreshold = ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold; + int maxThreshold = ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold; + + // 计算新的阈值 + int newLimit = calculateNewLimit(resourceInfo, maxConnections, minThreshold, maxThreshold); + + // 更新阈值 + int oldLimit = currentLimit.get(); + if (newLimit != oldLimit) { + currentLimit.set(newLimit); + log.info("限流阈值已调整: {} -> {} (Gradient: {:.3f}, RTT比值: {:.3f}/{:.3f})", + oldLimit, newLimit, calculateGradient(), rttNoLoad, rttActual); + } + + // 更新统计信息 + updateStats(resourceInfo); + + } catch (Exception e) { + log.error("调整限流阈值失败", e); + } + } + + /** + * 计算新的限流阈值 + * 基于Gradient算法:newLimit = currentLimit × gradient + queueSize + */ + private int calculateNewLimit( + SystemResourceMonitor.SystemResourceInfo resourceInfo, + int maxConnections, int minThreshold, int maxThreshold) { + + int currentLimit = this.currentLimit.get(); + + // 计算Gradient值 + double gradient = calculateGradient(); + + // 计算队列大小(允许一定的排队) + int queueSize = calculateQueueSize(); + + // 应用Gradient算法 + double newLimitDouble = currentLimit * gradient + queueSize; + int newLimit = (int) Math.round(newLimitDouble); + + // 限制在有效范围内 + newLimit = Math.max(minThreshold, Math.min(maxThreshold, newLimit)); + + // 考虑系统资源限制 + newLimit = applyResourceConstraints(newLimit, resourceInfo); + + return newLimit; + } + + /** + * 计算Gradient值 + * gradient = RTTNoLoad / RTTactual + * 当gradient = 1时,说明当前请求没有排队 + * 当gradient < 1时,说明当前开始排队了,需要降低limit + */ + private double calculateGradient() { + if (rttActual <= 0) return MAX_GRADIENT; + + double gradient = rttNoLoad / rttActual; + + // 限制在有效范围内 + return Math.max(MIN_GRADIENT, Math.min(MAX_GRADIENT, gradient)); + } + + /** + * 计算队列大小 + * 一般设置为当前limit的平方根,对于小的limit增长很快,大的limit变动平稳 + */ + private int calculateQueueSize() { + int currentLimit = this.currentLimit.get(); + return (int) Math.sqrt(currentLimit); + } + + /** + * 应用系统资源约束 + */ + private int applyResourceConstraints(int newLimit, SystemResourceMonitor.SystemResourceInfo resourceInfo) { + double cpuUsage = resourceInfo.getCpuUsage(); + double memoryUsage = resourceInfo.getMemoryUsage(); + + double cpuThreshold = ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold; + double memoryThreshold = ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold; + + // 如果CPU或内存使用率过高,减少limit + if (cpuUsage > cpuThreshold || memoryUsage > memoryThreshold) { + double reductionFactor = 0.8; // 减少20% + newLimit = (int) (newLimit * reductionFactor); + } + + return newLimit; + } + + /** + * 更新RTT值 + * 使用指数移动平均来平滑RTT变化 + */ + private void updateRtt(double rtt) { + long currentTime = System.currentTimeMillis(); + + // 更新实际RTT + if (rttActual == 0) { + rttActual = rtt; + } else { + rttActual = ALPHA * rtt + (1 - ALPHA) * rttActual; + } + + // 更新无负载RTT(取最小值) + if (rttNoLoad == 0 || rtt < rttNoLoad) { + rttNoLoad = rtt; + } + + // 定期更新无负载RTT(防止长期不更新) + if (currentTime - lastUpdateTime > 60000) { // 1分钟 + updateNoLoadRtt(); + lastUpdateTime = currentTime; + } + } + + /** + * 更新无负载RTT + * 使用最近一段时间的最小RTT作为无负载RTT + */ + private void updateNoLoadRtt() { + if (sampleCount.get() < MIN_SAMPLE_SIZE) return; + + // 计算平均RTT + double avgRtt = (double) totalRtt.get() / sampleCount.get() / 1000.0; // 转换回毫秒 + + // 如果当前RTT接近平均RTT,说明系统负载较低,可以更新无负载RTT + if (rttActual < avgRtt * 1.2) { + rttNoLoad = Math.min(rttNoLoad, rttActual); + } + + // 重置统计 + sampleCount.set(0); + totalRtt.set(0); + } + + private void updateStats(SystemResourceMonitor.SystemResourceInfo resourceInfo) { + RateLimitStats currentStats = stats.get(); + currentStats.setCpuUsage(resourceInfo.getCpuUsage()); + currentStats.setMemoryUsage(resourceInfo.getMemoryUsage()); + currentStats.setSystemLoad(resourceInfo.getSystemLoad()); + currentStats.setJvmMemoryUsage(resourceInfo.getJvmMemoryUsage()); + } + + @Getter + @Accessors(chain = true) + public static class RateLimitStats { + private int currentConnections = 0; + private int currentLimit = 0; + private long rejectedConnections = 0; + private long totalRequests = 0; + private double cpuUsage = 0.0; + private double memoryUsage = 0.0; + private double systemLoad = 0.0; + private double jvmMemoryUsage = 0.0; + private double rttNoLoad = 0.0; + private double rttActual = 0.0; + private double gradient = 0.0; + private int queueSize = 0; + private long timestamp = 0L; + + public RateLimitStats setCurrentConnections(int currentConnections) { + this.currentConnections = currentConnections; + return this; + } + + public RateLimitStats setCurrentLimit(int currentLimit) { + this.currentLimit = currentLimit; + return this; + } + + public RateLimitStats setRejectedConnections(long rejectedConnections) { + this.rejectedConnections = rejectedConnections; + return this; + } + + public RateLimitStats setTotalRequests(long totalRequests) { + this.totalRequests = totalRequests; + return this; + } + + public RateLimitStats setCpuUsage(double cpuUsage) { + this.cpuUsage = cpuUsage; + return this; + } + + public RateLimitStats setMemoryUsage(double memoryUsage) { + this.memoryUsage = memoryUsage; + return this; + } + + public RateLimitStats setSystemLoad(double systemLoad) { + this.systemLoad = systemLoad; + return this; + } + + public RateLimitStats setJvmMemoryUsage(double jvmMemoryUsage) { + this.jvmMemoryUsage = jvmMemoryUsage; + return this; + } + + public RateLimitStats setRttNoLoad(double rttNoLoad) { + this.rttNoLoad = rttNoLoad; + return this; + } + + public RateLimitStats setRttActual(double rttActual) { + this.rttActual = rttActual; + return this; + } + + public RateLimitStats setGradient(double gradient) { + this.gradient = gradient; + return this; + } + + public RateLimitStats setQueueSize(int queueSize) { + this.queueSize = queueSize; + return this; + } + + public RateLimitStats setTimestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public double getRejectionRate() { + if (totalRequests == 0) return 0.0; + return ((double) rejectedConnections / totalRequests) * 100.0; + } + + public double getConnectionRate() { + if (currentLimit == 0) return 0.0; + return ((double) currentConnections / currentLimit) * 100.0; + } + + @Override + public String toString() { + return String.format( + "RateLimitStats{currentConnections=%d, currentLimit=%d, " + + "rejectedConnections=%d, totalRequests=%d, rejectionRate=%.2f%%, " + + "connectionRate=%.2f%%, gradient=%.3f, rttNoLoad=%.3f, rttActual=%.3f, " + + "queueSize=%d, cpuUsage=%.2f%%, memoryUsage=%.2f%%, " + + "systemLoad=%.2f, jvmMemoryUsage=%.2f%%, timestamp=%d}", + currentConnections, currentLimit, rejectedConnections, totalRequests, + getRejectionRate(), getConnectionRate(), gradient, rttNoLoad, rttActual, + queueSize, cpuUsage, memoryUsage, systemLoad, jvmMemoryUsage, timestamp + ); + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiter.java b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiter.java new file mode 100644 index 000000000..b9d7f1d94 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiter.java @@ -0,0 +1,217 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +/** + * Gradient2限流算法实现 + * 将noLoadRTT设置为RTT的指数移动平均,会随着RTT的增大而增大,缓解了过度保护的情况 + */ +@Slf4j +public class Gradient2RateLimiter extends AbstractRateLimiter { + + private static final Gradient2RateLimiter INSTANCE = new Gradient2RateLimiter(); + + /** RTT相关参数 */ + private volatile double rttNoLoad = 0.0; // 无负载时的RTT + private volatile double rttActual = 0.0; // 当前实际RTT + private volatile double longRtt = 0.0; // 长期RTT(指数移动平均) + private volatile long lastUpdateTime = 0L; // 上次更新时间 + + /** 自适应参数 */ + private static final double MIN_GRADIENT = 0.5; // 最小梯度值 + private static final double MAX_GRADIENT = 1.0; // 最大梯度值 + private static final double ALPHA = 0.1; // 平滑因子 + private static final double WINDOW_SIZE = 100.0; // 请求窗口大小 + private static final int MIN_SAMPLE_SIZE = 10; // 最小样本数 + + private Gradient2RateLimiter() { + this.rttNoLoad = 1.0; + this.rttActual = 1.0; + this.longRtt = 1.0; + } + + public static Gradient2RateLimiter getInstance() { + return INSTANCE; + } + + @Override + protected String getAlgorithmName() { + return "Gradient2"; + } + + @Override + protected void adjustLimit() { + try { + SystemResourceMonitor.SystemResourceInfo resourceInfo = resourceMonitor.getCurrentInfo(); + + int maxConnections = ExternalGlobalConfig.TrafficProtectionOption.maxConnections; + int minThreshold = ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold; + int maxThreshold = ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold; + + int newLimit = calculateNewLimit(resourceInfo, maxConnections, minThreshold, maxThreshold); + + int oldLimit = currentLimit.get(); + if (newLimit != oldLimit) { + currentLimit.set(newLimit); + log.info("限流阈值已调整: {} -> {} (Gradient: {:.3f}, LongRTT: {:.3f}, RTT: {:.3f})", + oldLimit, newLimit, calculateGradient(), longRtt, rttActual); + } + + } catch (Exception e) { + log.error("调整限流阈值失败", e); + } + } + + private int calculateNewLimit( + SystemResourceMonitor.SystemResourceInfo resourceInfo, + int maxConnections, int minThreshold, int maxThreshold) { + + int currentLimit = this.currentLimit.get(); + double gradient = calculateGradient(); + int queueSize = calculateQueueSize(); + + double newLimitDouble = currentLimit * gradient + queueSize; + int newLimit = (int) Math.round(newLimitDouble); + + newLimit = Math.max(minThreshold, Math.min(maxThreshold, newLimit)); + newLimit = applyResourceConstraints(newLimit, resourceInfo); + + return newLimit; + } + + private double calculateGradient() { + if (rttActual <= 0) return MAX_GRADIENT; + + double gradient = longRtt / rttActual; + return Math.max(MIN_GRADIENT, Math.min(MAX_GRADIENT, gradient)); + } + + private int calculateQueueSize() { + int currentLimit = this.currentLimit.get(); + return (int) Math.sqrt(currentLimit); + } + + @Override + protected void updateRtt(double rtt) { + long currentTime = System.currentTimeMillis(); + + if (rttActual == 0) { + rttActual = rtt; + } else { + rttActual = ALPHA * rtt + (1 - ALPHA) * rttActual; + } + + if (longRtt == 0) { + longRtt = rtt; + } else { + longRtt = (1 - 1.0 / WINDOW_SIZE) * longRtt + (1.0 / WINDOW_SIZE) * rtt; + } + + if (rttNoLoad == 0 || rtt < rttNoLoad) { + rttNoLoad = rtt; + } + + if (currentTime - lastUpdateTime > 60000) { + updateNoLoadRtt(); + lastUpdateTime = currentTime; + } + } + + private void updateNoLoadRtt() { + if (sampleCount.get() < MIN_SAMPLE_SIZE) return; + + double avgRtt = (double) totalRtt.get() / sampleCount.get() / 1000.0; + + if (rttActual < avgRtt * 1.2) { + rttNoLoad = Math.min(rttNoLoad, rttActual); + } + + sampleCount.set(0); + totalRtt.set(0); + } + + @Override + protected void updateStats(BaseRateLimitStats stats) { + SystemResourceMonitor.SystemResourceInfo resourceInfo = resourceMonitor.getCurrentInfo(); + stats.setCpuUsage(resourceInfo.getCpuUsage()); + stats.setMemoryUsage(resourceInfo.getMemoryUsage()); + stats.setSystemLoad(resourceInfo.getSystemLoad()); + stats.setJvmMemoryUsage(resourceInfo.getJvmMemoryUsage()); + + if (stats instanceof Gradient2RateLimitStats) { + Gradient2RateLimitStats gradient2Stats = (Gradient2RateLimitStats) stats; + gradient2Stats.setRttNoLoad(rttNoLoad); + gradient2Stats.setRttActual(rttActual); + gradient2Stats.setLongRtt(longRtt); + gradient2Stats.setGradient(calculateGradient()); + gradient2Stats.setQueueSize(calculateQueueSize()); + } + } + + @Override + public RateLimitStats getStats() { + Gradient2RateLimitStats currentStats = new Gradient2RateLimitStats(); + currentStats.setCurrentConnections(currentConnections.get()); + currentStats.setCurrentLimit(currentLimit.get()); + currentStats.setRejectedConnections(rejectedConnections.get()); + currentStats.setTotalRequests(totalRequests.get()); + currentStats.setTimestamp(System.currentTimeMillis()); + + updateStats(currentStats); + + return currentStats; + } + + @Getter + @Accessors(chain = true) + public static class Gradient2RateLimitStats extends BaseRateLimitStats { + private double rttNoLoad = 0.0; + private double rttActual = 0.0; + private double longRtt = 0.0; + private double gradient = 0.0; + private int queueSize = 0; + + public Gradient2RateLimitStats setRttNoLoad(double rttNoLoad) { + this.rttNoLoad = rttNoLoad; + return this; + } + + public Gradient2RateLimitStats setRttActual(double rttActual) { + this.rttActual = rttActual; + return this; + } + + public Gradient2RateLimitStats setLongRtt(double longRtt) { + this.longRtt = longRtt; + return this; + } + + public Gradient2RateLimitStats setGradient(double gradient) { + this.gradient = gradient; + return this; + } + + public Gradient2RateLimitStats setQueueSize(int queueSize) { + this.queueSize = queueSize; + return this; + } + + @Override + public String toString() { + return String.format( + "Gradient2RateLimitStats{currentConnections=%d, currentLimit=%d, " + + "rejectedConnections=%d, totalRequests=%d, rejectionRate=%.2f%%, " + + "connectionRate=%.2f%%, gradient=%.3f, rttNoLoad=%.3f, rttActual=%.3f, " + + "longRtt=%.3f, queueSize=%d, cpuUsage=%.2f%%, memoryUsage=%.2f%%, " + + "systemLoad=%.2f, jvmMemoryUsage=%.2f%%, timestamp=%d}", + getCurrentConnections(), getCurrentLimit(), getRejectedConnections(), getTotalRequests(), + getRejectionRate(), getConnectionRate(), gradient, rttNoLoad, rttActual, + longRtt, queueSize, getCpuUsage(), getMemoryUsage(), getSystemLoad(), getJvmMemoryUsage(), getTimestamp() + ); + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/RateLimiter.java b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/RateLimiter.java new file mode 100644 index 000000000..76e8d95e9 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/RateLimiter.java @@ -0,0 +1,152 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.monitor.SystemResourceMonitor; + +/** + * 限流器抽象接口 + * 为各种自适应限流算法提供统一的抽象 + * + * 参考:https://gummary.github.io/post/netfix%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95/ + */ +public interface RateLimiter { + + /** + * 启动限流器 + */ + void start(); + + /** + * 停止限流器 + */ + void stop(); + + /** + * 尝试获取连接许可 + * + * @return true 允许连接,false 拒绝连接 + */ + boolean tryAcquire(); + + /** + * 增加连接数 + */ + void incrementConnections(); + + /** + * 减少连接数 + */ + void decrementConnections(); + + /** + * 获取当前连接数 + * + * @return 当前连接数 + */ + int getCurrentConnections(); + + /** + * 获取当前限流阈值 + * + * @return 当前限流阈值 + */ + int getCurrentLimit(); + + /** + * 记录RTT样本 + * + * @param rtt 响应时间(毫秒) + */ + void recordRtt(double rtt); + + /** + * 获取限流统计信息 + * + * @return 限流统计信息 + */ + RateLimitStats getStats(); + + /** + * 限流统计信息接口 + */ + interface RateLimitStats { + /** + * 获取当前连接数 + */ + int getCurrentConnections(); + + /** + * 获取当前限流阈值 + */ + int getCurrentLimit(); + + /** + * 获取被拒绝的连接数 + */ + long getRejectedConnections(); + + /** + * 获取总连接请求数 + */ + long getTotalRequests(); + + /** + * 获取CPU使用率 + */ + double getCpuUsage(); + + /** + * 获取内存使用率 + */ + double getMemoryUsage(); + + /** + * 获取系统负载 + */ + double getSystemLoad(); + + /** + * 获取JVM内存使用率 + */ + double getJvmMemoryUsage(); + + /** + * 获取拒绝率 + */ + double getRejectionRate(); + + /** + * 获取连接率 + */ + double getConnectionRate(); + + /** + * 获取时间戳 + */ + long getTimestamp(); + } + + /** + * 限流器工厂接口 + */ + interface Factory { + /** + * 创建限流器 + * + * @param algorithm 算法类型 + * @return 限流器实例 + */ + RateLimiter createRateLimiter(Algorithm algorithm); + + /** + * 算法类型枚举 + */ + enum Algorithm { + /** Gradient算法 */ + GRADIENT, + /** Gradient2算法 */ + GRADIENT2, + /** Vegas算法 */ + VEGAS + } + } +} diff --git a/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/VegasRateLimiter.java b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/VegasRateLimiter.java new file mode 100644 index 000000000..a2a41c173 --- /dev/null +++ b/external/external-core/src/main/java/com/iohao/game/external/core/ratelimit/VegasRateLimiter.java @@ -0,0 +1,248 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +/** + * Vegas限流算法实现 + * 启发自TCP的Vegas拥塞避免算法,根据RTT来判断网络是否出现拥塞 + */ +@Slf4j +public class VegasRateLimiter extends AbstractRateLimiter { + + private static final VegasRateLimiter INSTANCE = new VegasRateLimiter(); + + /** RTT相关参数 */ + private volatile double rttNoLoad = 0.0; // 无负载时的RTT + private volatile double rttActual = 0.0; // 当前实际RTT + private volatile long lastUpdateTime = 0L; // 上次更新时间 + + /** Vegas算法参数 */ + private static final double ALPHA = 0.1; // 平滑因子 + private static final int MIN_SAMPLE_SIZE = 10; // 最小样本数 + + private VegasRateLimiter() { + this.rttNoLoad = 1.0; + this.rttActual = 1.0; + } + + public static VegasRateLimiter getInstance() { + return INSTANCE; + } + + @Override + protected String getAlgorithmName() { + return "Vegas"; + } + + @Override + protected void adjustLimit() { + try { + SystemResourceMonitor.SystemResourceInfo resourceInfo = resourceMonitor.getCurrentInfo(); + + int maxConnections = ExternalGlobalConfig.TrafficProtectionOption.maxConnections; + int minThreshold = ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold; + int maxThreshold = ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold; + + int newLimit = calculateNewLimit(resourceInfo, maxConnections, minThreshold, maxThreshold); + + int oldLimit = currentLimit.get(); + if (newLimit != oldLimit) { + currentLimit.set(newLimit); + log.info("限流阈值已调整: {} -> {} (QueueSize: {}, RTT比值: {:.3f}/{:.3f})", + oldLimit, newLimit, calculateQueueSize(), rttNoLoad, rttActual); + } + + } catch (Exception e) { + log.error("调整限流阈值失败", e); + } + } + + /** + * 基于Vegas算法计算新的限流阈值 + * 直接使用等待队列的大小queueSize进行判断是否限流 + */ + private int calculateNewLimit( + SystemResourceMonitor.SystemResourceInfo resourceInfo, + int maxConnections, int minThreshold, int maxThreshold) { + + int currentLimit = this.currentLimit.get(); + int queueSize = calculateQueueSize(); + + // 计算动态调整阈值 + double alpha = 3 * Math.log10(currentLimit); + double beta = 6 * Math.log10(currentLimit); + double threshold = Math.log10(currentLimit); + + int newLimit = currentLimit; + + // Vegas算法核心逻辑 + if (queueSize < threshold) { + // 队列大小小于阈值,扩大窗口 + newLimit = currentLimit + (int) beta; + } else if (queueSize < alpha) { + // 阈值 < 队列大小 < alpha,适度增加 + newLimit = currentLimit + (int) Math.log10(currentLimit); + } else if (queueSize > beta) { + // 队列大小 > beta,缩小窗口 + newLimit = currentLimit - (int) Math.log10(currentLimit); + } + // 其他情况保持当前值 + + // 限制在有效范围内 + newLimit = Math.max(minThreshold, Math.min(maxThreshold, newLimit)); + + // 考虑系统资源限制 + newLimit = applyResourceConstraints(newLimit, resourceInfo); + + return newLimit; + } + + /** + * 计算队列大小 + * queueSize = limit × (1 - RttNoLoad / RTTactual) + */ + private int calculateQueueSize() { + if (rttActual <= 0) return 0; + + int currentLimit = this.currentLimit.get(); + double queueSize = currentLimit * (1 - rttNoLoad / rttActual); + + return Math.max(0, (int) Math.round(queueSize)); + } + + @Override + protected void updateRtt(double rtt) { + long currentTime = System.currentTimeMillis(); + + // 更新实际RTT(使用指数移动平均) + if (rttActual == 0) { + rttActual = rtt; + } else { + rttActual = ALPHA * rtt + (1 - ALPHA) * rttActual; + } + + // 更新无负载RTT(取最小值) + if (rttNoLoad == 0 || rtt < rttNoLoad) { + rttNoLoad = rtt; + } + + // 定期更新无负载RTT(防止长期不更新) + if (currentTime - lastUpdateTime > 60000) { + updateNoLoadRtt(); + lastUpdateTime = currentTime; + } + } + + /** + * 更新无负载RTT + */ + private void updateNoLoadRtt() { + if (sampleCount.get() < MIN_SAMPLE_SIZE) return; + + double avgRtt = (double) totalRtt.get() / sampleCount.get() / 1000.0; + + if (rttActual < avgRtt * 1.2) { + rttNoLoad = Math.min(rttNoLoad, rttActual); + } + + sampleCount.set(0); + totalRtt.set(0); + } + + @Override + protected void updateStats(BaseRateLimitStats stats) { + SystemResourceMonitor.SystemResourceInfo resourceInfo = resourceMonitor.getCurrentInfo(); + stats.setCpuUsage(resourceInfo.getCpuUsage()); + stats.setMemoryUsage(resourceInfo.getMemoryUsage()); + stats.setSystemLoad(resourceInfo.getSystemLoad()); + stats.setJvmMemoryUsage(resourceInfo.getJvmMemoryUsage()); + + if (stats instanceof VegasRateLimitStats) { + VegasRateLimitStats vegasStats = (VegasRateLimitStats) stats; + vegasStats.setRttNoLoad(rttNoLoad); + vegasStats.setRttActual(rttActual); + vegasStats.setQueueSize(calculateQueueSize()); + vegasStats.setAlpha(3 * Math.log10(currentLimit.get())); + vegasStats.setBeta(6 * Math.log10(currentLimit.get())); + vegasStats.setThreshold(Math.log10(currentLimit.get())); + } + } + + @Override + public RateLimitStats getStats() { + VegasRateLimitStats currentStats = new VegasRateLimitStats(); + currentStats.setCurrentConnections(currentConnections.get()); + currentStats.setCurrentLimit(currentLimit.get()); + currentStats.setRejectedConnections(rejectedConnections.get()); + currentStats.setTotalRequests(totalRequests.get()); + currentStats.setTimestamp(System.currentTimeMillis()); + + updateStats(currentStats); + + return currentStats; + } + + /** + * Vegas限流统计信息 + */ + @Getter + @Accessors(chain = true) + public static class VegasRateLimitStats extends BaseRateLimitStats { + private double rttNoLoad = 0.0; + private double rttActual = 0.0; + private int queueSize = 0; + private double alpha = 0.0; + private double beta = 0.0; + private double threshold = 0.0; + + public VegasRateLimitStats setRttNoLoad(double rttNoLoad) { + this.rttNoLoad = rttNoLoad; + return this; + } + + public VegasRateLimitStats setRttActual(double rttActual) { + this.rttActual = rttActual; + return this; + } + + public VegasRateLimitStats setQueueSize(int queueSize) { + this.queueSize = queueSize; + return this; + } + + public VegasRateLimitStats setAlpha(double alpha) { + this.alpha = alpha; + return this; + } + + public VegasRateLimitStats setBeta(double beta) { + this.beta = beta; + return this; + } + + public VegasRateLimitStats setThreshold(double threshold) { + this.threshold = threshold; + return this; + } + + @Override + public String toString() { + return String.format( + "VegasRateLimitStats{currentConnections=%d, currentLimit=%d, " + + "rejectedConnections=%d, totalRequests=%d, rejectionRate=%.2f%%, " + + "connectionRate=%.2f%%, queueSize=%d, alpha=%.3f, beta=%.3f, " + + "threshold=%.3f, rttNoLoad=%.3f, rttActual=%.3f, " + + "cpuUsage=%.2f%%, memoryUsage=%.2f%%, systemLoad=%.2f, " + + "jvmMemoryUsage=%.2f%%, timestamp=%d}", + getCurrentConnections(), getCurrentLimit(), getRejectedConnections(), getTotalRequests(), + getRejectionRate(), getConnectionRate(), queueSize, alpha, beta, threshold, + rttNoLoad, rttActual, getCpuUsage(), getMemoryUsage(), getSystemLoad(), + getJvmMemoryUsage(), getTimestamp() + ); + } + } +} diff --git a/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiterTest.java b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiterTest.java new file mode 100644 index 000000000..58eabe5d6 --- /dev/null +++ b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/Gradient2RateLimiterTest.java @@ -0,0 +1,246 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * Gradient2限流算法单元测试 + */ +@ExtendWith(MockitoExtension.class) +class Gradient2RateLimiterTest { + + @Mock + private SystemResourceMonitor mockResourceMonitor; + + @Mock + private SystemResourceMonitor.SystemResourceInfo mockResourceInfo; + + private Gradient2RateLimiter rateLimiter; + + @BeforeEach + void setUp() { + // 设置配置参数 + ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit = true; + ExternalGlobalConfig.TrafficProtectionOption.maxConnections = 1000; + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 100; + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 2000; + ExternalGlobalConfig.TrafficProtectionOption.monitorInterval = 100; + ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold = 80.0; + ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold = 85.0; + + // 创建限流器实例 + rateLimiter = Gradient2RateLimiter.getInstance(); + } + + @Test + void testInitialState() { + // 测试初始状态 + assertEquals(1000, rateLimiter.getCurrentLimit()); + assertEquals(0, rateLimiter.getCurrentConnections()); + assertFalse(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testTryAcquire() { + // 测试连接获取 + assertTrue(rateLimiter.tryAcquire()); + assertEquals(1, rateLimiter.getCurrentConnections()); + + // 测试连接数达到限制时 + for (int i = 1; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + assertFalse(rateLimiter.tryAcquire()); + assertEquals(1000, rateLimiter.getCurrentConnections()); + } + + @Test + void testConnectionLifecycle() { + // 测试连接生命周期 + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + assertEquals(1, rateLimiter.getCurrentConnections()); + + rateLimiter.decrementConnections(); + assertEquals(0, rateLimiter.getCurrentConnections()); + } + + @Test + void testRttRecording() { + // 测试RTT记录 + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + rateLimiter.recordRtt(20.0); + + // 验证RTT统计 + assertTrue(rateLimiter.getStats().getTotalRequests() > 0); + } + + @Test + void testStartAndStop() { + // 测试启动和停止 + assertDoesNotThrow(() -> rateLimiter.start()); + assertDoesNotThrow(() -> rateLimiter.stop()); + } + + @Test + void testStatsCalculation() { + // 测试统计信息计算 + rateLimiter.tryAcquire(); + rateLimiter.incrementConnections(); + rateLimiter.recordRtt(10.0); + + var stats = rateLimiter.getStats(); + assertEquals(1, stats.getCurrentConnections()); + assertEquals(1000, stats.getCurrentLimit()); + assertEquals(1, stats.getTotalRequests()); + assertEquals(0.0, stats.getRejectionRate()); + assertEquals(0.1, stats.getConnectionRate()); + } + + @Test + void testGradient2Calculation() { + // 测试Gradient2值计算 + rateLimiter.recordRtt(1.0); // 无负载RTT + rateLimiter.recordRtt(2.0); // 实际RTT + + // 验证Gradient值在合理范围内 + var stats = rateLimiter.getStats(); + assertTrue(stats.getGradient() >= 0.5 && stats.getGradient() <= 1.0); + } + + @Test + void testLongRttCalculation() { + // 测试长期RTT计算(指数移动平均) + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + rateLimiter.recordRtt(20.0); + + // 验证长期RTT被正确计算 + var stats = rateLimiter.getStats(); + assertTrue(stats.getLongRtt() > 0); + } + + @Test + void testQueueSizeCalculation() { + // 测试队列大小计算 + int queueSize = (int) Math.sqrt(1000); + assertEquals(31, queueSize); // sqrt(1000) ≈ 31.62 + } + + @Test + void testMultipleConnections() { + // 测试多个连接 + for (int i = 0; i < 100; i++) { + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + } + + assertEquals(100, rateLimiter.getCurrentConnections()); + assertEquals(100, rateLimiter.getStats().getTotalRequests()); + } + + @Test + void testRejectionTracking() { + // 测试拒绝连接跟踪 + // 先填满连接数 + for (int i = 0; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + // 尝试获取新连接,应该被拒绝 + assertFalse(rateLimiter.tryAcquire()); + + // 验证拒绝统计 + assertEquals(1, rateLimiter.getStats().getRejectedConnections()); + assertTrue(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testBoundaryConditions() { + // 测试边界条件 + // 设置最小阈值 + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 500; + + // 验证限流阈值不会低于最小值 + assertTrue(rateLimiter.getCurrentLimit() >= 500); + + // 设置最大阈值 + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 1500; + + // 验证限流阈值不会超过最大值 + assertTrue(rateLimiter.getCurrentLimit() <= 1500); + } + + @Test + void testGradient2SpecificFeatures() { + // 测试Gradient2特有的功能 + rateLimiter.recordRtt(5.0); + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + + var stats = rateLimiter.getStats(); + + // 验证Gradient2特有的字段 + assertTrue(stats.getLongRtt() > 0); + assertTrue(stats.getGradient() >= 0.5 && stats.getGradient() <= 1.0); + assertTrue(stats.getQueueSize() > 0); + } + + @Test + void testExponentialMovingAverage() { + // 测试指数移动平均计算 + // 连续记录多个RTT值 + for (int i = 1; i <= 10; i++) { + rateLimiter.recordRtt(i * 10.0); + } + + var stats = rateLimiter.getStats(); + + // 验证长期RTT被正确计算 + assertTrue(stats.getLongRtt() > 0); + assertTrue(stats.getLongRtt() <= 100.0); // 最大值应该是100 + } + + @Test + void testNoLoadRttUpdate() { + // 测试无负载RTT更新 + rateLimiter.recordRtt(1.0); // 设置一个很小的RTT + + // 等待一段时间后再次记录RTT + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + rateLimiter.recordRtt(2.0); + + var stats = rateLimiter.getStats(); + assertTrue(stats.getRttNoLoad() > 0); + } + + @Test + void testGradient2StatsExtension() { + // 测试Gradient2统计信息扩展 + rateLimiter.recordRtt(10.0); + + var stats = rateLimiter.getStats(); + + // 验证Gradient2特有的统计字段 + if (stats instanceof Gradient2RateLimiter.Gradient2RateLimitStats) { + var gradient2Stats = (Gradient2RateLimiter.Gradient2RateLimitStats) stats; + assertTrue(gradient2Stats.getLongRtt() > 0); + assertTrue(gradient2Stats.getGradient() >= 0.5 && gradient2Stats.getGradient() <= 1.0); + } + } +} diff --git a/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/GradientRateLimiterTest.java b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/GradientRateLimiterTest.java new file mode 100644 index 000000000..a98e74c4b --- /dev/null +++ b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/GradientRateLimiterTest.java @@ -0,0 +1,182 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * Gradient限流算法单元测试 + */ +@ExtendWith(MockitoExtension.class) +class GradientRateLimiterTest { + + @Mock + private SystemResourceMonitor mockResourceMonitor; + + @Mock + private SystemResourceMonitor.SystemResourceInfo mockResourceInfo; + + private GradientRateLimiter rateLimiter; + + @BeforeEach + void setUp() { + // 设置配置参数 + ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit = true; + ExternalGlobalConfig.TrafficProtectionOption.maxConnections = 1000; + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 100; + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 2000; + ExternalGlobalConfig.TrafficProtectionOption.monitorInterval = 100; + ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold = 80.0; + ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold = 85.0; + + // 创建限流器实例 + rateLimiter = GradientRateLimiter.getInstance(); + } + + @Test + void testInitialState() { + // 测试初始状态 + assertEquals(1000, rateLimiter.getCurrentLimit()); + assertEquals(0, rateLimiter.getCurrentConnections()); + assertFalse(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testTryAcquire() { + // 测试连接获取 + assertTrue(rateLimiter.tryAcquire()); + assertEquals(1, rateLimiter.getCurrentConnections()); + + // 测试连接数达到限制时 + for (int i = 1; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + assertFalse(rateLimiter.tryAcquire()); + assertEquals(1000, rateLimiter.getCurrentConnections()); + } + + @Test + void testConnectionLifecycle() { + // 测试连接生命周期 + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + assertEquals(1, rateLimiter.getCurrentConnections()); + + rateLimiter.decrementConnections(); + assertEquals(0, rateLimiter.getCurrentConnections()); + } + + @Test + void testRttRecording() { + // 测试RTT记录 + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + rateLimiter.recordRtt(20.0); + + // 验证RTT统计 + assertTrue(rateLimiter.getStats().getTotalRequests() > 0); + } + + @Test + void testStartAndStop() { + // 测试启动和停止 + assertDoesNotThrow(() -> rateLimiter.start()); + assertDoesNotThrow(() -> rateLimiter.stop()); + } + + @Test + void testStatsCalculation() { + // 测试统计信息计算 + rateLimiter.tryAcquire(); + rateLimiter.incrementConnections(); + rateLimiter.recordRtt(10.0); + + var stats = rateLimiter.getStats(); + assertEquals(1, stats.getCurrentConnections()); + assertEquals(1000, stats.getCurrentLimit()); + assertEquals(1, stats.getTotalRequests()); + assertEquals(0.0, stats.getRejectionRate()); + assertEquals(0.1, stats.getConnectionRate()); + } + + @Test + void testResourceConstraints() { + // 测试资源约束 + when(mockResourceInfo.getCpuUsage()).thenReturn(90.0); + when(mockResourceInfo.getMemoryUsage()).thenReturn(90.0); + + // 模拟资源监控器 + // 这里需要注入mock,但由于是单例模式,我们直接测试算法逻辑 + assertTrue(rateLimiter.getCurrentLimit() > 0); + } + + @Test + void testGradientCalculation() { + // 测试Gradient值计算 + rateLimiter.recordRtt(1.0); // 无负载RTT + rateLimiter.recordRtt(2.0); // 实际RTT + + // 验证Gradient值在合理范围内 + var stats = rateLimiter.getStats(); + assertTrue(stats.getGradient() >= 0.5 && stats.getGradient() <= 1.0); + } + + @Test + void testQueueSizeCalculation() { + // 测试队列大小计算 + int queueSize = (int) Math.sqrt(1000); + assertEquals(31, queueSize); // sqrt(1000) ≈ 31.62 + } + + @Test + void testMultipleConnections() { + // 测试多个连接 + for (int i = 0; i < 100; i++) { + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + } + + assertEquals(100, rateLimiter.getCurrentConnections()); + assertEquals(100, rateLimiter.getStats().getTotalRequests()); + } + + @Test + void testRejectionTracking() { + // 测试拒绝连接跟踪 + // 先填满连接数 + for (int i = 0; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + // 尝试获取新连接,应该被拒绝 + assertFalse(rateLimiter.tryAcquire()); + + // 验证拒绝统计 + assertEquals(1, rateLimiter.getStats().getRejectedConnections()); + assertTrue(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testBoundaryConditions() { + // 测试边界条件 + // 设置最小阈值 + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 500; + + // 验证限流阈值不会低于最小值 + assertTrue(rateLimiter.getCurrentLimit() >= 500); + + // 设置最大阈值 + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 1500; + + // 验证限流阈值不会超过最大值 + assertTrue(rateLimiter.getCurrentLimit() <= 1500); + } +} diff --git a/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/RateLimiterIntegrationTest.java b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/RateLimiterIntegrationTest.java new file mode 100644 index 000000000..e24ac21dc --- /dev/null +++ b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/RateLimiterIntegrationTest.java @@ -0,0 +1,285 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 限流器集成测试 + * 测试所有三种算法的基本功能和性能 + */ +@ExtendWith(MockitoExtension.class) +class RateLimiterIntegrationTest { + + private GradientRateLimiter gradientRateLimiter; + private Gradient2RateLimiter gradient2RateLimiter; + private VegasRateLimiter vegasRateLimiter; + + @BeforeEach + void setUp() { + // 设置配置参数 + ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit = true; + ExternalGlobalConfig.TrafficProtectionOption.maxConnections = 1000; + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 100; + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 2000; + ExternalGlobalConfig.TrafficProtectionOption.monitorInterval = 100; + ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold = 80.0; + ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold = 85.0; + + // 创建所有限流器实例 + gradientRateLimiter = GradientRateLimiter.getInstance(); + gradient2RateLimiter = Gradient2RateLimiter.getInstance(); + vegasRateLimiter = VegasRateLimiter.getInstance(); + } + + @Test + void testAllAlgorithmsInitialState() { + // 测试所有算法的初始状态 + assertEquals(1000, gradientRateLimiter.getCurrentLimit()); + assertEquals(1000, gradient2RateLimiter.getCurrentLimit()); + assertEquals(1000, vegasRateLimiter.getCurrentLimit()); + + assertEquals(0, gradientRateLimiter.getCurrentConnections()); + assertEquals(0, gradient2RateLimiter.getCurrentConnections()); + assertEquals(0, vegasRateLimiter.getCurrentConnections()); + } + + @Test + void testAllAlgorithmsConnectionLifecycle() { + // 测试所有算法的连接生命周期 + // Gradient算法 + assertTrue(gradientRateLimiter.tryAcquire()); + gradientRateLimiter.incrementConnections(); + assertEquals(1, gradientRateLimiter.getCurrentConnections()); + gradientRateLimiter.decrementConnections(); + assertEquals(0, gradientRateLimiter.getCurrentConnections()); + + // Gradient2算法 + assertTrue(gradient2RateLimiter.tryAcquire()); + gradient2RateLimiter.incrementConnections(); + assertEquals(1, gradient2RateLimiter.getCurrentConnections()); + gradient2RateLimiter.decrementConnections(); + assertEquals(0, gradient2RateLimiter.getCurrentConnections()); + + // Vegas算法 + assertTrue(vegasRateLimiter.tryAcquire()); + vegasRateLimiter.incrementConnections(); + assertEquals(1, vegasRateLimiter.getCurrentConnections()); + vegasRateLimiter.decrementConnections(); + assertEquals(0, vegasRateLimiter.getCurrentConnections()); + } + + @Test + void testAllAlgorithmsRttRecording() { + // 测试所有算法的RTT记录 + double[] rttValues = {10.0, 15.0, 20.0, 25.0, 30.0}; + + for (double rtt : rttValues) { + gradientRateLimiter.recordRtt(rtt); + gradient2RateLimiter.recordRtt(rtt); + vegasRateLimiter.recordRtt(rtt); + } + + // 验证所有算法都正确记录了RTT + assertTrue(gradientRateLimiter.getStats().getTotalRequests() > 0); + assertTrue(gradient2RateLimiter.getStats().getTotalRequests() > 0); + assertTrue(vegasRateLimiter.getStats().getTotalRequests() > 0); + } + + @Test + void testAllAlgorithmsStartAndStop() { + // 测试所有算法的启动和停止 + assertDoesNotThrow(() -> { + gradientRateLimiter.start(); + gradient2RateLimiter.start(); + vegasRateLimiter.start(); + }); + + assertDoesNotThrow(() -> { + gradientRateLimiter.stop(); + gradient2RateLimiter.stop(); + vegasRateLimiter.stop(); + }); + } + + @Test + void testAllAlgorithmsStatsCalculation() { + // 测试所有算法的统计信息计算 + // 添加一些连接和RTT数据 + for (int i = 0; i < 10; i++) { + gradientRateLimiter.tryAcquire(); + gradientRateLimiter.incrementConnections(); + gradientRateLimiter.recordRtt(10.0 + i); + + gradient2RateLimiter.tryAcquire(); + gradient2RateLimiter.incrementConnections(); + gradient2RateLimiter.recordRtt(10.0 + i); + + vegasRateLimiter.tryAcquire(); + vegasRateLimiter.incrementConnections(); + vegasRateLimiter.recordRtt(10.0 + i); + } + + // 验证统计信息 + var gradientStats = gradientRateLimiter.getStats(); + var gradient2Stats = gradient2RateLimiter.getStats(); + var vegasStats = vegasRateLimiter.getStats(); + + assertEquals(10, gradientStats.getCurrentConnections()); + assertEquals(10, gradient2Stats.getCurrentConnections()); + assertEquals(10, vegasStats.getCurrentConnections()); + + assertEquals(10, gradientStats.getTotalRequests()); + assertEquals(10, gradient2Stats.getTotalRequests()); + assertEquals(10, vegasStats.getTotalRequests()); + } + + @Test + void testAllAlgorithmsRejectionHandling() { + // 测试所有算法的拒绝连接处理 + // 先填满连接数 + for (int i = 0; i < 1000; i++) { + gradientRateLimiter.incrementConnections(); + gradient2RateLimiter.incrementConnections(); + vegasRateLimiter.incrementConnections(); + } + + // 尝试获取新连接,应该被拒绝 + assertFalse(gradientRateLimiter.tryAcquire()); + assertFalse(gradient2RateLimiter.tryAcquire()); + assertFalse(vegasRateLimiter.tryAcquire()); + + // 验证拒绝统计 + assertEquals(1, gradientRateLimiter.getStats().getRejectedConnections()); + assertEquals(1, gradient2RateLimiter.getStats().getRejectedConnections()); + assertEquals(1, vegasRateLimiter.getStats().getRejectedConnections()); + } + + @Test + void testAllAlgorithmsBoundaryConditions() { + // 测试所有算法的边界条件 + // 设置最小和最大阈值 + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 500; + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 1500; + + // 验证所有算法的限流阈值都在有效范围内 + assertTrue(gradientRateLimiter.getCurrentLimit() >= 500); + assertTrue(gradient2RateLimiter.getCurrentLimit() >= 500); + assertTrue(vegasRateLimiter.getCurrentLimit() >= 500); + + assertTrue(gradientRateLimiter.getCurrentLimit() <= 1500); + assertTrue(gradient2RateLimiter.getCurrentLimit() <= 1500); + assertTrue(vegasRateLimiter.getCurrentLimit() <= 1500); + } + + @Test + void testAllAlgorithmsPerformance() { + // 测试所有算法的性能 + long startTime = System.currentTimeMillis(); + + // 执行大量操作 + for (int i = 0; i < 1000; i++) { + gradientRateLimiter.tryAcquire(); + gradient2RateLimiter.tryAcquire(); + vegasRateLimiter.tryAcquire(); + + if (i % 100 == 0) { + gradientRateLimiter.recordRtt(i * 0.1); + gradient2RateLimiter.recordRtt(i * 0.1); + vegasRateLimiter.recordRtt(i * 0.1); + } + } + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // 验证性能(应该在合理时间内完成) + assertTrue(duration < 5000, "性能测试应该在5秒内完成,实际耗时: " + duration + "ms"); + } + + @Test + void testAllAlgorithmsConcurrentAccess() { + // 测试所有算法的并发访问 + int threadCount = 10; + int operationsPerThread = 100; + + Thread[] threads = new Thread[threadCount]; + + for (int i = 0; i < threadCount; i++) { + final int threadId = i; + threads[i] = new Thread(() -> { + for (int j = 0; j < operationsPerThread; j++) { + try { + gradientRateLimiter.tryAcquire(); + gradient2RateLimiter.tryAcquire(); + vegasRateLimiter.tryAcquire(); + + if (j % 10 == 0) { + gradientRateLimiter.recordRtt(threadId * 10.0 + j); + gradient2RateLimiter.recordRtt(threadId * 10.0 + j); + vegasRateLimiter.recordRtt(threadId * 10.0 + j); + } + } catch (Exception e) { + // 忽略异常,继续测试 + } + } + }); + } + + // 启动所有线程 + for (Thread thread : threads) { + thread.start(); + } + + // 等待所有线程完成 + for (Thread thread : threads) { + try { + thread.join(5000); // 最多等待5秒 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + // 验证所有算法都能正确处理并发访问 + assertTrue(gradientRateLimiter.getStats().getTotalRequests() > 0); + assertTrue(gradient2RateLimiter.getStats().getTotalRequests() > 0); + assertTrue(vegasRateLimiter.getStats().getTotalRequests() > 0); + } + + @Test + void testAllAlgorithmsMemoryUsage() { + // 测试所有算法的内存使用 + Runtime runtime = Runtime.getRuntime(); + + // 记录初始内存 + long initialMemory = runtime.totalMemory() - runtime.freeMemory(); + + // 执行大量操作 + for (int i = 0; i < 10000; i++) { + gradientRateLimiter.tryAcquire(); + gradient2RateLimiter.tryAcquire(); + vegasRateLimiter.tryAcquire(); + + if (i % 100 == 0) { + gradientRateLimiter.recordRtt(i * 0.01); + gradient2RateLimiter.recordRtt(i * 0.01); + vegasRateLimiter.recordRtt(i * 0.01); + } + } + + // 强制垃圾回收 + System.gc(); + + // 记录最终内存 + long finalMemory = runtime.totalMemory() - runtime.freeMemory(); + long memoryIncrease = finalMemory - initialMemory; + + // 验证内存使用在合理范围内(增加不超过100MB) + assertTrue(memoryIncrease < 100 * 1024 * 1024, + "内存使用增加过多: " + (memoryIncrease / 1024 / 1024) + "MB"); + } +} diff --git a/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/VegasRateLimiterTest.java b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/VegasRateLimiterTest.java new file mode 100644 index 000000000..ce8cc6a66 --- /dev/null +++ b/external/external-core/src/test/java/com/iohao/game/external/core/ratelimit/VegasRateLimiterTest.java @@ -0,0 +1,291 @@ +package com.iohao.game.external.core.ratelimit; + +import com.iohao.game.external.core.config.ExternalGlobalConfig; +import com.iohao.game.external.core.monitor.SystemResourceMonitor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * Vegas限流算法单元测试 + */ +@ExtendWith(MockitoExtension.class) +class VegasRateLimiterTest { + + @Mock + private SystemResourceMonitor mockResourceMonitor; + + @Mock + private SystemResourceMonitor.SystemResourceInfo mockResourceInfo; + + private VegasRateLimiter rateLimiter; + + @BeforeEach + void setUp() { + // 设置配置参数 + ExternalGlobalConfig.TrafficProtectionOption.enableAdaptiveRateLimit = true; + ExternalGlobalConfig.TrafficProtectionOption.maxConnections = 1000; + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 100; + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 2000; + ExternalGlobalConfig.TrafficProtectionOption.monitorInterval = 100; + ExternalGlobalConfig.TrafficProtectionOption.cpuThreshold = 80.0; + ExternalGlobalConfig.TrafficProtectionOption.memoryThreshold = 85.0; + + // 创建限流器实例 + rateLimiter = VegasRateLimiter.getInstance(); + } + + @Test + void testInitialState() { + // 测试初始状态 + assertEquals(1000, rateLimiter.getCurrentLimit()); + assertEquals(0, rateLimiter.getCurrentConnections()); + assertFalse(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testTryAcquire() { + // 测试连接获取 + assertTrue(rateLimiter.tryAcquire()); + assertEquals(1, rateLimiter.getCurrentConnections()); + + // 测试连接数达到限制时 + for (int i = 1; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + assertFalse(rateLimiter.tryAcquire()); + assertEquals(1000, rateLimiter.getCurrentConnections()); + } + + @Test + void testConnectionLifecycle() { + // 测试连接生命周期 + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + assertEquals(1, rateLimiter.getCurrentConnections()); + + rateLimiter.decrementConnections(); + assertEquals(0, rateLimiter.getCurrentConnections()); + } + + @Test + void testRttRecording() { + // 测试RTT记录 + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + rateLimiter.recordRtt(20.0); + + // 验证RTT统计 + assertTrue(rateLimiter.getStats().getTotalRequests() > 0); + } + + @Test + void testStartAndStop() { + // 测试启动和停止 + assertDoesNotThrow(() -> rateLimiter.start()); + assertDoesNotThrow(() -> rateLimiter.stop()); + } + + @Test + void testStatsCalculation() { + // 测试统计信息计算 + rateLimiter.tryAcquire(); + rateLimiter.incrementConnections(); + rateLimiter.recordRtt(10.0); + + var stats = rateLimiter.getStats(); + assertEquals(1, stats.getCurrentConnections()); + assertEquals(1000, stats.getCurrentLimit()); + assertEquals(1, stats.getTotalRequests()); + assertEquals(0.0, stats.getRejectionRate()); + assertEquals(0.1, stats.getConnectionRate()); + } + + @Test + void testVegasAlgorithm() { + // 测试Vegas算法核心逻辑 + rateLimiter.recordRtt(1.0); // 无负载RTT + rateLimiter.recordRtt(2.0); // 实际RTT + + // 验证Vegas算法特有的统计字段 + var stats = rateLimiter.getStats(); + assertTrue(stats.getQueueSize() >= 0); + } + + @Test + void testQueueSizeCalculation() { + // 测试队列大小计算 + // queueSize = limit × (1 - RttNoLoad / RTTactual) + rateLimiter.recordRtt(1.0); // 无负载RTT + rateLimiter.recordRtt(2.0); // 实际RTT + + var stats = rateLimiter.getStats(); + int queueSize = stats.getQueueSize(); + + // 当RTTactual > RttNoLoad时,queueSize应该 > 0 + assertTrue(queueSize >= 0); + } + + @Test + void testMultipleConnections() { + // 测试多个连接 + for (int i = 0; i < 100; i++) { + assertTrue(rateLimiter.tryAcquire()); + rateLimiter.incrementConnections(); + } + + assertEquals(100, rateLimiter.getCurrentConnections()); + assertEquals(100, rateLimiter.getStats().getTotalRequests()); + } + + @Test + void testRejectionTracking() { + // 测试拒绝连接跟踪 + // 先填满连接数 + for (int i = 0; i < 1000; i++) { + rateLimiter.incrementConnections(); + } + + // 尝试获取新连接,应该被拒绝 + assertFalse(rateLimiter.tryAcquire()); + + // 验证拒绝统计 + assertEquals(1, rateLimiter.getStats().getRejectedConnections()); + assertTrue(rateLimiter.getStats().getRejectionRate() > 0); + } + + @Test + void testBoundaryConditions() { + // 测试边界条件 + // 设置最小阈值 + ExternalGlobalConfig.TrafficProtectionOption.minRateLimitThreshold = 500; + + // 验证限流阈值不会低于最小值 + assertTrue(rateLimiter.getCurrentLimit() >= 500); + + // 设置最大阈值 + ExternalGlobalConfig.TrafficProtectionOption.maxRateLimitThreshold = 1500; + + // 验证限流阈值不会超过最大值 + assertTrue(rateLimiter.getCurrentLimit() <= 1500); + } + + @Test + void testVegasSpecificFeatures() { + // 测试Vegas特有的功能 + rateLimiter.recordRtt(5.0); + rateLimiter.recordRtt(10.0); + rateLimiter.recordRtt(15.0); + + var stats = rateLimiter.getStats(); + + // 验证Vegas特有的字段 + assertTrue(stats.getQueueSize() >= 0); + } + + @Test + void testDynamicThresholds() { + // 测试动态阈值计算 + // alpha = 3 * log10(limit) + // beta = 6 * log10(limit) + // threshold = log10(limit) + + int currentLimit = 1000; + double expectedAlpha = 3 * Math.log10(currentLimit); + double expectedBeta = 6 * Math.log10(currentLimit); + double expectedThreshold = Math.log10(currentLimit); + + // 验证阈值计算 + assertEquals(expectedAlpha, 3 * Math.log10(1000), 0.001); + assertEquals(expectedBeta, 6 * Math.log10(1000), 0.001); + assertEquals(expectedThreshold, Math.log10(1000), 0.001); + } + + @Test + void testVegasAlgorithmLogic() { + // 测试Vegas算法的核心逻辑 + // 这里我们测试算法的数学计算部分 + + int currentLimit = 1000; + double alpha = 3 * Math.log10(currentLimit); + double beta = 6 * Math.log10(currentLimit); + double threshold = Math.log10(currentLimit); + + // 验证阈值关系 + assertTrue(alpha > threshold); + assertTrue(beta > alpha); + assertTrue(threshold > 0); + } + + @Test + void testQueueSizeBoundary() { + // 测试队列大小边界条件 + rateLimiter.recordRtt(1.0); // 无负载RTT + + // 当RTTactual = RttNoLoad时,queueSize应该 = 0 + rateLimiter.recordRtt(1.0); + + var stats = rateLimiter.getStats(); + int queueSize = stats.getQueueSize(); + + // 由于浮点数精度问题,我们检查是否接近0 + assertTrue(queueSize >= 0); + } + + @Test + void testVegasStatsExtension() { + // 测试Vegas统计信息扩展 + rateLimiter.recordRtt(10.0); + + var stats = rateLimiter.getStats(); + + // 验证Vegas特有的统计字段 + if (stats instanceof VegasRateLimiter.VegasRateLimitStats) { + var vegasStats = (VegasRateLimiter.VegasRateLimitStats) stats; + assertTrue(vegasStats.getQueueSize() >= 0); + assertTrue(vegasStats.getAlpha() > 0); + assertTrue(vegasStats.getBeta() > 0); + assertTrue(vegasStats.getThreshold() > 0); + } + } + + @Test + void testNoLoadRttUpdate() { + // 测试无负载RTT更新 + rateLimiter.recordRtt(1.0); // 设置一个很小的RTT + + // 等待一段时间后再次记录RTT + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + rateLimiter.recordRtt(2.0); + + var stats = rateLimiter.getStats(); + assertTrue(stats.getRttNoLoad() > 0); + } + + @Test + void testVegasAlgorithmConvergence() { + // 测试Vegas算法的收敛性 + // 连续记录多个RTT值,观察算法的收敛行为 + + for (int i = 1; i <= 20; i++) { + rateLimiter.recordRtt(i * 5.0); + } + + var stats = rateLimiter.getStats(); + + // 验证算法能够收敛到合理的值 + assertTrue(stats.getQueueSize() >= 0); + assertTrue(stats.getCurrentLimit() > 0); + } +} diff --git a/external/external-core/src/test/resources/test-config.properties b/external/external-core/src/test/resources/test-config.properties new file mode 100644 index 000000000..d91e962e4 --- /dev/null +++ b/external/external-core/src/test/resources/test-config.properties @@ -0,0 +1,24 @@ +# 测试配置文件 +# 用于限流器单元测试的配置参数 + +# 流量保护配置 +traffic.protection.enable=true +traffic.protection.max.connections=1000 +traffic.protection.min.threshold=100 +traffic.protection.max.threshold=2000 +traffic.protection.monitor.interval=100 + +# 自适应限流配置 +adaptive.rate.limit.enable=true +adaptive.rate.limit.window.size=60 +adaptive.rate.limit.alpha=0.1 + +# 系统资源阈值 +system.cpu.threshold=80.0 +system.memory.threshold=85.0 + +# 测试参数 +test.thread.count=10 +test.operations.per.thread=100 +test.performance.timeout=5000 +test.memory.limit=100