本文章是在網(wǎng)易云課堂的課程學(xué)習(xí)中編寫(xiě),部分圖片從網(wǎng)易云課堂ppt引用
一、微服務(wù)請(qǐng)求情況
1、請(qǐng)求處理情況
【請(qǐng)求處理】一個(gè)請(qǐng)求可能有多個(gè)微服務(wù)協(xié)同處理(相互依賴)
【服務(wù)超時(shí)】服務(wù)可能超時(shí)、網(wǎng)絡(luò)不通,導(dǎo)致調(diào)用者出現(xiàn)阻塞
【系統(tǒng)雪崩】請(qǐng)求一旦大量阻塞,會(huì)占用大量資源,可能導(dǎo)致整個(gè)系統(tǒng)雪崩
2、構(gòu)建彈性應(yīng)用
【服務(wù)限流】服務(wù)消費(fèi)者限制自身對(duì)某一服務(wù)能發(fā)起的并發(fā)請(qǐng)求數(shù)量,超過(guò)數(shù)量則不調(diào)用或等一段時(shí)間后再調(diào)用
【服務(wù)熔斷】熔斷狀態(tài)下,服務(wù)消費(fèi)者不會(huì)發(fā)起對(duì)某一服務(wù)的調(diào)用
【服務(wù)降級(jí)】請(qǐng)求異常情況下,程序執(zhí)行指定的降級(jí)策略(可類比try-catch)
3、spring cloud提供的hystrix
若服務(wù)出現(xiàn)超時(shí)或其他錯(cuò)誤,可以使用【hystrix】來(lái)處理
二、集成Hystrix
在《分布式系統(tǒng)開(kāi)發(fā)技術(shù) | Eureka》中代碼的基礎(chǔ)上,對(duì) 【服務(wù)消費(fèi)者】進(jìn)行改造
1. maven引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2. 代碼示例
創(chuàng)建一個(gè)類CustomerCommand,繼承HystrixCommand,重寫(xiě)fallback方法
import com.netflix.hystrix.*;
import org.springframework.web.client.RestTemplate;
/**
* 繼承HystrixCommand,重寫(xiě)fallback方法
*/
public class CustomerCommand extends HystrixCommand<Object> {
private RestTemplate restTemplate;
/**
* 重寫(xiě)構(gòu)造方法,傳入我們需要的參數(shù)
* @param restTemplate
*/
public CustomerCommand(RestTemplate restTemplate) {
super(
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("study-hystrix")) //設(shè)置命令分組名
.andCommandKey(HystrixCommandKey.Factory.asKey("CustomerController")) //設(shè)置命令名,誰(shuí)發(fā)起請(qǐng)求的設(shè)置成誰(shuí)
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("studyThreadPool")) //設(shè)置線程池名
//設(shè)置熔斷的參數(shù)
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(100) //超時(shí)時(shí)間:100毫秒
.withCircuitBreakerSleepWindowInMilliseconds(5000)) //熔斷時(shí)長(zhǎng):5秒
//設(shè)置線程池參數(shù)
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(1) //線程池大小
.withMaxQueueSize(2)) //線程池倉(cāng)庫(kù)大小
);
this.restTemplate = restTemplate;
}
/**
* 實(shí)現(xiàn)run方法
* @return
* @throws Exception
*/
@Override
protected Object run() throws Exception {
//核心實(shí)現(xiàn),調(diào)用我們期望調(diào)用的方法
System.out.println("當(dāng)前線程是: "+Thread.currentThread().getName());
Object result = restTemplate.getForObject("http://helloserver",String.class,"");
return result;
}
/**
* 降級(jí)方法
* @return
*/
@Override
protected Object getFallback() {
//核心方法,降級(jí)之后會(huì)實(shí)現(xiàn)這個(gè)
System.out.println("降級(jí)啦。。。");
return "降級(jí)了,返回降級(jí)";
}
}
改造CustomerController類中的發(fā)送請(qǐng)求方法,通過(guò)CustomerCommand類去代理相關(guān)請(qǐng)求
@RestController
public class CustomerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
@GetMapping("index")
public Object getIndex(){
return new CustomerCommand(restTemplate).execute();
}
}
這里可以看到,這種請(qǐng)求方式也可以收到應(yīng)答
我們來(lái)嘗試讓某個(gè)服務(wù)提供者模擬宕機(jī)情況:
@SpringBootApplication
@EnableEurekaClient
@RestController
public class HelloDemoPeer1Application {
public static void main(String[] args) {
SpringApplication.run(HelloDemoPeer1Application.class, args);
}
@GetMapping("")
public Object index() throws InterruptedException {
Random random = new Random();
int timeOut = random.nextInt(150);
System.out.println("當(dāng)前線程休眠時(shí)間是:"+timeOut);
Thread.sleep(timeOut);
String str = "這是服務(wù)端1返回的應(yīng)答";
return new String(str);
}
}
hystrix設(shè)置的超時(shí)時(shí)間是100毫秒,若休眠時(shí)間大于100毫秒,則執(zhí)行fallback