一、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