Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等。我们要构建稳定、可靠的分布式系统,就必须要有这样一套容错方法。需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码一零三八七七四六二六
举例子:
1.比如我们现在有3个业务调用分别是查询订单、查询商品、查询用户,且这三个业务请求都是依赖第三方服务-订单服务、商品服务、用户服务。三个服务均是通过RPC调用。当查询订单服务,假如线程阻塞了,这个时候后续有大量的查询订单请求过来,那么容器中的线程数量则会持续增加直致CPU资源耗尽到100%,整个服务对外不可用,集群环境下就是雪崩。
术语介绍:
1.1. Command
命令用于包裹对服务依赖或者外部系统的调用。
1.2. Circuit Breaker
类似于现实世界的断路器,起保护系统的作用。能够在一段时间内停止调用某个或者某些服务。
1.3. Fallback
Fallback的字面意思是回退、退路的意思。命令执行出错时,系统可以使用fallback,从而实现优雅降级。
1.4. Collapser
将若干命令合并成单一命令,可以减少调用次数。
pom.xml的依赖
<!-- 中央库:引入hystrix等-->
<repository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://search.maven.org</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<!-- hystrix -->
<hystrix.version>1.5.12</hystrix.version>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>${hystrix.version}</version>
</dependency>
简单例子1:
package com.book.web.test.hystrix;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
/**
* 入门
* @author liweihan
*
*/
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
protected CommandHelloWorld(String name) {
//最少配置:指定命令组名
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() throws Exception {
//a real example would do work like a network call here
//依赖逻辑封装在run()方法中
return "Hello " + name + "! thread: " + Thread.currentThread().getName();
}
public static void main(String[] args) throws Exception{
/**
* 每个Command对象只能调用一次,不可以重复调用
* 重复调用对应的异常信息:This instance can only be executed once.
* Please instantiate a new instance
*/
CommandHelloWorld commandHelloWorld = new CommandHelloWorld("Synchronous-hystrix");
//使用execute()同步调用代码,效果等同于:commandHelloWorld.queue().get();
String s = commandHelloWorld.execute();
System.out.println(" 同步 ====== " + s);
//异步调用,可以自由控制获取结果的时机
commandHelloWorld = new CommandHelloWorld("Asynchronous-hystrix");
Future<String> future = commandHelloWorld.queue();
//get()操作不能超过command定义的超时时间,默认为1秒
s = future.get(100, TimeUnit.MILLISECONDS);
System.out.println(" 异步 ====== " + s);
System.out.println(" 主函数 ===== " + Thread.currentThread().getName());
/**
* 注意:
* 异步调用使用 command.queue()get(timeout, TimeUnit.MILLISECONDS);
* 同步调用使用command.execute() 等同于 command.queue().get();
*/
}
}
简单例子2:
package com.book.web.test.hystrix;
import java.util.concurrent.TimeUnit;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
/**
* 测试4-熔断测试
* @author liweihan
*
*/
public class CommandHelloWorld5 extends HystrixCommand<String>{
private Integer id;
public CommandHelloWorld5(Integer id) {
super(setter());
this.id = id;
}
private static Setter setter() {
return ApiSetter.setter("getNum");
}
@Override
protected String run() throws Exception {
if (id % 2 == 0 && id <= 10) { //让小于等于10的偶数返回
return "running run():" + id;
} else { //让奇数或大于10的数进入fallback
TimeUnit.MILLISECONDS.sleep(200);
return " XXX ";
}
}
@Override
protected String getFallback() {
return " ====== CircuitBreaker fallback" + id + " ,是否进入熔断:" + super.isCircuitBreakerOpen();
}
public static void main(String[] args) throws Exception {
for(int i = 0; i < 30; i++) {
System.out.println(new CommandHelloWorld5(i).execute());
/*Future<String> future = new CommandHelloWorld5(i).queue();
System.out.println(future.get());*/
}
}
private static class ApiSetter {
public static Setter setter(String commandKeyName,String threadPoolKeyName) {
return setter("ApiGroup",commandKeyName,threadPoolKeyName);
}
public static Setter setter(String commandKeyName) {
return setter(commandKeyName,"Api-Pool");
}
/**
* @author liweihan
* @time 2017/12/20 16:57
* @description 相关参数设置
* @param groupKeyName 服务分组名
* @param commandKeyName 服务标识名称
* @param threadPoolKeyName 线程池名称
* @return
*/
public static Setter setter(String groupKeyName,String commandKeyName,String threadPoolKeyName) {
//服务分组
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(groupKeyName);
//服务标识
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandKeyName);
//线程池名称
HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(threadPoolKeyName);
//线程配置
HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()
//设置核心线程池的大小,默认为10
.withCoreSize(25)
//设置存活时间,单位分钟。如果coreSize小于maximumSize,那么该属性控制一个线程从实用完成到被释放的时间。默认为1
.withKeepAliveTimeMinutes(5)
//设置BlockingQueue最大的队列值,默认值为-1
.withMaxQueueSize(Integer.MAX_VALUE)
//设置队列拒绝的阈值——一个为设置的拒绝访问的最大队列值,即使maxQueueSize还没有达到。
//当将一个线程放入队列等待执行时,HystrixCommand使用该属性
//注意:如果maxQueueSize设置为-1,该属性不可用 ,默认为5
.withQueueSizeRejectionThreshold(10000);
//命令属性的配置
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
//设置HystrixCommand.run()的执行是否有超时限制。默认是true
.withExecutionTimeoutEnabled(true)
//使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作,默认是:true
//即:设置HystrixCommand.run()的执行是否在超时发生时被中断。
.withExecutionIsolationThreadInterruptOnTimeout(true)
//设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,并执行回退逻辑。默认是1000ms
//注意:超时会作用在HystrixCommand.queue(),即使调用者没有调用get()去获得Future对象。
.withExecutionTimeoutInMilliseconds(100)
//使用线程隔离时,调用超时时间,默认:1秒 ,该方法已经不建议使用!
// .withExecutionIsolationThreadTimeoutInMilliseconds(3000)
//失败率达到20%熔断器启动,默认值是50
.withCircuitBreakerErrorThresholdPercentage(20)
// 置为true时,所有请求都将被拒绝,直接到fallback
//.withCircuitBreakerForceOpen(true)
//10秒内请求超过5个的话才会启动熔断器,
//熔断器在设置在一个滚动窗口中,打开断路器的最少请求数。
//默认20。也就是10秒钟内至少请求20次,熔断器才发挥起作用 ,
//比如:如果值是20,在一个窗口内(比如10s),收到19个请求,即使这19个请求都失败了,熔断器也不会打开
//.withCircuitBreakerRequestVolumeThreshold(5)
//是否启用熔断器,默认true. 启动
.withCircuitBreakerEnabled(true)
//设置HystrixCommand.getCacheKey()是否启用,
//由HystrixRequestCache通过请求缓存提供去重复数据功能[默认为true]
.withRequestCacheEnabled(false)
;
//返回
return HystrixCommand.Setter
.withGroupKey(groupKey)
.andCommandKey(commandKey)
.andThreadPoolKey(threadPoolKey)
.andThreadPoolPropertiesDefaults(threadPoolProperties)
.andCommandPropertiesDefaults(commandProperties);
}
/**
* ☆参数说明:
1.HystrixCommandGroupKey:服务分组,以上pydyn分组就包括多个服务,必填选项
2.HystrixCommandKey:服务的名称,唯一标识,如果不配置,则默认是类名
3.HystrixThreadPoolKey:线程池的名称,相同线程池名称的线程池是同一个,如果不配置,默认为分组名
4.HystrixThreadPoolProperties:线程池的配置,
coreSize配置核心线程池的大小,
maxQueueSize线程池队列的最大大小,
queueSizeRejectionThreshold,限制当前队列的大小,
实际队列大小由这个参数决定,即到达队列里面条数到达10000,则都会被拒绝。
5.HystrixCommandProperties:配置命令的一些参数,
如executionIsolationStrategy,配置执行隔离策略,默认是使用线程隔离,THREAD即为线程池隔离,
ExecutionIsolationThreadInterruptOnTimeout 使用线程隔离时,是否对命令执行超时的线程调用中断操作.默认:true
和ExecutionTimeoutInMilliseconds配置了启用超时和最大执行时间,这里为3s,
circuitBreakerErrorThresholdPercentage失败率配置,默认为50%,
这里配置的为25%,即失败率到达25%触发熔断
*/
}
}
java B2B2C Springcloud电子商务平台源码