Java基础之《微服务(7)—微服务雪崩解决方案》

一、解决方案一:服务降级

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时,将忽略错误
​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值