第一节,服务雪崩简介
服务雪崩就是:一个服务不可用,导致一系列服务不可用,而这种后果往往无法预料。
造成雪崩原因可以归结为以下三个:
1,服务提供者不可用(硬件故障,程序bug,缓存击穿,用户大量请求)
2,重试加大流量(用户重试,代码逻辑重试)
3,服务调用者不可用(同步等待造成的资源耗尽)
解决方案有如下5个,其中隔离包括两种:
1,降级:超时降级,资源不足时(线程或信号量)降级,降级后可以配合降级接口放回托底数据。实现一个fallback方法,当请求后端服务出现异常的时候,可以使用fallback方法返回的值;
2,隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用;
3,熔断:当失败率(如因网络故障或超时 造成的失败率高)达到阈值自动触发降级,熔断器触发的快速失败会进行快速恢复;
4,缓存:提供了请求缓存;
5,请求合并:提供了请求合并。
下面的雪崩解决方案是基于ribbon的,即在发送请求的时候,需要自己手工构造远程调用。
第二节,微服务雪崩解决方案一:服务降级
场景:比如一个订单系统请求一个库存系统,一个请求发过去,由于各种原因,网络超时,在规定的时间内没有返回响应结果,这个时候更多的请求过来了,不断地请求库存服务,不断的创建线程,由于没有返回,也就没有资源的释放。时间一长,必将耗尽系统资源,导致系统崩溃。本来你的订单系统好好的,但是请求了一个有问题的库存系统,导致订单系统也崩溃了,然后订单系统又不断调用其他的依赖系统,然后导致其他依赖系统也崩溃了,造成服务雪崩。这个时候hystrix可以实现快速失败。
如果hystrix在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作而导致系统资源被耗尽。这时hystrix进行fallback操作来服务降级。
Fallback相当于是降级操作。对于查询操作,我们可以实现一个fallback方法,当请求后端服务出现异常的时候,可以使用fallback方法返回的值。fallback方法的返回值一般是默认的值或者是从缓存中得到的值,通知后面的请求服务暂时不可用了。
下面是一个实例:
(1)在e-book-consumer模块下新建子模块为e-book-consumer-hystrix,在新的子模块下新建maven项目为e-book-consumer-hystrix-ribbon-fallback。
(2)拷贝eureka-consumer项目的文件和代码到该项目。
(3)修改pom文件,加入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
(4)修改配置文件的端口和应用名
(5)改造ProductService.java。
package com.twf.e.book.consumer.hystrix.ribbon.fallback.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import com.twf.e.book.consumer.hystrix.ribbon.fallback.domain.Product;
@Service
public class ProductService {
@Autowired
private LoadBalancerClient loadBalancerClient; // ribbon的负载均衡客户端
// @HystrixCommand这个注解指定了fallbackMethod为fallback。
@HystrixCommand(fallbackMethod="fallback",commandProperties={
@HystrixProperty(name=HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,value="15")
})
public List<Product> listProduct() {
ServiceInstance si = loadBalancerClient.choose("e-book-product");
StringBuffer sb = new StringBuffer("");
sb.append("http://");
sb.append(si.getHost());
sb.append(":");
sb.append(si.getPort());
sb.append("/product/list");
System.out.println(sb.toString());
RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference<List<Product>> typeRef = new ParameterizedTypeReference<List<Product>>(){};
ResponseEntity<List<Product>> resp = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, typeRef);
List<Product> plist = resp.getBody();
return plist;
}
// 当调用远程服务出现异常的时候,会调用这个方法
public List<Product> fallback() {
List<Product> list = new ArrayList<Product>();
list.add(new Product(-1,"fallback"));
return list;
}
}
(6)启动注册中心,启动e-book-product-core和这个项目。
(7)访问http://localhost:8100/list,得到如下结果:
若关闭e-book-product-core,再访问http://localhost:8100/list,则得到如下结果:
(8)源码点<