微服務架構中,服務間透過網路調用。若下游服務 (如 Service4) 響應緩慢或失效,上游服務 (Service1) 的執行緒會大量阻塞等待,導致執行緒池耗盡,進而拖垮同機器上的其他服務 (Service2、Service3) —— **級聯故障**。
getFallback() 降級邏輯,釋放執行緒,保護上游服務穩定。<dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-core</artifactId><version>1.5.3</version></dependency>
<dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-metrics-event-stream</artifactId><version>1.5.3</version></dependency>
<!-- Retrofit + OkHttp + Jackson -->
<dependency><groupId>com.squareup.retrofit</groupId><artifactId>retrofit</artifactId><version>1.9.0</version></dependency>
<dependency><groupId>com.squareup.okhttp</groupId><artifactId>okhttp</artifactId><version>2.4.0</version></dependency>
@Component
public class RestAdapterConfig {
@Autowired private MyLoadBalancer lb;
public <T> T create(Class<T> apiType, String serviceName) {
ServerAddress server = lb.chooseServer(serviceName); // 負載均衡選址
String groupKey = apiType.getSimpleName(); // Hystrix CommandGroupKey
RestAdapter adapter = new RestAdapter.Builder()
.setConverter(new JacksonConverter())
.setErrorHandler(new MyErrorHandler())
.setClient(new MyHttpClient(server, groupKey)) // 自定義 Client 注入 Hystrix
.setEndpoint("/").build();
return adapter.create(apiType);
}
}
public class MyHttpClient implements Client {
private final ServerAddress server;
private final String commandGroupKey;
private final int timeoutMs = 3000; // 硬編碼超時,後續可配置化
public MyHttpClient(ServerAddress server, String commandGroupKey) { ... }
@Override public Response execute(Request request) throws IOException {
Setter setter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandGroupKey))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(timeoutMs));
return new HttpHystrixCommand(setter, server, request).execute(); // 同步執行
}
}
public class HttpHystrixCommand extends HystrixCommand<Response> {
private final ServerAddress server;
private final Request request;
private String requestUrl;
public HttpHystrixCommand(Setter setter, ServerAddress server, Request request) {
super(setter); this.server = server; this.request = request;
}
@Override protected Response run() throws Exception {
// 1. Retrofit Request -> OkHttp Request (含負載均衡地址)
Request okReq = buildOkHttpRequest(request, server);
// 2. OkHttp 同步調用
com.squareup.okhttp.Response okRes = new OkHttpClient().newCall(okReq).execute();
// 3. OkHttp Response -> Retrofit Response
return convertToRetrofitResponse(okRes);
}
@Override protected Response getFallback() {
log.error("Hystrix 超時/失敗,請求URL: {}", requestUrl);
// 返回特定狀態碼 404 + 錯誤訊息,供 ErrorHandler 識別
return new Response(requestUrl, 404, "execute getFallback because execution timeout",
new ArrayList<>(), null);
}
// 輔助轉換方法省略...
}
public class MyErrorHandler implements ErrorHandler {
@Override public Throwable handleError(RetrofitError cause) {
Response resp = cause.getResponse();
if (resp != null && resp.getStatus() == 404) {
return new HystrixRuntimeException(cause); // 自定義運行時異常
}
return cause;
}
}
@RestController @RequestMapping("/myserviceA")
public class MyserviceAController {
@PostMapping("/provinces/{provincename}")
public Province getProvinceByCityName(@PathVariable String provincename,
@RequestParam long personNum) throws InterruptedException {
Thread.sleep(5000); // 故意延遲 5 秒 > Hystrix 3 秒超時
return new Province(1, provincename, personNum);
}
}
// Client
@Component
public class MyserviceAClient {
@Autowired RestAdapterConfig adapterConfig;
public Province getProvinceByCityName(String name, long num) {
MyserviceAAPI api = adapterConfig.create(MyserviceAAPI.class, "myserviceA");
return api.getProvinceByCityName(name, num);
}
}
// Controller
@RestController @RequestMapping("/myserviceB")
public class MyserviceBController {
@Autowired MyserviceAClient client;
@PostMapping("/provinces/{provincename}")
public Province callA(@PathVariable String provincename, @RequestParam long personNum) {
return client.getProvinceByCityName(provincename, personNum); // 3 秒後返回 Fallback
}
}
POST /myserviceB/provinces/浙江?personNum=1000。getFallback(),Service B 於 3 秒內收到 404 降級響應,拋出 HystrixRuntimeException,不會阻塞 5 秒。hystrix-metrics-event-stream) 監控熔斷指標。