Hystrix(4)

以下是 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() {
        return "hello" + name +"!";
    }
}

使用 HystrixObservableCommand 而不是 HystrixCommand 的等效 Hello World 解决方案将涉及重写构造方法,如下所示:

public class ObCommandHelloWorld extends HystrixObservableCommand<String> {

    private final String name;

    public ObCommandHelloWorld(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> subscriber) {
                try{
                    if (!subscriber.isUnsubscribed()){
                       // 一个真实的例子:像网络调用
                        subscriber.onNext("Hello");
                        subscriber.onNext(name+"!");
                        subscriber.onCompleted();
                    }
                }catch (Exception e){
                    subscriber.onError(e);
                }
            }
        }).subscribeOn(Schedulers.io());
    }
}

同步执行

我们可以使用 execute() 方法同步执行 HystrixCommand,如下例所示:

 CommandHelloWorld command = new CommandHelloWorld("jin shuai");
 String execute = command.execute();

对于 HystrixObservableCommand 没有简单的等价物执行,但如果我们知道此类命令产生的 Observable 必须始终只产生一个值,我们可以通过将 .toBlocking().toFuture().get() 应用于 Observable 来模仿exexute的行为。

ObCommandHelloWorld command = new ObCommandHelloWorld("js");
String s = command.observe().toBlocking().toFuture().get();

异步执行

我们可以使用 queue() 方法异步执行 HystrixCommand,如下例所示:

CommandHelloWorld command = new CommandHelloWorld("jin shuai");
Future<String> queue = command.queue();
String s = queue.get();

以下是彼此等价的:

String s1 = command.queue().get();
String s2 = command.execute();

HystrixObservableCommand 等效

对于 HystrixObservableCommand 没有简单的队列等价物,但是如果我们知道此类命令生成的 Observable 必须始终只生成一个值,我们可以通过应用 RxJava 运算符 .toBlocking().toFuture( ) 到 Observable。

反应式执行

我们还可以使用以下方法之一将 HystrixCommand 的结果作为 Observable 来观察:

  • observe() — 返回一个立即执行命令的“hot” Observable,但由于 Observable 是通过 ReplaySubject 过滤的,所以在我们有机会subscribe之前,我们不会有丢失它发出的任何项目的危险
  • toObservable() — 返回一个“cold”的 Observable,它不会执行命令并开始发送结果,直到我们订阅 Observable
Observable<String> hot = new ObCommandHelloWorld("js").observe();
Observable<String> cold = new ObCommandHelloWorld("js").toObservable();

然后通过订阅 Observable 来检索命令的值:

hot.subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                System.out.println("-------"+s);
            }
        });

使用 Java 8 lambdas/closures 更紧凑; 它看起来像这样:

        hot.subscribe(s1 -> {
            System.out.println("-------"+ s1);
        });

反应式Commands

除了使用上述方法将 HystrixCommand 转换为 Observable 之外,我们还可以创建一个 HystrixObservableCommand,它是 HystrixCommand 的专用版本,用于包装 Observables。 HystrixObservableCommand 能够包装发出多个项目的 Observables,而普通的 HystrixCommands,即使转换为 Observables,也永远不会发出超过一个项目。

在这种情况下,不要用命令逻辑覆盖 run 方法(就像使用普通 HystrixCommand 一样),而是覆盖构造方法,以便它返回我们打算包装的 Observable。

要获取 HystrixObservableCommand 的 Observable 表示,请使用以下两种方法之一:

  • observe() — 返回一个立即订阅底层 Observable 的“hot” Observable,尽管因为它是通过 ReplaySubject 过滤的,所以在我们有机会订阅生成的 Observable 之前,我们不会有丢失它发出的任何项目的危险
  • toObservable() — 返回一个“cold”的 Observable,在我们订阅生成的 Observable 之前不会订阅底层的 Observable

FallBack

我们可以通过添加一个fallback方法来支持 Hystrix 命令中的优雅降级,Hystrix 将调用该方法来获取一个或多个默认值,以防主命令失败。 我们将希望为大多数可能会失败的 Hystrix 命令实现回退,但有几个例外:

  • 执行写操作的命令

       如果我们的 Hystrix 命令旨在执行写入操作而不是返回值(这样的命令通常可能在 HystrixCommand 的情况下返回 void 或在 HystrixObservableCommand 的情况下返回空的 Observable),那么没有多大意义 在实施fallback。 如果写入失败,我们可能希望将失败传播回调用者。

  • 批处理系统/离线计算

        如果我们的 Hystrix 命令正在填充缓存、生成报告或进行任何类型的离线计算,通常更适合将错误传播回调用者,然后调用者可以稍后重试命令,而不是向调用者发送 默默降级的反应。

无论我们的命令是否有回退,所有常见的 Hystrix 状态和断路器状态/指标都会更新以指示命令失败。

在普通的 HystrixCommand 中,我们通过 getFallback() 实现来实现回退。 Hystrix 将对所有类型的故障执行此回退,例如 run() 故障、超时、线程池或信号量拒绝以及断路器短路。 以下示例包括这样的回退:

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() {
        throw new RuntimeException("失败");
    }

    @Override
    protected String getFallback() {
        return "失败了:"+name;
    }
}

HystrixObservableCommand 等效

对于 HystrixObservableCommand,我们可以改写 resumeWithFallback 方法,以便它返回第二个 Observable,如果失败,它将从主 Observable 接管。 请注意,由于 Observable 在发出一个或多个项目后可能会失败,因此我们的fallback不应假定它将发出观察者将看到的唯一值。

在内部,Hystrix 使用 RxJava 的 onErrorResumeNext 操作符在发生错误时在主 Observable 和备用 Observable 之间无缝转换。

错误传播

除了 HystrixBadRequestException 之外,从 run() 方法抛出的所有异常都算作失败并触发 getFallback() 和断路器(circuit-breaker)逻辑。

我们可以将要抛出的异常包装在 HystrixBadRequestException 中并通过 getCause() 检索它。 HystrixBadRequestException 旨在用于报告非法参数或非系统故障等用例,这些故障不应计入故障指标并且不应触发回退(fallback)逻辑。

HystrixObservableCommand 等效
在 HystrixObservableCommand 的情况下,不可恢复的错误是通过来自结果 Observable 的 onError 通知返回的,并且通过回退到 Hystrix 通过我们实现的 resumeWithFallback 方法获得的第二个 Observable 来完成回退。

执行异常类型

Failure TypeException classException.causesubject to fallback
FailureHystrixRuntimeException底层异常(用户控制)YES
TimeoutHystrixRuntimeExceptionj.u.c.TimeoutExceptionYES
short_circuitedHystrixRuntimeExceptionj.l.TimeoutExceptionYES
thread_pool_rejectedHystrixRuntimeExceptionj.u.c.RejectedExecutionExceptionYES
semaphore_rejectedHystrixRuntimeExceptionj.l.TimeoutExceptionYES
bad_requestHystrixBadRequestException底层异常(用户控制)NO

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值