当某个服务阻塞时,大量客户线程就会消耗完Tomcat的链接,从而其他服务也不可使用。这个现象就是服务雪崩。解决方案有两种:服务降级和服务熔断。
服务降级是消费者端进行的,服务熔断的服务生产者进行的。
服务降级
服务降级,就是服务超时后立刻返回给客户一个失败的信息,不让它在占用Tomcat的链接。
1、导入jar
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、yml
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
#配置服务降级的时长,不配置也可以,默认是1s,这里配置成了3s,这是全局的配置
3、ConsumerController
@RestController
@RequestMapping("consumer")
@DefaultProperties(defaultFallback = "defaultFallback") //默认的返回降级的方法
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
//@HystrixCommand(fallbackMethod = "queryByIdFallback")//可以独立配置降级方法
@HystrixCommand(commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")//独立配置降级时间
})
public String queryById(@PathVariable("id") Long id) {
String url="http://user-service/user/"+id;//ip+端口 用服务id代替了,默认是轮询
String user = restTemplate.getForObject(url, String.class);
return user;
}
public String queryByIdFallback(Long id){
return "服务太拥挤了";
}
public String defaultFallback(){
return "默认服务太拥挤了";
}
服务熔断
默认情况下,20次服务请求,50%的失败率就会触发服务熔断。此时熔断器就会打开,打开后5s后会进入半开状态,会允许少量的请求通过,测试服务是否可用,可用熔断器就会变为关闭状态,否则继续等5s继续测试。
这个很难演示出来,所以用id模拟这个熔断。
@RestController
@RequestMapping("consumer")
@DefaultProperties(defaultFallback = "defaultFallback")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
//@HystrixCommand(fallbackMethod = "queryByIdFallback")
@HystrixCommand(commandProperties = {
//请求次数不小于10次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),
//10s进入半开状态
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000"),
//60%的错误熔断熔断器
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="60")
})
public String queryById(@PathVariable("id") Long id) {
//抛出异常表明服务失败
if(id%2==0){
throw new RuntimeException("异常");
}
String url="http://user-service/user/"+id;//ip+端口 用服务id代替了,默认是轮询
String user = restTemplate.getForObject(url, String.class);
return user;
}
public String queryByIdFallback(Long id){
return "服务太拥挤了";
}
public String defaultFallback(){
return "默认服务太拥挤了";
}
}
开发状态下,这些参数不用调,这里为了演示效果。
连续点击id为16的链接
快速点击id为17的链接
过几秒后再次点击id为17的链接
它就又变好了。