原理
在微服務(wù)架構(gòu)中鸭栖,服務(wù)之間形成調(diào)用鏈路,鏈路中的任何一個(gè)服務(wù)提供者都可能面臨著相應(yīng)超時(shí)握巢、宕機(jī)等不可用的情況晕鹊,在高并發(fā)的情況下,這種情況會(huì)隨著并發(fā)量的上升惡化暴浦,形成“雪崩效應(yīng)”溅话,而斷路器hystrix正是用來解決這一個(gè)問題的組件。
斷路器基本原理為:
- 正常情況下歌焦,斷路器關(guān)閉飞几,服務(wù)消費(fèi)者正常請(qǐng)求微服務(wù)
- 一段事件內(nèi),失敗率達(dá)到一定閾值(比如50%失敗独撇,或者失敗了50次)屑墨,斷路器將斷開躁锁,此時(shí)不再請(qǐng)求服務(wù)提供者,而是只是快速失敗的方法(斷路方法)
- 斷路器打開一段時(shí)間卵史,自動(dòng)進(jìn)入“半開”狀態(tài)战转,此時(shí),斷路器可允許一個(gè)請(qǐng)求方法服務(wù)提供者程腹,如果請(qǐng)求調(diào)用成功匣吊,則關(guān)閉斷路器,否則繼續(xù)保持?jǐn)嗦菲鞔蜷_狀態(tài)寸潦。
斷路器hystrix是保證了局部發(fā)生的錯(cuò)誤,不會(huì)擴(kuò)展到整個(gè)系統(tǒng)社痛,從而保證系統(tǒng)的即使出現(xiàn)局部問題也不會(huì)造成系統(tǒng)雪崩见转。
本文示例代碼:helloworld+helloworldfeign+hello+world
主要見springcloud-demo下hello
/world
/helloworld
/helloworldfeign
項(xiàng)目。
配置/使用
下面講解在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依賴蒜哀,因?yàn)橄旅嬗玫降腀HystrixCommand注解用到了hystrix-javanica包
- 啟動(dòng)類加上@EnableCircuitBreaker注解(@EnableHystrix也可以)
- 修改HelloWorldController的入口請(qǐng)求方法
@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指向斷路方法斩箫,該方法會(huì)在調(diào)用hello服務(wù)或者world服務(wù)失敗時(shí)被調(diào)用。
@HystrixCommand 注解還可以配置超時(shí)事件等其他屬性撵儿。
- 測(cè)試
1)依次啟動(dòng)eureka server:
discovery
/trace
/hello
/world
/helloword
項(xiàng)目
2)在瀏覽器輸入地址http:\\localhost:8020/message
乘客,則返回正確的結(jié)果
3)停止hello項(xiàng)目,再次輸入上述地址淀歇,則執(zhí)行斷路器中的方法易核。
feign下整合Hystrix
- feign禁用Hystrix
在Spring Cloud中,只要Hystrix在項(xiàng)目的classpath中浪默,F(xiàn)eign就會(huì)用斷路器包裹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
默認(rèn)情況下feign已經(jīng)整合了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 475572229@qq.com
* @create 17-8-23
*/
@FeignClient(value="hello",fallback = HelloServiceFallback.class)
public interface HelloService {
@GetMapping("/message")
HelloMessage hello();
}
實(shí)現(xiàn)了接口fallback的類的實(shí)現(xiàn):
package com.example.helloworldfeign.service;
import com.example.helloworldfeign.model.HelloMessage;
import org.springframework.stereotype.Component;
/**
* @author billjiang 475572229@qq.com
* @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項(xiàng)目同上
- 測(cè)試
1)依次啟動(dòng)eureka server:
discovery
/trace
/hello
/world
/helloword-feing
項(xiàng)目
2)在瀏覽器輸入地址http:\\localhost:8030/message
碰逸,則返回正確的結(jié)果
3)停止hello項(xiàng)目,再次輸入上述地址阔加,則執(zhí)行斷路器中的方法饵史。
查看斷路器錯(cuò)誤日志
如果要查看詳細(xì)的斷路器的日志,可以通過注解@FeignClient的fallbackFactory來實(shí)現(xiàn)胜榔,如下代碼所示:
import com.example.helloworldfeign.model.HelloMessage;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author billjiang 475572229@qq.com
* @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 475572229@qq.com
* @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;
}
};
}
}
這樣會(huì)在控制臺(tái)把具體導(dǎo)致熔斷的信息輸出胳喷,以便跟蹤錯(cuò)誤。