diff --git a/changelog.md b/changelog.md index abe4cb9e..0eb502ab 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # changelog +## 2.1.0 + +- 支持分布式限流(redis实现) + ## 2.0.0 - 全面使用nacos,舍弃zookeeper(1.x版本见1.x分支) diff --git a/doc/docs/_sidebar.md b/doc/docs/_sidebar.md index 578edd2f..370a3a49 100644 --- a/doc/docs/_sidebar.md +++ b/doc/docs/_sidebar.md @@ -1,32 +1,32 @@ -* [首页](/?t=1566794701229) +* [首页](/?t=1567770151526) * 开发文档 - * [快速体验](files/10010_快速体验.md?t=1566794701233) - * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1566794701264) - * [新增接口](files/10020_新增接口.md?t=1566794701265) - * [开发流程](files/10021_开发流程.md?t=1566794701265) - * [业务参数校验](files/10030_业务参数校验.md?t=1566794701265) - * [错误处理](files/10040_错误处理.md?t=1566794701265) - * [编写文档](files/10041_编写文档.md?t=1566794701265) - * [接口交互详解](files/10050_接口交互详解.md?t=1566794701265) - * [easyopen支持](files/10070_easyopen支持.md?t=1566794701265) - * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1566794701266) - * [ISV管理](files/10085_ISV管理.md?t=1566794701266) - * [自定义返回结果](files/10087_自定义返回结果.md?t=1566794701266) - * [自定义过滤器](files/10088_自定义过滤器.md?t=1566794701266) - * [路由授权](files/10090_路由授权.md?t=1566794701266) - * [接口限流](files/10092_接口限流.md?t=1566794701266) - * [监控日志](files/10093_监控日志.md?t=1566794701266) - * [SDK开发](files/10095_SDK开发.md?t=1566794701266) - * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1566794701267) - * [应用授权](files/10097_应用授权.md?t=1566794701267) - * [传统web开发](files/10100_传统web开发.md?t=1566794701267) - * [文件上传](files/10104_文件上传.md?t=1566794701270) - * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1566794701270) - * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1566794701270) - * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1566794701270) + * [快速体验](files/10010_快速体验.md?t=1567770151530) + * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1567770151558) + * [新增接口](files/10020_新增接口.md?t=1567770151558) + * [开发流程](files/10021_开发流程.md?t=1567770151558) + * [业务参数校验](files/10030_业务参数校验.md?t=1567770151558) + * [错误处理](files/10040_错误处理.md?t=1567770151558) + * [编写文档](files/10041_编写文档.md?t=1567770151558) + * [接口交互详解](files/10050_接口交互详解.md?t=1567770151558) + * [easyopen支持](files/10070_easyopen支持.md?t=1567770151559) + * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1567770151559) + * [ISV管理](files/10085_ISV管理.md?t=1567770151559) + * [自定义返回结果](files/10087_自定义返回结果.md?t=1567770151559) + * [自定义过滤器](files/10088_自定义过滤器.md?t=1567770151559) + * [路由授权](files/10090_路由授权.md?t=1567770151559) + * [接口限流](files/10092_接口限流.md?t=1567770151559) + * [监控日志](files/10093_监控日志.md?t=1567770151559) + * [SDK开发](files/10095_SDK开发.md?t=1567770151559) + * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1567770151559) + * [应用授权](files/10097_应用授权.md?t=1567770151560) + * [传统web开发](files/10100_传统web开发.md?t=1567770151560) + * [文件上传](files/10104_文件上传.md?t=1567770151560) + * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1567770151560) + * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1567770151560) + * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1567770151560) * 原理分析 - * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1566794701270) - * [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1566794701270) - * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1566794701270) - * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1566794701270) - * [常见问题](files/90100_常见问题.md?t=1566794701270) + * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1567770151560) + * [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1567770151560) + * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1567770151560) + * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1567770151560) + * [常见问题](files/90100_常见问题.md?t=1567770151560) diff --git a/doc/docs/files/10092_接口限流.md b/doc/docs/files/10092_接口限流.md index e56c32b8..2c36cd00 100644 --- a/doc/docs/files/10092_接口限流.md +++ b/doc/docs/files/10092_接口限流.md @@ -42,3 +42,41 @@ SOP提供了简单的接口限流策略: ![限流配置](images/10092_1.png "10092_1.png") ![限流配置](images/10092_2.png "10092_2.png") + +## 分布式限流 + +默认的限流方式是单机的,如果要部署多台网关实例,需要使用分布式限流 + +SOP使用redis进行分布式限流(只支持窗口策略),操作步骤如下: + +- sop-gateway/pom.xml添加redis依赖 + +```xml + + org.springframework.boot + spring-boot-starter-data-redis + +``` + +- sop-gateway下的application-dev.properties文件添加redis配置 + +```properties +# redis +spring.redis.database=0 +spring.redis.host=127.0.0.1 +spring.redis.port=6379 +``` + +- ZuulConfig.java中添加如下代码: + +```java +@Autowired +private RedisTemplate redisTemplate; + +@Override +protected void doAfter() { + super.doAfter(); + ApiConfig.getInstance().setLimitManager(new RedisLimitManager(redisTemplate)); +} +``` + diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java deleted file mode 100644 index 28efaf4a..00000000 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.gitee.sop.adminserver.api.service; - -import com.gitee.easyopen.annotation.Api; -import com.gitee.easyopen.annotation.ApiService; -import com.gitee.easyopen.doc.annotation.ApiDoc; -import com.gitee.easyopen.doc.annotation.ApiDocMethod; -import com.gitee.easyopen.util.CopyUtil; -import com.gitee.fastmybatis.core.query.Query; -import com.gitee.sop.adminserver.api.service.param.LimitParam; -import com.gitee.sop.adminserver.api.service.param.RouteSearchParam; -import com.gitee.sop.adminserver.api.service.result.LimitVO; -import com.gitee.sop.adminserver.bean.RouteDefinition; -import com.gitee.sop.adminserver.bean.RouteConfigDto; -import com.gitee.sop.adminserver.common.BizException; -import com.gitee.sop.adminserver.common.LimitEnum; -import com.gitee.sop.adminserver.entity.ConfigRouteLimit; -import com.gitee.sop.adminserver.mapper.ConfigRouteLimitMapper; -import com.gitee.sop.adminserver.service.RouteConfigService; -import com.gitee.sop.adminserver.service.RouteService; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.BooleanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * 限流 - * - * @author tanghc - */ -@ApiService -@ApiDoc("服务管理") -@Slf4j -public class LimitApi { - - @Autowired - RouteService routeService; - - @Autowired - RouteConfigService routeConfigService; - - @Autowired - ConfigRouteLimitMapper configRouteLimitMapper; - - @Api(name = "route.limit.list") - @ApiDocMethod(description = "限流列表", elementClass = LimitVO.class) - List listLimit(RouteSearchParam param) throws Exception { - List routeDefinitionList = routeService.getRouteDefinitionList(param); - if (CollectionUtils.isEmpty(routeDefinitionList)) { - return Collections.emptyList(); - } - List routeIdList = getRouteIdList(routeDefinitionList); - // key:routeId - Map routeLimitMap = getStoreConfigRouteLimit(routeIdList); - List gatewayRouteDefinitions = routeDefinitionList - .stream() - .map(gatewayRouteDefinition -> { - String routeId = gatewayRouteDefinition.getId(); - LimitVO vo = new LimitVO(); - CopyUtil.copyPropertiesIgnoreNull(gatewayRouteDefinition, vo); - ConfigRouteLimit configRouteLimit = routeLimitMap.getOrDefault(routeId, getDefaultLimit()); - CopyUtil.copyPropertiesIgnoreNull(configRouteLimit, vo); - vo.setRouteId(routeId); - vo.setHasRecord(BooleanUtils.toInteger(configRouteLimit.getId() != null)); - return vo; - }) - .collect(Collectors.toList()); - return gatewayRouteDefinitions; - } - - private List getRouteIdList(List routeDefinitionList) { - return routeDefinitionList - .stream() - .map(RouteDefinition::getId) - .collect(Collectors.toList()); - } - - private Map getStoreConfigRouteLimit(List routeIdList) { - Query query = new Query(); - query.in("route_id", routeIdList); - // key:routeId - Map routeLimitMap = configRouteLimitMapper.list(query) - .stream() - .collect(Collectors.toMap(ConfigRouteLimit::getRouteId, Function.identity())); - return routeLimitMap; - } - - private ConfigRouteLimit getDefaultLimit() { - ConfigRouteLimit configRouteLimit = new ConfigRouteLimit(); - configRouteLimit.setLimitType(LimitEnum.TYPE_LEAKY_BUCKET.getVal()); - configRouteLimit.setLimitStatus(LimitEnum.STATUS_CLOSE.getVal()); - return configRouteLimit; - } - - @Api(name = "route.limit.update") - @ApiDocMethod(description = "修改限流") - @Transactional(rollbackFor = Exception.class) - public void updateLimtit(LimitParam param) { - String routeId = param.getRouteId(); - ConfigRouteLimit configRouteLimit = configRouteLimitMapper.getByColumn("route_id", routeId); - if (configRouteLimit == null) { - configRouteLimit = new ConfigRouteLimit(); - CopyUtil.copyPropertiesIgnoreNull(param, configRouteLimit); - configRouteLimitMapper.save(configRouteLimit); - } else { - CopyUtil.copyPropertiesIgnoreNull(param, configRouteLimit); - configRouteLimitMapper.updateIgnoreNull(configRouteLimit); - } - RouteConfigDto routeConfigDto = new RouteConfigDto(); - CopyUtil.copyPropertiesIgnoreNull(param, routeConfigDto); - try { - routeConfigService.sendRouteConfigMsg(routeConfigDto); - } catch (Exception e) { - log.error("推送限流消息错误, param:{}", param, e); - throw new BizException("修改失败,请查看日志"); - } - } -}