spring-cloud-alibaba:2021.0.4.0
spring-boot:2.6.8
spring-cloud-loadbalancer:3.1.3
sentinel:2021.0.4.0
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-transport-simple-httpartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webfluxartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
dependency>
server:
port: 8481
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: devilvan
password: 741258963hjkl
management:
endpoints:
web:
exposure:
include: '*'
server:
port: 8581
spring:
application:
name: nacos-consumer
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: localhost:8848
【资源】是sentinel限流、熔断的基本单位,可以设置每个资源的阈值。
@Service
public class NacosProviderServiceImpl implements NacosProviderService {
private static final String[] RESOURCE_NAME_ARR = new String[]{"echo", "echo2"};
/**
* 初始化限流规则
*/
@PostConstruct
public void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
for (String resourceName : RESOURCE_NAME_ARR) {
FlowRule flowRule = new FlowRule();
// 设置受保护的资源
flowRule.setResource(resourceName);
// 设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 1.
flowRule.setCount(1);
flowRules.add(flowRule);
}
// 加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
}
其中echo方法使用注解形式定义sentinel资源,并通过自定义类的形式指定熔断和限流的方法。
/**
* @Description Nacos生产者 控制层
*/
@RestController
@RequestMapping(value = "nacosProviderController")
public class NacosProviderController {
@Resource(name = "nacosProviderServiceImpl")
private NacosProviderService nacosProviderService;
@GetMapping(value = "/echo/{str}")
@SentinelResource(value = "echo", fallback = "echoFallback", fallbackClass = EchoFallback.class,
blockHandler = "echoBlockHandler", blockHandlerClass = EchoFallback.class)
public ResultMessage<String> echo(@PathVariable String str) {
return nacosProviderService.echo(str);
}
@GetMapping(value = "/echo2/{str}")
public ResultMessage<String> echo2(@PathVariable String str) {
return nacosProviderService.echo2(str);
}
}
/**
* @Description echo方法 异常回调类
*/
public class EchoFallback {
/**
* 遇到异常走的逻辑
*
* @param str 原方法的参数
* @param e 异常信息
* @return 异常回调方法返回值,和原方法返回值一致
*/
public static ResultMessage<String> echoFallback(String str, Throwable e) {
ResultMessage<String> resultMessage = new ResultMessage<>();
String message = "熔断-echo方法调用异常,str: " + str + "\n" + e;
resultMessage.setMessage(message);
return resultMessage;
}
/**
* 方法限流逻辑
*
* @param str 原方法的参数
* @param e 异常信息
* @return 限流回调方法返回值,和原方法返回值一致
*/
public static ResultMessage<String> echoBlockHandler(String str, BlockException e) {
ResultMessage<String> resultMessage = new ResultMessage<>();
String message = "限流-echo方法进行 限流,str: " + str + "\n" + e;
resultMessage.setMessage(message);
return resultMessage;
}
}
echo2方法则使用官方案例的写法,先在初始化initFlowRules()
方法中定义echo2资源,然后在实现类中编写对该资源熔断、限流的逻辑
/**
* @Description Nacos生产者 业务逻辑实现类
*/
@Service
public class NacosProviderServiceImpl implements NacosProviderService {
private static final String[] RESOURCE_NAME_ARR = new String[]{"echo", "echo2"};
/**
* 初始化限流规则
*/
@PostConstruct
public void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
for (String resourceName : RESOURCE_NAME_ARR) {
FlowRule flowRule = new FlowRule();
// 设置受保护的资源
flowRule.setResource(resourceName);
// 设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 1.
flowRule.setCount(1);
flowRules.add(flowRule);
}
// 加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
/**
* 测试限流/熔断的方法
*
* @param str 原方法的参数
* @return 回调
*/
@Override
public ResultMessage<String> echo(String str) {
ResultMessage<String> resultMessage = new ResultMessage<>();
if ("devilvan".equals(str)) {
String msg = "Hello Nacos Discovery " + str;
resultMessage.setMessage(msg);
} else {
throw new RuntimeException();
}
return resultMessage;
}
/**
* 测试sentinel设置资源并使用的方法
*
* @param str 入参字符串
* @return 回调
*/
@Override
public ResultMessage<String> echo2(String str) {
String resource = "echo2";
ResultMessage<String> resultMessage = new ResultMessage<>();
Entry entry = null;
try {
entry = SphU.entry(resource);
if ("devilvan".equals(str)) {
String msg = "Hello Nacos Discovery " + str;
resultMessage.setMessage(msg);
} else {
throw new RuntimeException();
}
} catch (BlockException e) {
String msg = "限流-echo2方法调用异常,str: " + str + "\n" + e;
resultMessage.setMessage(msg);
} catch (Exception e) {
String msg = "熔断-echo2方法调用异常,str: " + str + "\n" + e;
resultMessage.setMessage(msg);
} finally {
if (entry != null) {
entry.exit();
}
}
return resultMessage;
}
}
以上两个方法案例中都涉及到对异常的处理(高亮部分),熔断的方法对应使用Throwable的异常捕获,限流的方法只使用BlockException
异常进行捕获。
/**
* @Description Nacos消费者 控制层
*/
@RestController
@RequestMapping(value = "nacosConsumerController")
public class NacosConsumerController {
private NacosFeignService nacosFeignService;
@Autowired
public void setNacosFeignService(NacosFeignService nacosFeignService) {
this.nacosFeignService = nacosFeignService;
}
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
public String echo(@PathVariable String str) {
return nacosFeignService.echo(str);
}
@RequestMapping(value = "/echo2/{str}", method = RequestMethod.GET)
public String echo2(@PathVariable String str) {
return nacosFeignService.echo2(str);
}
}
/**
* @author Evad.Wu
* @Description Nacos Feign 远程调用接口
* @date 2022-11-05
*/
@FeignClient(value = "nacos-provider")
public interface NacosFeignService {
/**
* 远程调用的测试方法
*
* @param str 路由下的参数
* @return 返回值
* @author Evad.Wu
* @Description 远程调用的测试方法
* @date 2022-11-05
*/
@GetMapping(value = "nacosProviderController/echo/{str}")
String echo(@PathVariable String str);
/**
* 远程调用的测试方法2
*
* @param str 路由下的参数
* @return 返回值
* @author Evad.Wu
* @Description 远程调用的测试方法2
* @date 2022-11-05
*/
@GetMapping(value = "nacosProviderController/echo2/{str}")
String echo2(@PathVariable String str);
}