zuul整合sentinel实现限流
效果图
一分钟以内点击三次触发限流
Set<GatewayFlowRule> rules=new HashSet<>(); rules.add(new GatewayFlowRule("product-service").setCount(3).setIntervalSec(60)); GatewayRuleManager.loadRules(rules);
自定义限流返回结果
本次测试需要三个项目,eureka项目,product项目,zuul网关项目
父级pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>zuul-aprent</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>eureka-service</module> <module>prodoct-service</module> <module>order-service</module> <module>zuul-service</module> <module>zuul-one</module> <module>zuul-two</module> <module>zuul-three</module> <module>zuul-sentinal</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <!--编译插件--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> <!--打包插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
eureka项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.eureka</groupId> <artifactId>eureka-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <finalName>eureka</finalName> </build> </project>
package com.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @author yourheart * @Description * @create 2022-04-20 21:17 */ @SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
server.port=8761 spring.application.name=eureka-service eureka.instance.hostname=localhost eureka.client.service-url.defaultZone=http://localhost:8761/eureka eureka.client.register-with-eureka=false eureka.client.fetch-registry=false logging.level.com.eureka=info logging.level.web=info spring.devtools.add-properties=false
product项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.product</groupId> <artifactId>prodoct-service</artifactId> <dependencies> <!--客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--添加fastjson依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> <!--判断空的用法 --> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <finalName>product</finalName> </build> </project>
server.port=1000 spring.application.name=product-service #注册到eureka注册中心,如果是注册到集群就用逗号连接多个,单实例写上一个就好 eureka.client.service-url.defaultZone=http://localhost:8761/eureka logging.level.com.product=debug logging.level.web=debug spring.devtools.add-properties=false
package com.product; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @author yourheart * @Description * @create 2022-04-20 21:28 */ @SpringBootApplication @EnableDiscoveryClient public class ProductApplication { public static void main(String[] args) { SpringApplication.run(ProductApplication.class,args); } } package com.product.controller.front; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author yourheart * @Description * @create 2022-04-20 21:30 */ @RestController @RequestMapping("/product") @Slf4j public class ProductController { @GetMapping("/getProduct/{id}") public String selectProduct(@PathVariable String id){ log.info("【调用服务者入参】:{}",id); return "查询到的主键返回"+id; } @GetMapping("/testFirst/{id}") public String testFirst(@PathVariable Integer id){ log.info("【调用服务者入参】:{}",id); StringBuilder stringBuilder=new StringBuilder(); stringBuilder.append("qwe"); stringBuilder.append("-"); stringBuilder.append(id); return stringBuilder.toString(); } }
zuul项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.zuul</groupId> <artifactId>zuul-sentinal</artifactId> <dependencies> <!--spring cloud zuul依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!--netflix eureka client依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-zuul-adapter</artifactId> <version>1.8.2</version> </dependency> </dependencies> </project>
server.port=1006 spring.application.name=zuul-sentinal #注册到eureka注册中心,如果是注册到集群就用逗号连接多个,单实例写上一个就好 eureka.client.service-url.defaultZone=http://localhost:8761/eureka logging.level.com.zuul=debug logging.level.web=debug spring.devtools.add-properties=false #设置为不支持 URL 粒度 spring.cloud.sentinel.filter.enabled=false
package com.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @author yourheart * @Description * @create 2022-06-06 23:22 */ @SpringBootApplication //开启zuul注解 @EnableZuulProxy @EnableDiscoveryClient public class SentinalApplication { public static void main(String[] args) { SpringApplication.run(SentinalApplication.class,args); } } package com.zuul.exception; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.DefaultBlockFallbackProvider; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider; import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author yourheart * @Description * @create 2022-06-09 0:19 */ public class MyBlockFallbackProvider implements ZuulBlockFallbackProvider { private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class); @Override public String getRoute() { return "*"; } @Override public BlockResponse fallbackResponse(String route, Throwable cause) { RecordLog.info(String.format("[Sentinel DefaultBlockFallbackProvider] Run fallback route: %s", route)); if (cause instanceof BlockException) { return new BlockResponse(429, "Sentinel触发限流", route); } else { return new BlockResponse(500, "系统异常", route); } } } package com.zuul.filter; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter; import com.netflix.zuul.ZuulFilter; import com.zuul.exception.MyBlockFallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.Set; /** * @author yourheart * @Description * @create 2022-06-06 23:30 */ @Configuration public class ZuulConfigFilter { @Bean public ZuulFilter sentinelZuulPreFilter(){ return new SentinelZuulPreFilter(); } @Bean public ZuulFilter sentinelZuulPostFilter(){ return new SentinelZuulPostFilter(); } @Bean public ZuulFilter sentinelZuulErrorFilter(){ return new SentinelZuulErrorFilter(); } /** * spring容器初始化调用该方法 */ @PostConstruct public void doInt(){ /** * 注册 FallbackProvider */ ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider()); /** * 加载网关限流规则 */ initGatewayRules(); } private void initGatewayRules(){ Set<GatewayFlowRule> rules=new HashSet<>(); /** * 设置为60秒点击3次触发限流 */ rules.add(new GatewayFlowRule("product-service").setCount(3).setIntervalSec(60)); GatewayRuleManager.loadRules(rules); } }
测试地址http://127.0.0.1:1006/product-service/product/getProduct/1992
官方文档提供大家学习
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81