🌈Yu-Gateway::基于 Netty 构建的自研 API 网关,采用 Java 原生实现,整合 Nacos 作为注册配置中心。其设计目标是为微服务架构提供高性能、可扩展的统一入口和基础设施,承载请求路由、安全控制、流量治理等核心网关职能。
🌈项目代码地址:https://github.com/YYYUUU42/YuGateway-master
如果该项目对你有帮助,可以在 github 上点个 ⭐ 喔 🥰🥰
🌈自研网关系列:可以点开专栏,参看完整的文档
目录
1、限流配置
2、实现流程
Redis 固定窗口限流
Guava 单机限流
3、限流压测
1、限流配置
nacos 上的配置:
type:匹配的类型(根据路径或者服务名称)
value:路径或者服务名
model:限流方式(单机或者分布式)
algorithm:限流算法(固定窗口、令牌桶)
duration:限流时间单位(秒)
permits:限流请求次数(次)
{"id": "http-server","name": "http-server","paths": ["/http-server/ping","/http-server/gray"],"prefix": "/http-server","protocol": "http","retryConfig": {"times": 3},"serviceId": "backend-http-server","filterConfigs": [{"config": {"load_balance": "RoundRobin"},"id": "load_balance_filter"},{"id": "auth_filter"},{"id": "gray_filter"},{"id": "flow_ctl_filter"}],"flowControlConfigs": [ {"type": "path","value": "/http-server/ping","mode": "distributed","algorithm": "fixed_window","config": {"duration": 1,"permits": 10}} ]}
2、实现流程
继续通过debug的方式来讲述流程,由于类比较多,就不展示代码,在 github 上 clone 代码执行查看
首先还是从 nacos 中读取 Rule 规则,得到限流的配置,这里是可以制定多个限流规则的,每个 url 都可以自己的限流规
这一步的主要作用是获取一个 FlowControlByPathRule 的实例,这样做的目的是为了实现对每个服务路径的流量控制,每个服务路径都有一个对应的 FlowControlByPathRule 实例,用于处理该路径的流量控制规则,也算是单例设计模式的一种运用
if (flowControlConfig.getType().equalsIgnoreCase(FilterConst.FLOW_CTL_TYPE_PATH)&& path.equals(flowControlConfig.getValue())) {flowControlRule = FlowControlByPathRule.getInstance(rule.getServiceId(), path);
}
这里根据服务ID和请求路径,以及从配置中心获取的限流配置,来执行具体的流控操作
if (flowControlConfig == null || StringUtils.isEmpty(serviceId) || StringUtils.isEmpty(flowControlConfig.getConfig())) {return;
}
//获得当前路径对应的流控次数
Map<String, Integer> configMap = JSON.parseObject(flowControlConfig.getConfig(), Map.class);//判断是否包含流控规则 FLOW_CTL_LIMIT_DURATION:限流时间单位---秒 FLOW_CTL_LIMIT_PERMITS:限流请求次数---次
if (!configMap.containsKey(FLOW_CTL_LIMIT_DURATION) || !configMap.containsKey(FLOW_CTL_LIMIT_PERMITS)) {return;
}//得到流控时间和时间内限制次数
double duration = configMap.get(FLOW_CTL_LIMIT_DURATION);
double permits = configMap.get(FLOW_CTL_LIMIT_PERMITS);//当前请求是否触发流控标志位
boolean flag = false;
String key = serviceId + "." + path;//如果是分布式项目 那么我们就需要使用Redis来实现流控 单机则可以直接使用Guava
if (FilterConst.FLOW_CTL_MODE_DISTRIBUTED.equalsIgnoreCase(flowControlConfig.getMode())) {flag = switch (flowControlConfig.getAlgorithm()) {case VOTE_BUCKET_ALGORITHM -> new VoteBucketAlgorithm(new JedisUtil()).executeResp(flowControlConfig);case FIXED_WINDOWS_ALGORITHM -> new StableAlgorithm(new JedisUtil()).executeResp(flowControlConfig);default -> new VoteBucketAlgorithm(new JedisUtil()).executeResp(flowControlConfig);};
}
Redis 固定窗口限流
/*** @param limit 请求限制数量* @param windowSize 窗口大小*/
public boolean isAllowed(String id, int limit, int windowSize) {String lockKey = PREFIX + ":" + "LOCK" + ":" + id;// 窗口初始化try {boolean isLock = jedisUtil.getDistributeLock(lockKey, id, windowSize);if (isLock) {String window_key = PREFIX + ":" + id;long current = jedisUtil.increment(window_key);if (current == 1) {jedisUtil.setExpire(window_key, windowSize);}return current <= limit;}} finally {jedisUtil.releaseDistributeLock(lockKey, id);}return false;
}
Guava 单机限流
主要就是通过 Guava 库中的 RateLimiter 类来实现限流
/*** 获取令牌** @param permits 需要获取的令牌数量* @return 是否获取成功*/
public boolean acquire(int permits) {return rateLimiter.tryAcquire(permits);
}
3、限流压测
这里的话,网关限流配置是 1 秒 10个请求
jmeter 设置 1 秒 100 个请求,结果树显示只有 10 个请求响应成功,剩下的请求失败