hystrix文档翻译之如何使用
Hello World!
使用HystrixCommand实现“Hello World”。
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() {
// a real example would do work like a network call here
return "Hello " + name + "!";
}
}
使用HystrixObservableCommand实现“Hello World”。
public class CommandHelloWorld extends HystrixObservableCommand<String> {
private final String name;
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected Observable<String> construct() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> observer) {
try {
if (!observer.isUnsubscribed()) {
// a real example would do work like a network call here
observer.onNext("Hello");
observer.onNext(name + "!");
observer.onCompleted();
}
} catch (Exception e) {
observer.onError(e);
}
}
} ).subscribeOn(Schedulers.io());
}
}
同步执行
使用HystrixCommand的execute方法同步执行。
String s = new CommandHelloWorld("World").execute();
HystrixObservableCommand没有execute方法,但如果你确定Observable只会返回一个单一结果,你可以使用.toBlocking().toFuture().get()方法。
异步执行
使用HystrixCommand的queue()方法实现异步:
Future<String> fs = new CommandHelloWorld("World").queue();
通过get方式获得结果
String s = fs.get();
HystrixObservableCommand没有queue方法,但如果你确定Observable只会返回一个单一结果,你可以使用.toBlocking().toFuture()方法。
响应执行
通过下面两个方法可以获取Observable对象。
- observe,返回一个Observable并且立即执行命令,因为observe方法内部使用了一个RepaySubject,所以也会接受到监听以前命令返回的结果。
- toObservable,返回一个Observable但不回立即执行,当监听该对象时才执行。
Observable<String> ho = new CommandHelloWorld("World").observe();
// or Observable<String> co = new CommandHelloWorld("World").toObservable();
ho.subscribe(new Action1<String>() {
@Override
public void call(String s) {
// value emitted here
}
});
使用单元测试执行
@Test
public void testObservable() throws Exception { Observable<String> fWorld = new CommandHelloWorld("World").observe();
Observable<String> fBob = new CommandHelloWorld("Bob").observe(); // blocking
assertEquals("Hello World!", fWorld.toBlockingObservable().single());
assertEquals("Hello Bob!", fBob.toBlockingObservable().single()); // non-blocking
// - this is a verbose anonymous inner-class approach and doesn't do assertions
fWorld.subscribe(new Observer<String>() { @Override
public void onCompleted() {
// nothing needed here
} @Override
public void onError(Throwable e) {
e.printStackTrace();
} @Override
public void onNext(String v) {
System.out.println("onNext: " + v);
} }); // non-blocking
// - also verbose anonymous inner-class
// - ignore errors and onCompleted signal
fBob.subscribe(new Action1<String>() { @Override
public void call(String v) {
System.out.println("onNext: " + v);
} });
}
响应式命令
除了使用上面的方式来获取Observable对象,还可以通过HystrixObservableCommand来创建一个Observable对象。HystrixObservableCommand可以创建一个返回多个值的Observable对象。HystrixObservableCommand使用consruct方法来执行命令而不是run方法。通过一下两种方式来获取Observable对象:
- observe,返回一个Observable并且立即执行命令,因为observe方法内部使用了一个RepaySubject,所以也会接受到监听以前命令返回的结果。
- toObservable,返回一个Observable但不回立即执行,当监听该对象时才执行。
降级
通过添加fallback方法可以让命令执行异常时执行降级措施。你会为大多数的hystrix 命令实现降级方法,除了一下的情况:
- 命令执行写操作
如果hystrix命令是被设计成一个写操作而非读操作(HystrixCommand命令返回void或者HystrixObservableCommand返回一个空的Observable对象)。那么没有什么实现fallback方法。如果写出错了,应该把异常抛出给调用方。
- 执行批量计算
如果hystrix命令使用了缓存、或者批量、或者离线技术,也应该把异常抛给调用方,让调用放过处理而不是降级。
无论你的命令是否有fallback,hystrix状态和熔断器状态都会更新。
在HystrixCommand中实现getFallback方法,当run方法失败、超时、线程池拒绝、信号量拒绝、熔断时将会执行getFallback,并返回结果。
public class CommandHelloFailure extends HystrixCommand<String> { private final String name; public CommandHelloFailure(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
} @Override
protected String run() {
throw new RuntimeException("this command always fails");
} @Override
protected String getFallback() {
return "Hello Failure " + name + "!";
}
}
run方法执行时将会抛出一个异常。但调用方会收到getFallback方法的返回结果。
使用HystrixObservableCommand的resumeWithFallback方法返回一个Observable对象也可以在执行命令失败后被调用返回。因为Observable对象可能在发射了一些数据之后才发生异常,所以可能在执行resumeWithFallback前返回数据。Hystrix内部使用了rxjava的onErrorResumeNext来实现。
异常传播
所有从run抛出的异常,除了HystrixBadRequestException都会执行getFallback方法并且进入熔断计算。你可以把你的异常封装成HystrixBadRequestException抛出,HystrixBadRequestException常常用于抛出参数错误,非系统异常不需要记入metric和执行降级的错误。
执行异常类型
失败类型 | 异常类 | 异常原因 |
FAILURE | HystrixRuntimeException | underlying exception (user-controlled) |
TIMEOUT | HystrixRuntimeException | TimeoutException |
SHORT_CIRCUITED | HystrixRuntimeException | RuntimeException |
THREAD_POOL_REJECTED | HystrixRuntimeException | RejectedExecutionException |
SEMAPHORE_REJECTED | HystrixRuntimeException | RuntimeException |
BAD_REQUEST | HystrixBadRequestException | underlying exception (user-controlled) |
命令名
命令名默认是使用类名
String name = cls.getSimpleName();
可以自定义命令名
public CommandHelloWorld(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")));
this.name = name;
}
使用下面的方式来为每个command缓存Setter。
private static final Setter cachedSetter =
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"));
public CommandHelloWorld(String name) {
super(cachedSetter);
this.name = name;
}
HystrixCommandKey是一个接口,并且提供了一个Factory来构造实现类。
HystrixCommandKey.Factory.asKey("HelloWorld")
组名
Hystrix使用组名来合并命令,用于报表,报警,项目管理。
如果没有指定线程池key,默认使用组名作为线程池key。
HystrixCommandGroupKey是一个接口,并且提供了一个Factory来构造实现类。
HystrixCommandGroupKey.Factory.asKey("ExampleGroup")
线程池key
线程池key唯一代表了一个线程池,用于监控、metrics、命令执行。默认使用HystrixCommandGroupKey。也可以显式指明:
public CommandHelloWorld(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
this.name = name;
}
HystrixThreadPoolKey是一个接口,并且提供了一个Factory来构造实现类。
HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")
当多个命令属于同一个组,但是又要相互直接隔离时,可以显示指定HystrixThreadPoolKey。
缓存
通过实现HystrixCommand或HystrixObservableCommand的getCacheKey方法 ,可以开启请求缓存。
public class CommandUsingRequestCache extends HystrixCommand<Boolean> {
private final int value;
protected CommandUsingRequestCache(int value) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.value = value;
}
@Override
protected Boolean run() {
return value == 0 || value % 2 == 0;
}
@Override
protected String getCacheKey() {
return String.valueOf(value);
}
}
因为请求缓存依赖HystrixRequestContext,所以在执行前需要先进行初始化。
@Test
public void testWithoutCacheHits() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
assertTrue(new CommandUsingRequestCache(2).execute());
assertFalse(new CommandUsingRequestCache(1).execute());
assertTrue(new CommandUsingRequestCache(0).execute());
assertTrue(new CommandUsingRequestCache(58672).execute());
} finally {
context.shutdown();
}
}
通常通过ServletFilter来初始化和关闭HystrixRequestContext。
@Test
public void testWithCacheHits() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);
CommandUsingRequestCache command2b = new CommandUsingRequestCache(2);
assertTrue(command2a.execute());
// this is the first time we've executed this command with
// the value of "2" so it should not be from cache
assertFalse(command2a.isResponseFromCache());
assertTrue(command2b.execute());
// this is the second time we've executed this command with
// the same value so it should return from cache
assertTrue(command2b.isResponseFromCache());
} finally {
context.shutdown();
} // start a new request context
context = HystrixRequestContext.initializeContext();
try {
CommandUsingRequestCache command3b = new CommandUsingRequestCache(2);
assertTrue(command3b.execute());
// this is a new request context so this
// should not come from cache
assertFalse(command3b.isResponseFromCache());
} finally {
context.shutdown();
}
}
请求合并
请求合并可以让多个请求合并成一到HystrixCommand中执行。可以设置合并请求数量和合并等待时间来触发请求合并。有两种作用域:请求级别和全局,通过构造函数指定,默认使用请求级别。
请求级别的合并通过一个HystrixRequestContext实现。全局的合并通过多个HystrixRequestContexts;如果依赖服务不能处理多个HystrixRequestContexts,最好使用请求级别作用域。
使用请求级别合并:
public class CommandCollapserGetValueForKey extends HystrixCollapser<List<String>, String, Integer> {
private final Integer key;
public CommandCollapserGetValueForKey(Integer key) {
this.key = key;
}
@Override
public Integer getRequestArgument() {
return key;
}
@Override
protected HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, Integer>> requests) {
return new BatchCommand(requests);
}
@Override
protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) {
int count = 0;
for (CollapsedRequest<String, Integer> request : requests) {
request.setResponse(batchResponse.get(count++));
}
}
private static final class BatchCommand extends HystrixCommand<List<String>> {
private final Collection<CollapsedRequest<String, Integer>> requests;
private BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GetValueForKey")));
this.requests = requests;
}
@Override
protected List<String> run() {
ArrayList<String> response = new ArrayList<String>();
for (CollapsedRequest<String, Integer> request : requests) {
// artificial response for each argument received in the batch
response.add("ValueForKey: " + request.getArgument());
}
return response;
}
}
}
测试请求合并
@Test
public void testCollapser() throws Exception {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
Future<String> f1 = new CommandCollapserGetValueForKey(1).queue();
Future<String> f2 = new CommandCollapserGetValueForKey(2).queue();
Future<String> f3 = new CommandCollapserGetValueForKey(3).queue();
Future<String> f4 = new CommandCollapserGetValueForKey(4).queue(); assertEquals("ValueForKey: 1", f1.get());
assertEquals("ValueForKey: 2", f2.get());
assertEquals("ValueForKey: 3", f3.get());
assertEquals("ValueForKey: 4", f4.get()); // assert that the batch command 'GetValueForKey' was in fact
// executed and that it executed only once
assertEquals(1, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size());
HystrixCommand<?> command = HystrixRequestLog.getCurrentRequest().getExecutedCommands().toArray(new HystrixCommand<?>[1])[0];
// assert the command is the one we're expecting
assertEquals("GetValueForKey", command.getCommandKey().name());
// confirm that it was a COLLAPSED command execution
assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));
// and that it was successful
assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));
} finally {
context.shutdown();
}
}
请求上下文
如果想要使用请求缓存、请求合并、请求日志的请求级别功能,我们必需管理HystrixRequestContext生命周期。
在请求开始之前执行下面的代码
HystrixRequestContext context = HystrixRequestContext.initializeContext();
在请求结束后执行下面的代码:
context.shutdown();
在java web应用中可以使用ServletFilter来管理HystrixRequestContext
public class HystrixRequestContextServletFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} finally {
context.shutdown();
}
}
}
在web.xml中添加一下配置
<filter>
<display-name>HystrixRequestContextServletFilter</display-name>
<filter-name>HystrixRequestContextServletFilter</filter-name>
<filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HystrixRequestContextServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
公共特性
在下面的章节中,会讲HystrixCommand和HystrixObservableCommand的公共特性。
快速失败
大多数的使用是执行一个命令,并且没有fallback方法,如果碰到异常就会抛出
public class CommandThatFailsFast extends HystrixCommand<String> {
private final boolean throwException;
public CommandThatFailsFast(boolean throwException) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.throwException = throwException;
}
@Override
protected String run() {
if (throwException) {
throw new RuntimeException("failure from CommandThatFailsFast");
} else {
return "success";
}
}
单元测试
@Test
public void testSuccess() {
assertEquals("success", new CommandThatFailsFast(false).execute());
}
@Test
public void testFailure() {
try {
new CommandThatFailsFast(true).execute();
fail("we should have thrown an exception");
} catch (HystrixRuntimeException e) {
assertEquals("failure from CommandThatFailsFast", e.getCause().getMessage());
e.printStackTrace();
}
}
使用HystrixObservableCommand实现需要实现resumeWithFallback方法。
@Override
protected Observable<String> resumeWithFallback() {
if (throwException) {
return Observable.error(new Throwable("failure from CommandThatFailsFast"));
} else {
return Observable.just("success");
}
}
静默失败
静默失败是让fallback返回一个空结果。
public class CommandThatFailsSilently extends HystrixCommand<String> {
private final boolean throwException;
public CommandThatFailsSilently(boolean throwException) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.throwException = throwException;
}
@Override
protected String run() {
if (throwException) {
throw new RuntimeException("failure from CommandThatFailsFast");
} else {
return "success";
}
}
@Override
protected String getFallback() {
return null;
}
}
单元测试
@Test
public void testSuccess() {
assertEquals("success", new CommandThatFailsSilently(false).execute());
}
@Test
public void testFailure() {
try {
assertEquals(null, new CommandThatFailsSilently(true).execute());
} catch (HystrixRuntimeException e) {
fail("we should not get an exception as we fail silently with a fallback");
}
}
另一种实现
@Override
protected List<String> getFallback() {
return Collections.emptyList();
}
使用HystrixObservableCommand实现
@Override
protected Observable<String> resumeWithFallback() {
return Observable.empty();
}
静态fallback
fallfack返回一个固定的静态值,例如如果命令失败返回true。
@Override
protected Boolean getFallback() {
return true;
}
使用HystrixObservableCommand
@Override
protected Observable<Boolean> resumeWithFallback() {
return Observable.just( true );
}
存根fallback
通过咋fallback会返回一个包含请求信息和状态的对象,例如:cookies,请求参数,请求头,失败前service的返回结果。fallback可以通过请求作用域来获取信息,更典型的是在使用命令时通过构造函数设置这些值。
public class CommandWithStubbedFallback extends HystrixCommand<UserAccount> { private final int customerId;
private final String countryCodeFromGeoLookup; /**
* @param customerId
* The customerID to retrieve UserAccount for
* @param countryCodeFromGeoLookup
* The default country code from the HTTP request geo code lookup used for fallback.
*/
protected CommandWithStubbedFallback(int customerId, String countryCodeFromGeoLookup) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.customerId = customerId;
this.countryCodeFromGeoLookup = countryCodeFromGeoLookup;
} @Override
protected UserAccount run() {
// fetch UserAccount from remote service
// return UserAccountClient.getAccount(customerId);
throw new RuntimeException("forcing failure for example");
} @Override
protected UserAccount getFallback() {
/**
* Return stubbed fallback with some static defaults, placeholders,
* and an injected value 'countryCodeFromGeoLookup' that we'll use
* instead of what we would have retrieved from the remote service.
*/
return new UserAccount(customerId, "Unknown Name",
countryCodeFromGeoLookup, true, true, false);
} public static class UserAccount {
private final int customerId;
private final String name;
private final String countryCode;
private final boolean isFeatureXPermitted;
private final boolean isFeatureYPermitted;
private final boolean isFeatureZPermitted; UserAccount(int customerId, String name, String countryCode,
boolean isFeatureXPermitted,
boolean isFeatureYPermitted,
boolean isFeatureZPermitted) {
this.customerId = customerId;
this.name = name;
this.countryCode = countryCode;
this.isFeatureXPermitted = isFeatureXPermitted;
this.isFeatureYPermitted = isFeatureYPermitted;
this.isFeatureZPermitted = isFeatureZPermitted;
}
}
}
单元测试
@Test
public void test() {
CommandWithStubbedFallback command = new CommandWithStubbedFallback(1234, "ca");
UserAccount account = command.execute();
assertTrue(command.isFailedExecution());
assertTrue(command.isResponseFromFallback());
assertEquals(1234, account.customerId);
assertEquals("ca", account.countryCode);
assertEquals(true, account.isFeatureXPermitted);
assertEquals(true, account.isFeatureYPermitted);
assertEquals(false, account.isFeatureZPermitted);
}
使用HystrixObservableCommand
@Override
protected Observable<Boolean> resumeWithFallback() {
return Observable.just( new UserAccount(customerId, "Unknown Name",
countryCodeFromGeoLookup, true, true, false) );
}
如果使用返回多个数据,那么需要知道在异常前返回了哪些数据,然后在fallback继续处理。
@Override
protected Observable<Integer> construct() {
return Observable.just(1, 2, 3)
.concatWith(Observable.<Integer> error(new RuntimeException("forced error")))
.doOnNext(new Action1<Integer>() {
@Override
public void call(Integer t1) {
lastSeen = t1;
} })
.subscribeOn(Schedulers.computation());
} @Override
protected Observable<Integer> resumeWithFallback() {
if (lastSeen < 4) {
return Observable.range(lastSeen + 1, 4 - lastSeen);
} else {
return Observable.empty();
}
}
缓存fallback
有时候,如果执行异常需要在缓存中获取数据来代替。因为从缓存中获取数据也可能需要网络请求,所以也需要通过HystrixCommand或HystrixObservableCommand来处理
fallback使用的线程池必须和调用方法的隔离开,如果隔离开,那么当调用服务超负载是,fallback也会不可执行。下面的例子显示了CommandWithFallbackViaNetwork如何在他的getFallback中执行FallbackViaNetwork。如果FallbackViaNetwork执行失败了,他也有自己的一个fallback,返回null。
为了让FallbackViaNetwork和CommandWithFallbackViaNetwork不在同一个线程池中执行,通过HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")设置了他自己的线程池。
public class CommandWithFallbackViaNetwork extends HystrixCommand<String> {
private final int id; protected CommandWithFallbackViaNetwork(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GetValueCommand")));
this.id = id;
} @Override
protected String run() {
// RemoteServiceXClient.getValue(id);
throw new RuntimeException("force failure for example");
} @Override
protected String getFallback() {
return new FallbackViaNetwork(id).execute();
} private static class FallbackViaNetwork extends HystrixCommand<String> {
private final int id; public FallbackViaNetwork(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GetValueFallbackCommand"))
// use a different threadpool for the fallback command
// so saturating the RemoteServiceX pool won't prevent
// fallbacks from executing
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")));
this.id = id;
} @Override
protected String run() {
MemCacheClient.getValue(id);
} @Override
protected String getFallback() {
// the fallback also failed
// so this fallback-of-a-fallback will
// fail silently and return null
return null;
}
}
}
一些系统有主备模式,一般备用模式只用在失败的情况下,这种模式就是前一个例子讲的情况。然后自动切换主备并不是一种理想的方案,当主模式失败时,他会忽略报警。
为了解决这个问题,可以使用手动切换主备模式。
主备的HystrixCommand实现是相互线程隔离的,他们有不同的表现特性。
public class CommandFacadeWithPrimarySecondary extends HystrixCommand<String> {
private final static DynamicBooleanProperty usePrimary = DynamicPropertyFactory.getInstance().getBooleanProperty("primarySecondary.usePrimary", true);
private final int id;
public CommandFacadeWithPrimarySecondary(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("PrimarySecondaryCommand"))
.andCommandPropertiesDefaults(
// we want to default to semaphore-isolation since this wraps
// 2 others commands that are already thread isolated
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
this.id = id;
}
@Override
protected String run() {
if (usePrimary.get()) {
return new PrimaryCommand(id).execute();
} else {
return new SecondaryCommand(id).execute();
}
}
@Override
protected String getFallback() {
return "static-fallback-" + id;
}
@Override
protected String getCacheKey() {
return String.valueOf(id);
}
private static class PrimaryCommand extends HystrixCommand<String> {
private final int id;
private PrimaryCommand(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("PrimaryCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("PrimaryCommand"))
.andCommandPropertiesDefaults(
// we default to a 600ms timeout for primary
HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(600)));
this.id = id;
}
@Override
protected String run() {
// perform expensive 'primary' service call
return "responseFromPrimary-" + id;
}
}
private static class SecondaryCommand extends HystrixCommand<String> {
private final int id;
private SecondaryCommand(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("SecondaryCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("SecondaryCommand"))
.andCommandPropertiesDefaults(
// we default to a 100ms timeout for secondary
HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)));
this.id = id;
}
@Override
protected String run() {
// perform fast 'secondary' service call
return "responseFromSecondary-" + id;
}
}
public static class UnitTest {
@Test
public void testPrimary() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", true);
assertEquals("responseFromPrimary-20", new CommandFacadeWithPrimarySecondary(20).execute());
} finally {
context.shutdown();
ConfigurationManager.getConfigInstance().clear();
}
}
@Test
public void testSecondary() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", false);
assertEquals("responseFromSecondary-20", new CommandFacadeWithPrimarySecondary(20).execute());
} finally {
context.shutdown();
ConfigurationManager.getConfigInstance().clear();
}
}
}
}
无网络请求的依赖
如果执行的依赖不需要网络请求,可以设置executionIsolationStrategy为ExecutionIsolationStrategy.SEMAPHORE通过信号量来隔离。
public class CommandUsingSemaphoreIsolation extends HystrixCommand<String> {
private final int id;
public CommandUsingSemaphoreIsolation(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
// since we're doing an in-memory cache lookup we choose SEMAPHORE isolation
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
this.id = id;
}
@Override
protected String run() {
// a real implementation would retrieve data from in memory data structure
return "ValueFromHashMap_" + id;
} }
清除缓存
如果当数据改变时,需要清除缓存,可以通过HystrixRequestCache.clear()来清除。
public class CommandUsingRequestCacheInvalidation { /* represents a remote data store */
private static volatile String prefixStoredOnRemoteDataStore = "ValueBeforeSet_"; public static class GetterCommand extends HystrixCommand<String> {
private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("GetterCommand");
private final int id;
public GetterCommand(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetSetGet"))
.andCommandKey(GETTER_KEY));
this.id = id;
}
@Override
protected String run() {
return prefixStoredOnRemoteDataStore + id;
}
@Override
protected String getCacheKey() {
return String.valueOf(id);
}
/**
* Allow the cache to be flushed for this object.
*
* @param id
* argument that would normally be passed to the command
*/
public static void flushCache(int id) {
HystrixRequestCache.getInstance(GETTER_KEY,
HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
} }
public static class SetterCommand extends HystrixCommand<Void> { private final int id;
private final String prefix; public SetterCommand(int id, String prefix) {
super(HystrixCommandGroupKey.Factory.asKey("GetSetGet"));
this.id = id;
this.prefix = prefix;
}
@Override
protected Void run() {
// persist the value against the datastore
prefixStoredOnRemoteDataStore = prefix;
// flush the cache
GetterCommand.flushCache(id);
// no return value
return null;
}
}
}
单元测试
@Test
public void getGetSetGet() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
assertEquals("ValueBeforeSet_1", new GetterCommand(1).execute());
GetterCommand commandAgainstCache = new GetterCommand(1);
assertEquals("ValueBeforeSet_1", commandAgainstCache.execute());
// confirm it executed against cache the second time
assertTrue(commandAgainstCache.isResponseFromCache());
// set the new value
new SetterCommand(1, "ValueAfterSet_").execute();
// fetch it again
GetterCommand commandAfterSet = new GetterCommand(1);
// the getter should return with the new prefix, not the value from cache
assertFalse(commandAfterSet.isResponseFromCache());
assertEquals("ValueAfterSet_1", commandAfterSet.execute());
} finally {
context.shutdown();
}
}
}
如果想使用Hystrix,那么需要将依赖服务调用通过HystrixCommand来封装。
使用Hystrix之前的结构
使用Hystrix之后的结构
hystrix文档翻译之如何使用的更多相关文章
- hystrix文档翻译之Dashboard
Dashboard Hystrix Dashboard可以让你实时监控hystrix的metrics信息. 当netflix开始使用dashboard后,运维效率得到了极大的提升,并且极大降低了大多数 ...
- hystrix文档翻译之插件
插件 可以通过实现插件来改变Hystrix的行为.可以通过HystrixPlugins来注册自定义插件,这些插件会被应用到HystrixCommand,HystrixObservableCommand ...
- hystrix文档翻译之metrics
metrics和监控 动机 HystrixCommands和HystrixObservableCommands执行过程中会产生相关运行情况的metrics.这些metrics对于监控系统表现有很大的 ...
- hystrix文档翻译之配置
Hystrix使用Archaius作为配置的默认实现,下面介绍的是HystrixPropertiesStrategy的默认实现,你也可以通过插件方式重新实现. 每一个配置有四个级别: 全局默认 当下面 ...
- hystrix文档翻译之运维
hystrix不仅用作工程可靠性还可以用来运维. 这里将会分享一个拥有100+Hystrix命令,40+线程池,每天有100亿次线程请求,2000亿次信号量请求的系统是如何使用hystrix运维的.这 ...
- hystrix文档翻译之工作原理
流程图 下面的图片显示了一个请求在hystrix中的流程图. 1.构造一个HystrixCommand或者HystrixObservableCommand对象 第一步是创建一个HystrixComma ...
- hystrix文档翻译之开始使用
获取包 使用maven获取包. <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId ...
- hystrix文档翻译之概述
Hystrix是什么 在一个大型的分布式系统中,难免有些依赖服务会失败.hystrix通过容错逻辑来控制不同服务间的交互.hystrix通过隔离各服务交互节点来防止连级错误,并且提供降级功能,最终保证 ...
- 深入理解Hystrix之文档翻译
转载请标明出处: http://blog.csdn.net/forezp/article/details/75333088 本文出自方志朋的博客 什么是Hystrix 在分布式系统中,服务与服务之间依 ...
随机推荐
- 微服务技术栈:API网关中心,落地实现方案
本文源码:GitHub·点这里 || GitEE·点这里 一.服务网关简介 1.外观模式 客户端与各个业务子系统的通信必须通过一个统一的外观对象进行,外观模式提供一个高层次的接口,使得子系统更易于使用 ...
- Statistics and Samples in Distributional Reinforcement Learning
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:1902.08102v1 [stat.ML] 21 Feb 2019 Abstract 我们通过递归估计回报分布的统计量,提供 ...
- Inherent Adversarial Robustness of Deep Spiking Neural Networks: Effects of Discrete Input Encoding and Non-Linear Activations
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2003.10399v2 [cs.CV] 23 Jul 2020 ECCV 2020 1 https://github.com ...
- Salesforce LWC学习(二十一) Error浅谈
本篇参考:https://developer.salesforce.com/docs/component-library/documentation/en/lwc/data_error https:/ ...
- 基于伪分布式Hadoop搭建Hive平台详细教程
一.搭建环境的前提条件 环境:Linux系统 Hadoop-2.6.0 MySQL 5.6 apache-hive-2.3.7 这里的环境不一定需要和我一样,基本版本差不多都ok的,所需安装包和压缩包 ...
- SEO大神都是些什么人
http://www.wocaoseo.com/thread-97-1-1.html 貌似好久没有更新seo培训联盟的文章了,最近一直在专心学习其他的东西,前一段写了几篇关于用户需求和体验的文章,但是 ...
- openCV - 3. Mat对象
Mat对象与IplImage对象.Mat对象使用.Mat定义数组 Mat对象与IplImage对象 Mat对象OpenCV2.0之后引进的图像数据结构.自动分配内存.不存在内存泄漏的问题,是面向对象的 ...
- 【目标检测】SSD+Tensorflow 300&512 配置详解
SSD_300_vgg和SSD_512_vgg weights下载链接[需要科学上网~]: Model Training data Testing data mAP FPS SSD-300 VGG-b ...
- Data Vault玩转数据仓库(三)
在Data Vault 2.0版本里,其不只是针对数据仓库的建模,同时也包含了架构,方法论以及实现.这篇挑几个概念,附上我个人对其的理解.同时也把这个系列的名字改成<Data Vault玩转数据 ...
- 几个Graphics函数
1.Graphics.Blit:Copies source texture into destination render texture with a shader 声明: 1.public sta ...