服务降级
服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚至大分客户能得到正确的响应。也就是当前的请求处理不了或者出错了,给一个默认的返回。例如:双11降级产品评价等非核心功能,保证支持和订单的核心任务进行。
服务熔断
就是防止服务雪崩现象出现,是服务降级的一种特殊情况。
一、Hystrix的服务使用前的问题
1、ProductController 中方法异常和超时
在商品服务 ProductController 中的方法中增加异常和超时,ProductController 中方法修改如下:
package com.hwadee.springcloud.controller;
import com.hwadee.springcloud.entity.Product;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
@RequestMapping("/product")
public class ProductController {
//方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
@Value("${server.port}")
private String port;
@Value("${spring.cloud.client.ip-address}")
private String ip;
@RequestMapping("/buy/{id}")
public Product findById(@PathVariable Long id) {
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port+" "+"查询商品订单,订单号:"+id);
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
//测试超时熔断
try {
Thread.sleep(5000);
//测试并发熔断
//Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return product;
}
@RequestMapping(value = "/delete/{id}")
public Product deleteOrderById(@PathVariable Long id){
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port+" "+"从购物车删除订单,订单号:"+id);
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
//测试异常熔断
System.out.println(10/0);
return product;
}
}
2、访问查看效果
访问http://localhost:9000/order/buy/1
访问http://localhost:9000/order/delete/1
订单服务中OrderController 中 调用商品服务 ProductController 中方法时,ProductController 中方法出现异常和超时,访问浏览器的异常结果和订单服务中的内部异常如下:
3、问题分析
在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,线程资源无法释放,最终导致自身服务的瘫痪,进一步甚至出现故障的蔓延最终导致整个系统的瘫痪。如果这样的架构存在如此严重的隐患,那么相较传统架构就更加的不稳定,如下图。
二、 商品服务 Hystrix的 局部降级
1、降级配置
注解 @HistrixCommand
在商品服务 ProductController 中的 findById( )和deleteOrderById( ) 方法上增加降级配置的注解 @HistrixCommand
—旦调用服务方法失败并抛出了超时或错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法。
在@HistrixCommand 指定超时或异常要回调的方法,同时可以指定配置参数,例如使用@HistrixCommand 中的属性commandProperties 指定默认超时时间,如:
fallbackMethod:指定回调方法是findByIdTimeout
commandProperties: 指定@HystrixProperty 的默认值是默认超时时间是3s@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
2、回调(兜底降级)方法
在商品服务ProductController 中增加回调方法findByIdTimeout( ) 和deleteOrderByIdException( ),当访问ProductController 中的 findById( )和deleteOrderById( ) 发生超时 或 异常时,会调用回调方法。
3、具体代码
降级配置 和回调(兜底降级)方法的具体代码如下:
import com.hwadee.springcloud.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
@RequestMapping("/product")
public class ProductController {
//方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
@Value("${server.port}")
private String port;
@Value("${spring.cloud.client.ip-address}")
private String ip;
@RequestMapping("/buy/{id}")
@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public Product findById(@PathVariable Long id) {
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "查询商品订单,订单号:" + id);
product.setPrice(new BigDecimal(50000.0));
System.out.println(product);
//测试超时熔断
try {
Thread.sleep(5000);
//测试并发熔断
//Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return product;
}
@RequestMapping(value = "/delete/{id}")
@HystrixCommand(fallbackMethod = "deleteOrderByIdException")
public Product deleteOrderById(@PathVariable Long id) {
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "从购物车删除订单,订单号:" + id);
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
//测试异常熔断
System.out.println(10 / 0);
return product;
}
public Product findByIdTimeout(Long id) {
Product product = new Product();
product.setId(id);
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "访问 超时 进行降级服务");
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
return product;
}
public Product deleteOrderByIdException(Long id) {
Product product = new Product();
product.setId(id);
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "访问 异常 进行降级服务");
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
return product;
}
}
4、主启动类激活Hstrix
在商品服务的主启动类 ProductServerApplication 中使用注解@EnableCircuitBreaker 进行激活Hystrix,代码如下
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient// 启动 eureka 客户端
@EnableCircuitBreaker // 主启动类激活 Hystrix
public class ProductServerApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServerApplication.class, args);
}
}
5、进行测试
将商品服务中ProductController 和 ProductServerApplication复制到 其他所有 商品服务中,进行更新代码。
分别访问:http://localhost:9001/product/buy/1 和 http://localhost:9001/product/delete/1 查看超时和异常服务降级。看浏览器和内部结果。
三、 订单服务 Hystrix的 局部降级
1、降级配置
注解 @HistrixCommand
在订单服务 OrderController 中的方法上增加降级配置的注解 @HistrixCommand
2、回调(兜底降级)方法
在订单服务 OrderController 定义 回调方法 buyTimeout( Long id) 、deleteOrderException( Long id),并设置超时服务,超时服务要比将商品服务ProductController 中的 findById( ) 超时时间短。例如:ProductController 中的 findById( ) 超时时间是 3s ,则订单服务 OrderController 定义 回调方法 buyTimeout( ) 设定的超时时间应是 <3s 。
3、具体代码
降级配置 和回调(兜底降级)方法的具体代码如下:
import com.hwadee.springcloud.entity.Product;
import com.hwadee.springcloud.service.IOrderFeignService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
IOrderFeignService orderFeignService;
@RequestMapping("/buy/{id}")
@HystrixCommand(fallbackMethod = "buyTimeout", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public Product buy(@PathVariable Long id) {
System.out.println("进入OrderController的buy方法, orderFeignService 准备调用远端接口 findById");
Product product = orderFeignService.findOrderById(id);
return product;
}
@RequestMapping(value = "/delete/{id}")
@HystrixCommand(fallbackMethod = "deleteOrderException")
public Product deleteOrderById(@PathVariable Long id) {
System.out.println("进入OrderController的deleteOrderById方法, orderFeignService 准备调用远端接口deleteOrderById");
Product product = orderFeignService.deleteOrderById(id);
int i =10/0;
return product;
}
public Product buyTimeout( Long id) {
Product product = new Product();
product.setId(id);
product.setName("当前订单服务访问/order/buy/1 超时:"+id);
return product;
}
public Product deleteOrderException( Long id) {
Product product = orderFeignService.deleteOrderById(id);
product.setName("当前订单服务访问/order/delete/1 10/0异常:"+id);
return product;
}
}
4、将商品服务中的超时时间为正常
将商品服务ProductController 中的 findById( ) 超时时间为正常,即程序超时时间是2s,熔断等待时间是3s,并且要比 订单服务 OrderController 定义 回调方法 buyTimeout( ) 中的熔断时间大,代码如下:
@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
// 正常超时时间是 3s 比OrderController 中定义的超时时间长。
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public Product findById(@PathVariable Long id) { 。。。。。
// 超时时间 2s
Thread.sleep(2000); 。。。。。
return product;
}
完整代码如下:
import com.hwadee.springcloud.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
@RequestMapping("/product")
public class ProductController {
//方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
@Value("${server.port}")
private String port;
@Value("${spring.cloud.client.ip-address}")
private String ip;
@RequestMapping("/buy/{id}")
@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public Product findById(@PathVariable Long id) {
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "查询商品订单,订单号:" + id);
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
//测试超时熔断
try {
Thread.sleep(5000);
//测试并发熔断
//Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return product;
}
@RequestMapping(value = "/delete/{id}")
@HystrixCommand(fallbackMethod = "deleteOrderByIdException")
public Product deleteOrderById(@PathVariable Long id) {
Product product = new Product();
product.setId(id);
// 后面需要测试负载均衡,所以返回 ip 地址及端口号
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "从购物车删除订单,订单号:" + id);
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
//测试异常熔断
System.out.println(10 / 0);
return product;
}
public Product findByIdTimeout(Long id) {
Product product = new Product();
product.setId(id);
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "访问 超时 进行降级服务");
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
return product;
}
public Product deleteOrderByIdException(Long id) {
Product product = new Product();
product.setId(id);
product.setName("当前访问商品服务地址:" + ip + ":" + port + " " + "访问 异常 进行降级服务");
product.setPrice(new BigDecimal(10000.0));
System.out.println(product);
return product;
}
}
5、主启动类激活Hstrix
在订单服务的主启动类 OrderServerApplication 中使用注解@EnableCircuitBreaker 或 注解@EnableHystrix进行激活Hystrix,注意:@EnableHystrix包括了注解@EnableCircuitBreaker ,代码如下
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient// 启动 eureka 客户端
@EnableFeignClients // 启动 feign
@EnableCircuitBreaker // 或 @EnableHystrix 启动 Hystrix
public class OrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServerApplication.class, args);
}
}
6、进行测试
分别访问:http://localhost:9000/order/buy/1 和 http://localhost:9000/order/delete/1 查看超时和异常服务降级。
到此这篇关于SpringCloud hystrix断路器与服务降级全面介绍的文章就介绍到这了,更多相关SpringCloud hystrix断路器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!