原理
在微服務架構中,服務之間形成調用鏈路,鏈路中的任何一個服務提供者都可能面臨着相應超時、宕機等不可用的情況,在高併發的情況下,這種情況會隨着併發量的上升惡化,形成“雪崩效應”,而斷路器hystrix正是用來解決這一個問題的組件。
斷路器基本原理爲:
正常情況下,斷路器關閉,服務消費者正常請求微服務
一段事件內,失敗率達到一定閾值(比如50%失敗,或者失敗了50次),斷路器將斷開,此時不再請求服務提供者,而是隻是快速失敗的方法(斷路方法)
斷路器打開一段時間,自動進入“半開”狀態,此時,斷路器可允許一個請求方法服務提供者,如果請求調用成功,則關閉斷路器,否則繼續保持斷路器打開狀態。
斷路器hystrix是保證了局部發生的錯誤,不會擴展到整個系統,從而保證系統的即使出現局部問題也不會造成系統雪崩。
配置/使用
下面講解在restTemplate和feign中斷路器的配置和使用步驟
restTemplate+ribbon整合Hystrix
引入hystrix依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
雖然Eureka依賴了ribbon,ribbon依賴了hystrix-core,但還是要引用了上面的maven依賴,因爲下面用到的@HystrixCommand註解用到了hystrix-javanica包
啓動類加上@EnableCircuitBreaker註解(@EnableHystrix也可以)
修改HelloWorldController的入口請求方法
@GetMapping("/message")
@HystrixCommand(fallbackMethod = "getMessageFallback")
public HelloworldMessage getMessage() {
HelloMessage hello = getMessageFromHelloService();
WorldMessage world = getMessageFromWorldService();
HelloworldMessage helloworld = new HelloworldMessage();
helloworld.setHello(hello);
helloworld.setWord(world);
log.debug("Result helloworld message:{}", helloworld);
return helloworld;
}
/**
* 斷路方法
* @return
*/
public HelloworldMessage getMessageFallback(){
HelloMessage helloMessage=new HelloMessage();
helloMessage.setName("hello");
helloMessage.setMessage("error occurs");
WorldMessage worldMessage=new WorldMessage();
worldMessage.setMessage("world error occurs");
HelloworldMessage helloworldMessage=new HelloworldMessage();
helloworldMessage.setHello(helloMessage);
helloworldMessage.setWord(worldMessage);
return helloworldMessage;
}
通過@HystrixCommand註解的fallbackMethod指向斷路方法,該方法會在調用hello服務或者world服務失敗時被調用。
@HystrixCommand 註解還可以配置超時事件等其他屬性。
測試
1)依次啓動eureka server:discovery/trace/hello/world/helloword項目
2)在瀏覽器輸入地址http:\localhost:8020/message,則返回正確的結果
3)停止hello項目,再次輸入上述地址,則執行斷路器中的方法。
feign下整合Hystrix
feign禁用Hystrix
在Spring Cloud中,只要Hystrix在項目的classpath中,Feign就會用斷路器包裹Feign客戶端的所有方法,如果要禁用Hystrix則可以通過自定義feign的配置來解決。
@Configuration
public class FeignConfiguration{
@Bean
@Scope("prototype")
public Feign Builder feignBuilder(){
return Feign.builder();
}
}
要禁用Hystrix的接口引用該配置即可
@FeignClient(name="hello",configuration=FeignConfiguration.class)
public interface HelloService{
......
}
feign使用Hystrix
啓用Hystrix
默認情況下feign已經整合了Hystrix,在配置文件中開啓即可(本人用的的Dalston.SR2版本的Spring Cloud,需要在配置文件開啓)
feign:
hystrix:
enabled: true
接口指定回退類
在HelloService中修改FeignClient類,指定fallback的類
package com.example.helloworldfeign.service;
import com.example.helloworldfeign.model.HelloMessage;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author billjiang [email protected]
* @create 17-8-23
*/
@FeignClient(value="hello",fallback = HelloServiceFallback.class)
public interface HelloService {
@GetMapping("/message")
HelloMessage hello();
}
實現了接口fallback的類的實現:
package com.example.helloworldfeign.service;
import com.example.helloworldfeign.model.HelloMessage;
import org.springframework.stereotype.Component;
/**
* @author billjiang [email protected]
* @create 17-8-28
*/
@Component
public class HelloServiceFallback implements HelloService {
@Override
public HelloMessage hello() {
HelloMessage helloMessage=new HelloMessage();
helloMessage.setName("hello");
helloMessage.setMessage("error occurs");
return helloMessage;
}
}
world項目同上
測試
1)依次啓動eureka server:discovery/trace/hello/world/helloword-feing項目
2)在瀏覽器輸入地址http:\localhost:8030/message,則返回正確的結果
3)停止hello項目,再次輸入上述地址,則執行斷路器中的方法。
查看斷路器錯誤日誌
如果要查看詳細的斷路器的日誌,可以通過註解@FeignClient的fallbackFactory來實現,如下代碼所示:
import com.example.helloworldfeign.model.HelloMessage;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author billjiang [email protected]
* @create 17-8-23
*/
@FeignClient(value="hello",fallbackFactory = HelloServiceFallbackFactory.class)
public interface HelloService {
@GetMapping("/message")
HelloMessage hello();
}
HelloServiceFallbackFactory類:
package com.example.helloworldfeign.service;
import com.example.helloworldfeign.model.HelloMessage;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @author billjiang [email protected]
* @create 17-8-28
*/
@Component
public class HelloServiceFallbackFactory implements FallbackFactory<HelloService> {
private final static Logger LOGGER= LoggerFactory.getLogger(HelloServiceFallbackFactory.class);
@Override
public HelloService create(Throwable throwable) {
return new HelloService() {
@Override
public HelloMessage hello() {
//print the error
LOGGER.error("fallback ,the result is:",throwable);
HelloMessage helloMessage=new HelloMessage();
helloMessage.setName("hello");
helloMessage.setMessage("error occurs");
return helloMessage;
}
};
//需要JAVA Spring Cloud大型企業分佈式微服務雲構建的B2B2C電子商務平臺源碼 一零三八七七四六二六
}
}
這樣會在控制檯把具體導致熔斷的信息輸出,以便跟蹤錯誤。