一、解决方案一:服务降级
1、复制一份provider2为provider3,并引入项目
2、pom文件引入hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
</dependency>
3、启动类增加注解@EnableCircuitBreaker
@EnableCircuitBreaker //开启服务降级-断路器
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan("com.example.mycloud")
@EnableFeignClients("com.example.mycloud")
public class ServiceProvider3Application {
public static void main(String[] args) {
SpringApplication.run(ServiceProvider3Application.class, args);
}
}
4、resource添加测试方法testHystrix1
package com.example.mycloud.resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.mycloud.service.TestHystrixService;
@RestController
public class TestResource {
@Autowired
private Registration registration; // 服务注册
@Autowired
private TestHystrixService testHystrixService;
@RequestMapping("/InstanceInfo")
public String Info() {
String serviceId = registration.getServiceId();
System.out.println("服务id为: " + serviceId);
return registration.getInstanceId();
}
@RequestMapping("/testHystrix1")
public String testHystrix1() {
return testHystrixService.testHystrix1();
}
}
5、添加service类TestHystrixService.java
package com.example.mycloud.service;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
@Service
public class TestHystrixService {
@HystrixCommand(fallbackMethod = "fallback", //降级方法
//配置参数
commandProperties = {
//默认10秒内,如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用
@HystrixProperty(name=HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="15")
})
public String testHystrix1() {
throw new RuntimeException("服务异常");
//return "正常请求......";
}
/**
* 返回托底数据
* @return
*/
public String fallback() {
return "fallback method......";
}
}
没有抛异常正常返回,抛异常会返回fallback方法的内容。感觉做了一个AOP然后捕捉异常,返回指定内容的功能。
6、降级参数
(1)
参数:fallback.enabled
作用:fallback是否可用
默认值:true
备注:当执行失败或者请求被拒绝,是否尝试调用hystrixCommond.getFallback()
(2)
参数:fallback.isolation.semaphore.maxConcurrentRequests
作用:fallback最大并发数
默认值:10
备注:如果并发数达到该设置值,请求会被拒绝和抛出异常,并且fallback不会被调用
(3)以下四种请求将触发getFallback调用
方法抛出非HystrixBadRequestException异常
方法调用超时
熔断器开启拦截调用,熔断会触发降级
线程池/队列/信号量是否跑满
二、解决方案二:服务请求缓存
1、Hystrix自带缓存
只支持本地缓存,不支持集群
不支持第三方缓存容器:redis等
2、provider3模块,pom文件添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3、配置文件添加redis信息
spring:
redis:
host: 127.0.0.1
port: 6379
password:
#数据库号
database: 1
timeout: 2s
4、启动类添加注解@EnableCaching
@EnableCaching //加入springcache
@EnableCircuitBreaker //开启服务降级-断路器
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan("com.example.mycloud")
@EnableFeignClients("com.example.mycloud")
public class ServiceProvider3Application {
public static void main(String[] args) {
SpringApplication.run(ServiceProvider3Application.class, args);
}
}
5、service类添加注解@CacheConfig,添加key的前缀
@CacheConfig(cacheNames = {"com.example.mycloud"})
6、添加测试方法
package com.example.mycloud.service;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
@CacheConfig(cacheNames = {"com.example.mycloud"})
@Service
public class TestHystrixService {
@HystrixCommand(fallbackMethod = "fallback", //降级方法
//配置参数
commandProperties = {
//默认10秒内,如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用
@HystrixProperty(name=HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="15")
})
public String testHystrix1() {
throw new RuntimeException("服务异常");
//return "正常请求......";
}
/**
* 返回托底数据
* @return
*/
public String fallback() {
return "fallback method......";
}
@Cacheable(key = "'get' + #id")
public String get(Integer id) {
System.out.println("==========get==========");
return "测试缓存..." + id;
}
@CacheEvict(key = "'get' + #id")
public void del(Integer id) {
System.out.println("==========del==========");
}
}
resource添加:
@RequestMapping("/get")
public String get(Integer id) {
return testHystrixService.get(id);
}
@RequestMapping("/del")
public void del(Integer id) {
testHystrixService.del(id);
}
7、测试
http://127.0.0.1:8016/get?id=20
http://127.0.0.1:8016/del?id=20
三、解决方案三:请求合并
1、原理
合并
2、service类添加方法getIdInfo、batchIdInfo
package com.example.mycloud.service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
@CacheConfig(cacheNames = {"com.example.mycloud"})
@Service
public class TestHystrixService {
@HystrixCommand(fallbackMethod = "fallback", //降级方法
//配置参数
commandProperties = {
//默认10秒内,如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用
@HystrixProperty(name=HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="15")
})
public String testHystrix1() {
throw new RuntimeException("服务异常");
//return "正常请求......";
}
/**
* 返回托底数据
* @return
*/
public String fallback() {
return "fallback method......";
}
@Cacheable(key = "'get' + #id")
public String get(Integer id) {
System.out.println("==========get==========");
return "测试缓存..." + id;
}
@CacheEvict(key = "'get' + #id")
public void del(Integer id) {
System.out.println("==========del==========");
}
@HystrixCollapser(batchMethod = "batchIdInfo",
scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
//请求时间间隔在50ms之内的请求会被合并为一个请求
@HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
//设置触发批处理执行之前,在批处理中允许的最大请求数
@HystrixProperty(name = "maxRequestsInBatch", value = "200")
}
)
public Future<String> getIdInfo(Integer id) {
//没有打印这里,因为请求合并了
System.out.println("==========" + id + "==========");
return null;
}
@HystrixCommand
public List<String> batchIdInfo(List<Integer> id) {
List<String> list = new ArrayList<>();
for(Integer i : id) {
list.add("id: " + i);
}
return list;
}
}
resource添加:
@RequestMapping("/testHystrix3")
public void testHystrix3() throws InterruptedException, ExecutionException {
Future<String> s1 = testHystrixService.getIdInfo(1);
Future<String> s2 = testHystrixService.getIdInfo(2);
Future<String> s3 = testHystrixService.getIdInfo(3);
System.out.println(s1.get().toString());
System.out.println(s2.get().toString());
System.out.println(s3.get().toString());
}
3、测试
http://127.0.0.1:8016/testHystrix3
4、查看结果
日志打印的是:
id: 1
id: 2
id: 3
没有打印:
==========id==========
说明进到合并的方法里面去了。
5、合并配置参数
(1)
参数:@HystrixCollapser
作用:
默认值:
备注:被@HystrixCollapser标注的方法,返回类型必须为Future,使用异步方法,否则无法进行请求合并。
(2)
参数:batchMethod
作用:合并请求的方法
默认值:
备注:方法只能接受一个参数,如果你需要传递多个参数,那么请将它封装成一个类参数。
(3)
参数:scope
作用:请求方法
默认值:REQUEST
备注:请求方式分为REQUEST,GLOBAL。
REQUEST范围只对一个request请求内的多次服务请求进行合并。
GLOBAL是单个应用中的所有线程的请求中的多次服务请求进行合并。
(4)
参数:timerDelayInMilliseconds
作用:请求时间间隔在10ms之内的请求会被合并为一个请求
默认值:10ms
备注:建议尽量设置的小一点,如果并发量不大的话,其实也没有必要用HystrixCollapser来处理。
(5)
参数:maxRequestsInBatch
作用:设置触发批处理执行之前,在批处理中允许的最大请求数。
默认值:Integer.MAX_VALUE
备注:
四、解决方案四:服务熔断
1、什么是熔断机制
熔断机制相当于电路的跳闸功能。
例如:我们可以配置熔断策略为,当请求错误比例在10s内>50%时,该服务将进入熔断状态,后续请求都会进入fallback。
2、示意图
3、service类添加方法
package com.example.mycloud.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Future;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
@CacheConfig(cacheNames = {"com.example.mycloud"})
@Service
public class TestHystrixService {
/********************
* 服务降级案例
********************/
@HystrixCommand(fallbackMethod = "fallback", //降级方法
//配置参数
commandProperties = {
//默认10秒内,如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用
@HystrixProperty(name=HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="15")
})
public String testHystrix1() {
throw new RuntimeException("服务异常");
//return "正常请求......";
}
/**
* 返回托底数据
* @return
*/
public String fallback() {
return "fallback method......";
}
/********************
* 请求缓存案例
********************/
@Cacheable(key = "'get' + #id")
public String get(Integer id) {
System.out.println("==========get==========");
return "测试缓存..." + id;
}
@CacheEvict(key = "'get' + #id")
public void del(Integer id) {
System.out.println("==========del==========");
}
/********************
* 请求合并案例
********************/
@HystrixCollapser(batchMethod = "batchIdInfo",
scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
//请求时间间隔在50ms之内的请求会被合并为一个请求
@HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
//设置触发批处理执行之前,在批处理中允许的最大请求数
@HystrixProperty(name = "maxRequestsInBatch", value = "200")
}
)
public Future<String> getIdInfo(Integer id) {
//没有打印这里,因为请求合并了
System.out.println("==========" + id + "==========");
return null;
}
@HystrixCommand
public List<String> batchIdInfo(List<Integer> id) {
List<String> list = new ArrayList<>();
for(Integer i : id) {
list.add("id: " + i);
}
return list;
}
/********************
* 服务熔断案例
********************/
@HystrixCommand(fallbackMethod = "fallback2",
commandProperties = {
//默认20个;10s内请求数大于20个时就启动熔断器,当请求符合熔断条件时将触发getFallback()
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value = "10"),
//请求错误率大于50%时就熔断,然后for循环发起请求,当请求符合熔断条件时将触发getFallback()
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = "50"),
//默认5秒;熔断多少秒后去尝试请求
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "5000")
}
)
public String testHystrix4() {
Random random = new Random();
int i = random.nextInt();
if (i % 2 == 1) {
throw new RuntimeException("服务异常");
}
return "正常请求......";
}
public String fallback2() {
return "fallback2 method......";
}
}
resource添加:
@RequestMapping("/testHystrix4")
public String testHystrix4() {
return testHystrixService.testHystrix4();
}
4、熔断配置参数
(1)
参数:circuitBreaker.enabled
作用:是否开启熔断
默认值:TRUE
备注:
(2)
参数:circuitBreaker.requestVolumeThreshold
作用:一个统计窗口(10s)内熔断触发的最小个数
默认值:20
备注:10s内请求数大于20个时就启动熔断,当请求符合熔断条件时将触发getFallback()
(3)
参数:circuitBreaker.sleepWindowInMilliseconds
作用:熔断多少秒后去尝试请求
默认值:5000ms
备注:
(4)
参数:circuitBreaker.errorThresholdPercentage
作用:失败率达到多少百分比后熔断
默认值:默认配置下采样周期为10s,失败率为50%
备注:请求错误率大于50%时就熔断,然后for循环发起请求,当请求符合熔断条件时将触发getFallback()
(5)
参数:circuitBreaker.forceOpen
作用:是否强制开启熔断
默认值:FALSE
备注:置位true时,所有请求都将被拒绝,直接到fallback
(6)
参数:circuitBreaker.forceClosed
作用:是否强制关闭熔断
默认值:FALSE
备注:置位true时,将忽略错误