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提供了简单的接口限流策略:


+
+## 分布式限流
+
+默认的限流方式是单机的,如果要部署多台网关实例,需要使用分布式限流
+
+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("修改失败,请查看日志");
- }
- }
-}