在上一篇文章中已经说明了服务雪崩是什么,然后还列出了服务雪崩的几种解决方法,包括:降级服务、请求缓存、请求合并、服务熔断这4种方法。
上一篇服务雪崩
然后这一篇列出其他的几种方法。
线程池隔离
不使用线程池隔离会互相影响,使用线程池隔离互不影响。
pom中加入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>RELEASE</version>
</dependency>
配置文件中不需要添加什么。
目录结构:
ProductController代码:
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping(value="list",method=RequestMethod.GET)
public List<Product> listProduct(){
List<Product> list= this.productService.listProduct();
return list;
}
}
ProductService代码:
@Service
public class ProductService {
@Autowired
private LoadBalancerClient loadBalancerClient; //ribbon 负载均衡客户端
@HystrixCommand(groupKey="e-book-product", commandKey = "listProduct",
threadPoolKey="e-book-product",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),//线程池大小
@HystrixProperty(name = "maxQueueSize", value = "100"),//最大队列长度
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),//线程存活时间
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")//拒绝请求
},
fallbackMethod = "fallback")
public List<Product> listProduct(){
//获取eurekaone-provider客户端
ServiceInstance si=loadBalancerClient.choose("e-book-product");
StringBuffer sb = new StringBuffer("");
sb.append("http://");
//获取ip地址
sb.append(si.getHost());
sb.append(":");
//获取端口号
sb.append(si.getPort());
sb.append("/product/list");
System.out.println(sb.toString());
RestTemplate rt = new RestTemplate();
//对象为Product集合
ParameterizedTypeReference<List<Product>> typeRef =new ParameterizedTypeReference<List<Product>>(){};
//参数是浏览器地址,请求方法,和转化为的对象
ResponseEntity<List<Product>> resp= rt.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;
}
}
测试结果:
注解解释:
groupKey=“e-book-product”, commandKey = “listProduct”,threadPoolKey=“e-book-product”,每一个线程池对应一个product,commandKey 是接口名,
threadPoolKey是product名称。
信号量隔离
当请求量过大的时候就会进入fallback中。
pom文件中加入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>RELEASE</version>
</dependency>
配置文件中不需要加入什么。
ProductController代码:
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping(value="list",method=RequestMethod.GET)
public List<Product> listProduct(){
List<Product> list= this.productService.listProduct();
return list;
}
}
ProductService代码:
@Service
public class ProductService {
@Autowired
private LoadBalancerClient loadBalancerClient; //ribbon 负载均衡客户端
@HystrixCommand(fallbackMethod = "fallback",
commandProperties = { @HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value="SEMAPHORE"),// 信号量 隔离
@HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="100")//信号量最大并发度
})
public List<Product> listProduct(){
//获取eurekaone-provider客户端
ServiceInstance si=loadBalancerClient.choose("e-book-product");
StringBuffer sb = new StringBuffer("");
sb.append("http://");
//获取ip地址
sb.append(si.getHost());
sb.append(":");
//获取端口号
sb.append(si.getPort());
sb.append("/product/list");
System.out.println(sb.toString());
RestTemplate rt = new RestTemplate();
//对象为Product集合
ParameterizedTypeReference<List<Product>> typeRef =new ParameterizedTypeReference<List<Product>>(){};
//参数是浏览器地址,请求方法,和转化为的对象
ResponseEntity<List<Product>> resp= rt.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;
}
}
与线程池隔离只是改变了一下注解。注解注意的地方是最大信号量和value的值。
测试结果:
线程池隔离和信号量隔离区别,使用场景
Feign服务降级
pom中加入:
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>e-book-product-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
配置文件加入:
#Feign默认是不开启Hystrix
feign.hystrix.enabled=true
目录结构:
ProductController代码:
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping(value="list",method=RequestMethod.GET)
public List<Product> listProduct(){
List<Product> list= this.productService.listProduct();
return list;
}
}
ProductService代码:
@FeignClient(name="e-book-product",fallback=ProductServiceFallback.class)
public interface ProductService {
//无参
@RequestMapping(value="product/list",method=RequestMethod.GET)
public List<Product> listProduct();
}
ProductServiceFallback代码:
@Component
public class ProductServiceFallback implements ProductService{
@Override
public List<Product> listProduct() {
List<Product> list = new ArrayList<Product>();
list.add(new Product(-1,"fallback"));
return list;
}
}
测试结果:
当consumer和product都启动的时候:
当关闭product的时候:
就会进入fallback方法里面。
Feign服务降级后的异常记录
上面的例子是Feign服务降级,然后我们可以把服务降级的异常记录下来。
这个的pom文件和配置文件与上面是一样的。
目录结构:
ProductController代码
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping(value="list",method=RequestMethod.GET)
public List<Product> listProduct(){
List<Product> list= this.productService.listProduct();
return list;
}
}
ProductService代码:
@FeignClient(name="e-book-product",fallbackFactory=ProductServiceFallbackFactory.class)
public interface ProductService {
//无参
@RequestMapping(value="product/list",method=RequestMethod.GET)
public List<Product> listProduct();
}
ProductServiceFallbackFactory代码:
@Component
public class ProductServiceFallbackFactory implements FallbackFactory<ProductService>{
private Logger logger = LoggerFactory.getLogger(ProductServiceFallbackFactory.class);
@Override
public ProductService create(final Throwable arg0) {
return new ProductService() {
@Override
public List<Product> listProduct() {
logger.warn("fallback exception:",arg0);
List<Product> list = new ArrayList<Product>();
list.add(new Product(-1,"fallback"));
return list;
}
};
}
}
这里主要继承的接口变为了FallbackFactory
然后加入了private Logger logger = LoggerFactory.getLogger(ProductServiceFallbackFactory.class);
和logger.warn(“fallback exception:”,arg0);
启动consumer和product测试:
当关闭product时:
就会打印出异常日志。