概述
hystrix是netflix公司开发的一套具有熔断功能的服务隔离开源框架。
在一般的互联网公司,各种基础数据都是由专门的接口提供,这也是soa思想的一种体现。如果一个应用调用的接口多了,变会有雪崩效应。什么是雪崩效应?比如说应用调用了5个外部接口,每个接口的调用成功率是99.9%, 那么从理论上来说,应用的成功率就是99.9%的五次方。如果调用的服务多了,这种放大效应会更加明显。 hystrix就是为了应对这种情况的框架。他的原理就是将各种服务分割开,外部接口的调用不会相互影响。
hystrix具有如下特点:
1. 服务分割。
2.自动熔断。
maven引入
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>${hystrix.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
<version>${hystrix-metrics-event-stream.version}</version>
</dependency>
写一个command
package com.liang.hystrix.helloworld;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloServiceHystrixCommand extends HystrixCommand<String> {
private final String _name;
private final Service service;
private int i;
private Logger logger = LoggerFactory.getLogger(HelloServiceHystrixCommand.class);
public static final int MIN_SIZE = 5;
public static final int MAX_SIZE = 10;
public HelloServiceHystrixCommand(String name) {
super(setter());
_name = new String(name);//unmutable
service = new HelloService();
}
public HelloServiceHystrixCommand(String name, int i) {
super(setter());
_name = new String(name);//unmutable
service = new HelloService();
this.i = i;
}
@Override
protected String getFallback() {
logger.info("run failed.execute callback");
return null;
}
@Override
protected String run() {
if (sleep(i)) {
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
logger.info("execute command" + i);
return service.getHelloName(_name);
}
private static HystrixCommand.Setter setter() {
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("service"))
.andCommandKey(HystrixCommandKey.Factory.asKey("hello"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
.withExecutionIsolationThreadInterruptOnTimeout(true)
.withExecutionIsolationThreadTimeoutInMilliseconds(1000)
.withCircuitBreakerEnabled(true)
.withRequestLogEnabled(true)
.withMetricsRollingPercentileWindowBuckets(5)
.withMetricsRollingStatisticalWindowBuckets(5)
.withCircuitBreakerRequestVolumeThreshold(3)
.withCircuitBreakerErrorThresholdPercentage(30)
.withCircuitBreakerSleepWindowInMilliseconds(5000))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("thread-pool"));
}
public static boolean sleep(int i) {
return i > MIN_SIZE && i < MAX_SIZE;
}
其中Service, HelloService模拟的是具体的业务代码。代码如下:
package com.liang.hystrix.helloworld;
public interface Service {
public String getHelloName(String name);
}
package com.liang.hystrix.helloworld;
public class HelloService implements Service {
public String getHelloName(String name) {
return "Hello " + name;
}
}
单元测试
package hystrix;
import static org.junit.Assert.assertEquals;
import com.liang.hystrix.helloworld.HelloServiceHystrixCommand;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloServiceHystrixCommandTest {
private Logger logger = LoggerFactory.getLogger(HelloServiceHystrixCommandTest.class);
@Test
public void testExecute() {
HelloServiceHystrixCommand c = new HelloServiceHystrixCommand("World");
assertEquals("Hello World", c.execute());
try {
String result = new HelloServiceHystrixCommand("World").queue().get(30000, TimeUnit.SECONDS);
assertEquals("Hello World", result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
@Test
public void testRun() throws ExecutionException, TimeoutException {
HelloServiceHystrixCommand c = null;
AtomicInteger j = new AtomicInteger(0);
for (int i = 0; i < 100; i++) {
try {
c = new HelloServiceHystrixCommand("" + i, j.getAndIncrement());
String result = c.queue().get(3, TimeUnit.MILLISECONDS);
logger.info(c.getMetrics().getHealthCounts().getErrorPercentage() + " "
+ c.getMetrics().getHealthCounts().getErrorCount() + " "
+ c.getMetrics().getHealthCounts().getTotalRequests());
logger.info("CircuitBreaker is " + (c.isCircuitBreakerOpen() ? "open" : "closed"));
if (HelloServiceHystrixCommand.sleep(i) || c.isCircuitBreakerOpen()) {
assertEquals(null , result);
} else {
assertEquals("Hello " + i , result);
}
if (c.isCircuitBreakerOpen()) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}