Sentinel 限流示例
首先下载 sentinel-dashboard-1.8.1.jar
下载地址
https://github.com/alibaba/Sentinel/releases
cmd 到 jar包目录 , 运行命令 :
java -Dserver.port=8088 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
运行结果:
代码:
调用入口 Controller :
package com..sentinel; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphO; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.fastjson.JSONObject; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/user") public class SentinelController { @Resource private UserService userService; public static final String RESOURCE_NAME = "userList"; /** * 1.采用异常处理的形式 (控制台根据 userList 限流) * @return */ @RequestMapping("/exception") public List<User> exception(){ System.out.println(" exception 请求 进来 ...."); List<User> userList = null; Entry entry = null; try { entry = SphU.entry(RESOURCE_NAME); userList = userService.getList(); } catch (BlockException e) { List<User> list = new ArrayList<>(); list.add(new User("exception", "访问资源被限流!")); return list; }finally { if(entry != null){ System.out.println("执行 finally ....."); entry.exit(); } } return userList; } /** * 2.采用返回布尔值的方式 (控制台根据 userList 限流) * @return */ @RequestMapping("/booLean") public List<User> booLean(){ System.out.println(" booLean 请求 进来 ...."); List<User> userList = null; if(SphO.entry(RESOURCE_NAME)){ try{ userList = userService.getList(); }finally { System.out.println("执行 finally ....."); SphO.exit(); } }else { List<User> list = new ArrayList<>(); list.add(new User("booLean", "访问资源被限流!")); return list; } return userList; } /** * 3.采用注解形式,代码无侵入性 (控制台根据 userList 限流) * @return */ @RequestMapping("/annotation") public List<User> annotation(){ List<User> userList = userService.queryAllAnnotation(); return userList; } /** * 4.熔断 降级 (控制台根据 userList 限流) * @return */ @RequestMapping("/fallback") public List<User> fallback(){ List<User> userList = userService.queryAllFallback(); return userList; } //============================ 以下为根据地址限流 =============================== /** * 5. (控制台根据 /user/dashboard 地址限流) * @return */ @RequestMapping("/dashboard") public List<User> dashboard(){ List<User> userList = userService.queryAllDashboard(); return userList; } /** * 6. (控制台根据 /user/newTest 地址限流) * @return */ @RequestMapping("/newTest") public List<User> newTest(){ List<User> userList = userService.NewTest(); return userList; } /** * 7. (控制台根据 /user/newJson 地址限流) * @return */ @RequestMapping("/newJson") public @ResponseBody String newJson(){ JSONObject userList = userService.NewJson(); return userList.toString(); } }
配置类 :
package com..sentinel; import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.CompositeFilter; import javax.servlet.Filter; @Configuration public class SentinelConfig { /** * 用于注解限流 * 将SentinelResourceAspect注册为一个Bean * */ @Bean public SentinelResourceAspect sentinelResourceAspect(){ return new SentinelResourceAspect(); } /** * 配置filter * 与 Sentinel 控制台进行通信, * 把所有访问的 Web URL 自动统计为 Sentinel 的资源. * @return */ public FilterRegistrationBean sentinelFilterRegistration(){ FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CompositeFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setName("sentinelFilter"); registrationBean.setOrder(1); return registrationBean; } }
简单的实体类:
package com..sentinel; public class User { String id; String name; User(String id,String name){ this.id = id; this.name = name; } public String getId() { return id; } public String getName() { return name; } public void setId(String id) { this.id = id; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } }
接口 和 接口实现类:
package com..sentinel; import com.alibaba.fastjson.JSONObject; import java.util.List; public interface UserService { public List<User> getList(); public List<User> queryAllAnnotation(); public List<User> queryAllFallback(); public List<User> queryAllDashboard(); public List<User> NewTest(); public JSONObject NewJson(); } package com..sentinel; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.fastjson.JSONObject; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class UserServiceImpl implements UserService { @Override public List<User> getList() { List<User> list = new ArrayList<>(); list.add(new User("1", "zhangsan")); list.add(new User("2", "liusi")); list.add(new User("3", "wangwu")); return list; } //注解形式 value是资源名称,是必填项。blockHandler填限流处理的方法名称 @Override @SentinelResource(value=SentinelController.RESOURCE_NAME,blockHandler = "annotation") public List<User> queryAllAnnotation() { System.out.println("正常请求....."); List<User> list = new ArrayList<>(); list.add(new User("1", "zhangsan")); list.add(new User("2", "liusi")); list.add(new User("3", "wangwu")); return list; } //注解限流处理方法 public List<User> annotation(BlockException ex){ System.out.println("请求频繁,进入注解限流....."); List<User> list = new ArrayList<>(); list.add(new User("annotation", "访问资源被限流!")); return list; } // 抛出非 BlockException 的异常时,就会进入到fallback方法中,实现熔断机制 @Override @SentinelResource(value=SentinelController.RESOURCE_NAME,fallback = "fallback") public List<User> queryAllFallback() { System.out.println("正常请求....."); List<User> list = new ArrayList<>(); list.add(new User("1", "zhangsan")); list.add(new User("2", "liusi")); list.add(new User("3", "wangwu")); if(list.size()!=0){ throw new RuntimeException("list is not null ..."); } return list; } //熔断降级处理方法 public List<User> fallback(Throwable ex){ System.out.println("访问资源异常,进入 fallback ....."); System.out.println("异常信息---> : "); ex.printStackTrace(); List<User> list = new ArrayList<>(); list.add(new User("fallback", "访问资源异常,降级处理!")); return list; } @Override @SentinelResource(value="queryAllDashboard",fallback = "dashboardFallback") public List<User> queryAllDashboard() { System.out.println("Dashboard正常请求....."); List<User> list = new ArrayList<>(); list.add(new User("1", "zhangsan")); list.add(new User("2", "liusi")); list.add(new User("3", "wangwu")); return list; } public List<User> dashboardFallback(){ System.out.println("Dashboard访问资源频繁,进入 fallback ....."); List<User> list = new ArrayList<>(); list.add(new User("Dashboard-fallback", "访问资源频繁,降级处理!")); return list; } @Override @SentinelResource(value= "NewTest" ,fallback ="newFallback" ) public List<User> NewTest() { System.out.println("NewTest正常请求....."); List<User> list = new ArrayList<>(); list.add(new User("1", "zhangsan")); list.add(new User("2", "liusi")); list.add(new User("3", "wangwu")); return list; } public List<User> newFallback(){ System.out.println("NewTest访问资源频繁,进入 fallback ....."); List<User> list = new ArrayList<>(); list.add(new User("NewTest-fallback", "访问资源频繁,降级处理!")); return list; } public List<User> exceptionHandler(BlockException ex) { System.out.println("NewTest 异常......"); ex.printStackTrace(); List<User> list = new ArrayList<>(); list.add(new User("NewTest-Exception", "访问资源异常,降级处理!")); return list; } @Override @SentinelResource(value = "NewJson",fallback = "JsonFallback") public JSONObject NewJson() { System.out.println("NewJson 正常请求....."); JSONObject json = new JSONObject(); json.put("1","zhangsan"); json.put("2","liusi"); json.put("3","wangwu"); return json; } public JSONObject JsonFallback(){ System.out.println("NewJson 访问资源频繁,进入 fallback ....."); JSONObject json = new JSONObject(); json.put("fallback","访问资源频繁,降级处理!"); return json; } }
application.properties :
spring.application.name=ac-Sentinel
spring.cloud.sentinel.transport.dashboard=(本机地址):8088
pom ( groupId 需完善 ) :
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.</groupId> <!-- groupId 需完善 --> <artifactId>ac-sentinel</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ac-sentinel</name> <description>ac-sentinel</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Sentinel 依赖 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.1</version> </dependency> <!-- Sentinel 注解支持 对应Spring 中的切面 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.8.1</version> </dependency> <!-- Transport 模块来与 Sentinel 控制台进行通信--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
服务启动添加 参数 :
-Dserver.port=8080 -Dcsp.sentinel.dashboard.server=(本机地址):8088 -Dcsp.sentinel.api.port=8720 -Dproject.name=Test
注:
###(-Dproject.name=Test Test根据业务改,这里用来测试)
访问 http://(本机地址):8088
用户名 密码 都是 sentinel
点击登录 多了个Test ( 看不到就 刷新 或 重新登录 )
点开,里面有 个 簇点链路 ,可以把入口的几个方法调用一遍 结果 :
点击 流控 ,把 单机阈值 调成 2 点击新增 ,会进入到 流控规则 :
测试:
对入口的几个方法 一秒内多调用几遍 查看结果