前言
在微服務(wù)架構(gòu)中造壮,根據(jù)業(yè)務(wù)來拆分成一個(gè)個(gè)的服務(wù),服務(wù)與服務(wù)之間可以相互調(diào)用(RPC)告嘲,在Spring Cloud可以用RestTemplate+Ribbon和Feign來調(diào)用嗡呼。為了保證其高可用,單個(gè)服務(wù)通常會(huì)集群部署足淆。由于網(wǎng)絡(luò)原因或者自身的原因,服務(wù)并不能保證100%可用礁阁,如果單個(gè)服務(wù)出現(xiàn)問題,調(diào)用這個(gè)服務(wù)就會(huì)出現(xiàn)線程阻塞族奢,此時(shí)若有大量的請(qǐng)求涌入姥闭,Servlet容器的線程資源會(huì)被消耗完畢,導(dǎo)致服務(wù)癱瘓越走。服務(wù)與服務(wù)之間的依賴性棚品,故障會(huì)傳播靠欢,會(huì)對(duì)整個(gè)微服務(wù)系統(tǒng)造成災(zāi)難性的嚴(yán)重后果,這就是服務(wù)故障的“雪崩”效應(yīng)铜跑。
為了解決這個(gè)問題门怪,業(yè)界提出了斷路器模型。
一锅纺、斷路器簡介
在一個(gè)分布式系統(tǒng)里掷空,許多依賴不可避免的會(huì)調(diào)用失敗,比如超時(shí)囤锉、異常等坦弟,如何能夠保證在一個(gè)依賴出問題的情況下,不會(huì)導(dǎo)致整體服務(wù)失敗官地,這個(gè)就是Hystrix需要做的事情酿傍。Hystrix提供了熔斷、隔離驱入、Fallback赤炒、cache、監(jiān)控等功能亏较,能夠在一個(gè)莺褒、或多個(gè)依賴同時(shí)出現(xiàn)問題時(shí)保證系統(tǒng)依然可用。
Netflix開源了Hystrix組件宴杀,實(shí)現(xiàn)了斷路器模式癣朗,SpringCloud對(duì)這一組件進(jìn)行了整合。 在微服務(wù)架構(gòu)中旺罢,一個(gè)請(qǐng)求需要調(diào)用多個(gè)服務(wù)是非常常見的旷余,如下圖:
較底層的服務(wù)如果出現(xiàn)故障,會(huì)導(dǎo)致連鎖故障扁达。當(dāng)對(duì)特定的服務(wù)的調(diào)用的不可用達(dá)到一個(gè)閥值(Hystric 是5秒20次) 斷路器將會(huì)被打開正卧。
斷路打開后,可用避免連鎖故障跪解,fallback方法可以直接返回一個(gè)固定值炉旷。
二、準(zhǔn)備工作
這篇文章基于上一篇文章的工程叉讥,首先啟動(dòng)上一篇文章的工程窘行,啟動(dòng)eureka-server 工程;啟動(dòng)eureka-client工程图仓,它的端口為8762罐盔。
三、在Ribbon中使用路斷器
改造serice-ribbon 工程的代碼救崔,首先在pox.xml文件中加入spring-cloud-starter-netflix-hystrix的起步依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在程序的啟動(dòng)類ServiceRibbonApplication 加@EnableHystrix注解開啟Hystrix:
package com.example.serverribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableHystrix
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
public class ServerRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServerRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
改造HelloService類惶看,在HelloService方法上加上@HystrixCommand注解捏顺。該注解對(duì)該方法創(chuàng)建了熔斷器的功能,并指定了fallbackMethod熔斷方法纬黎,熔斷方法直接返回了一個(gè)字符串幅骄,字符串為"hi,"+name+",sorry,error!",代碼如下:
package com.example.serverribbon.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hierror")
public String hiService(String name) {
return restTemplate.getForObject("http://eureka-client/hi?name="+name,String.class);
}
public String hierror(String name){ return "hi,"+name+",sorry,error!";}
}
啟動(dòng):service-ribbon 工程本今,當(dāng)我們訪問http://localhost:8764/hi?name=lisi,瀏覽器顯示:
此時(shí)關(guān)閉eureka-client工程拆座,當(dāng)我們再訪問http://localhost:8764/hi?name=lisi,瀏覽器會(huì)顯示:
這就說明當(dāng)eureka-client工程不可用的時(shí)候诈泼,service-ribbon調(diào)用eureka-client的API接口時(shí)懂拾,會(huì)執(zhí)行快速失敗,直接返回一組字符串铐达,而不是等待響應(yīng)超時(shí)岖赋,這很好的控制了容器的線程阻塞。
四瓮孙、Feign中使用路斷器
Feign是自帶斷路器的唐断,在D版本的Spring Cloud之后,它沒有默認(rèn)打開杭抠。需要在配置文件中配置打開它脸甘,在配置文件加以下代碼:
feign:
hystrix:
enabled: true
基于service-feign工程進(jìn)行改造,只需要在FeignClient的HiService接口的注解中加上fallback的指定類就行了:
package com.example.servicefeign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "eureka-client",fallback = ServiceHiHystrix.class)
public interface HiService {
@RequestMapping(value = "hi",method = RequestMethod.GET)
String sayhiclient(@RequestParam(value = "name") String name);
}
ServiceHiHystric需要實(shí)現(xiàn)HiService接口偏灿,并注入到Ioc容器中丹诀,代碼如下:
package com.example.servicefeign.service;
import org.springframework.stereotype.Component;
@Component
public class ServiceHiHystrix implements HiService {
@Override
public String sayhiclient(String name) {
return "sorry"+name;
}
}
啟動(dòng)servcie-feign工程,瀏覽器打開http://localhost:8765/hi?name=lisi,注意此時(shí)eureka-client工程沒有啟動(dòng)翁垂,網(wǎng)頁顯示:
再次啟動(dòng)eureka-client工程后铆遭,用瀏覽器打開http://localhost:8765/hi?name=lisi