一、Why服务容错
在微服务架构中,需要将系统拆分成多个服务单元,各单元的应用间通过服务注册与订阅的方式相互依赖。由于服务之间通过远程过程调用RPC的方式执行,就有可能因为网络原因或者依赖服务自身问题造成调用失败或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因等待出现故障的依赖方响应延迟造成任务积压,最终导致自身服务的瘫痪。
举个例子,我们的系统中分为A,B,C等服务单元。用户的调用链为:User -> A -> B -> C。在用户User请求A的时候,A回去请求B,B去请求C,当服务C因为自身处理逻辑以及网络原因导致响应缓慢,会直接导致服务B中请求C的线程被阻塞,接连导致A中线程阻塞,在漫长的等待过程中,User会得到调用失败的结果。如果在高并发情况之下,因为下游服务C故障而影响上游服务,将A,B服务"拖死",导致不可用。
在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较于传统架构更加不稳定。为了解决这些问题,就产升了服务容错保护机制等组件。而在SpringCloud中,这个强大的组件就是Hystrix,下面会通过搭建服务介绍hystrix的使用,包括超时设置,降级处理等。
二、快速入门
2.1 Consumer构建
首选要在consumer工程pom文件中引入hystrix组件:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
工程主类ConsumerApplication中使用@EnableCircuitBreaker注解来开启断路器功能:
EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrix
@SpringBootApplication(exclude = PageHelperAutoConfiguration.class)
public class ConsumerApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
System.out.println("ヾ(◍°∇°◍)ノ゙ Spring Boot Application Boot SUCCESS ヾ(◍°∇°◍)ノ゙\n" +
" ______ _ ______ \n" +
"|_ _ \\ / |_|_ _ `. \n" +
" | |_) | .--. .--. `| |-' | | `. \\ .--. \n" +
" | __'. / .'`\\ \\/ .'`\\ \\| | | | | |/ .'`\\ \\ \n" +
" _| |__) || \\__. || \\__. || |, _| |_.' /| \\__. | \n" +
"|_______/ '.__.' '.__.' \\__/|______.' '.__.' ");
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 注意这里要指向原先用main方法执行的Application启动类
return builder.sources(ConsumerApplication.class);
}
}
ConsumerController定义:
@RestController
@RequestMapping("/springcloud/consumer/hystrix")
public class HystrixController extends BaseController {
@Resource
private HelloService helloService;
@GetMapping("/timeout")
public String hystrixTimeout() {
String resStr = helloService.hello();
System.out.println(resStr);
return success(resStr);
}
}
HelloService接口定义:
public interface HelloService {
String hello();
}
HelloServiceImpl实现:
@Service
public class HelloServiceImpl implements HelloService {
@Resource
private HelloFeign helloFeign;
@Override
@HystrixCommand(commandKey = "testKey", groupKey = "testGroup")
public String hello() {
return helloFeign.hello();
}
}
FeignClient定义:
@FeignClient(name = "provider-service")
public interface HelloFeign {
@GetMapping(value = "/springcloud/privoder/hello")
String hello();
}
hystrix配置文件:
hystrix:
threadpool:
testGroup:
coreSize: 20
maximumSize: 100
allowMaximumSizeToDivergeFromCoreSize: true
maxQueueSize: 200
queueSizeRejectionThreshold: 1000
command:
testKey:
execution:
timeout:
enabled: true
isolation:
strategy: THREAD
thread:
timeoutInMilliseconds: 1000
interruptOnTimeout: true
interruptOnFutureCancel: false
semaphore:
maxConcurrentRequests: 5000
2.2 Provider构建
@Slf4j
@RestController
@RequestMapping("/springcloud/provider")
public class ProviderController extends BaseController {
@GetMapping(value = "/hello")
public String hello() throws Exception{
//让处理线程随机等待sleepTime毫秒
int sleepTime = new Random().nextInt(3000);
Thread.sleep(sleepTime);
System.out.println("elapse time = " + sleepTime);
return success("hello hystrix elapse " + sleepTime);
}
}
2.3 演练
生产者模拟超时处理时间为0~3000ms,消费者请求的超时时间为1000ms,参数为:timeoutInMilliseconds,通过多次请求消费者,可以观察到两种结果:
1.返回结果正常,返回码200,响应时间<1000ms
{"errno":0,"data":{},"errmsg":"{\"errno\":0,\"data\":{},\"errmsg\":\"hello hystrix elapse 774\"}"}
2.返回结果异常,返回码500,响应时间>1000ms
{
"timestamp": "2020-01-05T07:10:39.470+0000",
"status": 500,
"error": "Internal Server Error",
"message": "testKey timed-out and fallback failed.",
"trace": "com.netflix.hystrix.exception.HystrixRuntimeException:",
"path": "//springcloud/consumer/hystrix/timeout"
}
三、超时设定及服务降级
有时候我们需要捕获异常情况,并返回自定义的信息给上游,也是所谓的"服务降级"。fallback是Hystrix命令执行失败时使用后备方法,用来实现服务的降级处理逻辑。通过@HystrixCommand中的fallbackMethod参数来指定具体的服务降级实现方法。
@Service
public class HelloServiceImpl implements HelloService {
@Resource
private HelloFeign helloFeign;
@Override
@HystrixCommand(fallbackMethod = "helloFallback", commandKey = "testKey", groupKey = "testGroup")
public String hello() {
return helloFeign.hello();
}
public String helloFallback() {
return "hello fallback";
}
}
在使用注解来定义服务降级逻辑时,我们需要将具体的Hystrix命令与fallback实现函数定义在同一个类中,并且fallbackMethod的值必须与实现fallback方法的名字相同。由于必须定义在一个类中,所以对于fallback的访问修饰符没有特定的要求,定义为private,public,protected都行。
异常返回结果为(>1000ms):
{"errno":0,"data":{},"errmsg":"hello fallback"}
Author:忆之独秀
Email:[email protected]
转载注明出处:https://blog.csdn.net/lavorange/article/details/103843058