使用Resilience4J实现断路器模式

栏目: 后端 · 发布时间: 5年前

内容简介:断路器是一种模式,可以防止整个架构中单个微服务的故障级联,从而确保系统具有弹性。该模式可以通过像Hystrix或Resilience4j这样的代码库实现,或者通过底层基础设施来实现,例如使用Istio。

断路器是一种模式,可以防止整个架构中单个微服务的故障级联,从而确保系统具有弹性。该模式可以通过像Hystrix或Resilience4j这样的代码库实现,或者通过底层基础设施来实现,例如使用Istio。

Hystrix vs. Resilience4j简介

Hystrix 是Netflix提供的一个开源库,旨在提高分布式系统的弹性,使HTTP请求在其分布式组件之间进行通信。它通过实现断路器模式实现。

Resilience4J 是一个受Hystrix启发的独立库,它建立在功能编程的原理之上。两者之间最显着的区别在于,虽然Hystrix采用面向对象的设计,其中对外部系统的调用必须包含在HystrixCommand提供多种功能中,但Resilience4J依赖于函数组合来让您堆叠所需的特定装饰器。

那些装饰器当然包括断路器,还包括速率限制器,重试和隔板。这些装饰器可以同步或异步执行,充分利用 Java 8中引入的lambda。

Resilience4J的其他优点包括更精细的配置选项(例如,关闭断路器模式所需的成功执行次数)和更轻的依赖性足迹。

Java中的函数编程简介

函数组合背后的想法是:

  • 如果函数f被定义为Function<X, Y>- 将类型X作为输入并返回类型的函数Y
  • 如果函数g定义为Function<Y, Z>
  • 然后可以将新函数h定义为Function<X, Z>组成函数f和g

Java 8在其API中引入了函数编程(FP)的一些方面。上面的函数组合可以在Java中翻译:

public class F implements Function<Integer, Integer> {

    @Override
    public Integer apply(Integer x) {
        return x + 1;
    }
}

public class G implements Function<Integer, Integer> {

    @Override
    public Integer apply(Integer y) {
        return 2 * y;
    }
}

public class H implements  Function<Integer, Integer> {

    @Override
    public Integer apply(Integer x) {
        var f = new F();
        var g = new G();
        Integer y = f.apply(x);
        return g.apply(y);
    }
}

这非常麻烦,因为Java最初设计时考虑了面向对象编程(OOP)。

一切都需要属于一个类,即使这没有多大意义。因此,为了弥合OOP和FP之间的这种差距,并使FP代码更容易编写,Java 8带来了函数接口的概念:功能接口是一个带有单个抽象方法的接口,并且可选择带注释@FunctionalInterface。

可以使用lambda表示法以简化的方式编写任何功能接口。例如,Function<T, V>是一个函数接口,因为它有一个抽象方法 - apply()。因此,可以使用lambdas重写上面的代码:

Function<Integer, Integer> h = x -> {
    Function<Integer, Integer> f = y -> y + 1;
    Function<Integer, Integer> g = y -> y + 1;
    return g.apply(f.apply(x));
};

FP的另一个基础是高阶函数。这只意味着函数是类似于任何其他类型的函数,并且可以作为函数中的参数传递,并作为结果返回。

例如,Functioninterface定义以下方法:

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}

使用这种方法,我们可以简单地重写h函数:

var h = f.compose(g);

Resilience4J完全基于函数式编程,并且使用了很多公开的概念。重要的是要记住从Hystrix迁移,因为与通常的Java思维方式相比,这需要进行更改。

Resilience4J入门

HTTP调用可以被认为是一个函数:它接受HTTP请求作为输入,并返回HTTP响应。

同样,Circuit Breaker可以被认为是一个函数,输入相同的HTTP请求,返回值如果调用成功则返回HTTP响应,如果失败则返回默认HTTP响应。

因此,使用断路器就像用第二个“断路器”函数组成第一个“调用”函数。

这是一个示例,用于说明如何使用它:

public class Command {
    public Long run() {
        // Does the actual job of making the HTTP request
    }
}

var cb = CircuitBreaker.ofDefaults("circuit-breaker");
var result = cb.executeSupplier(new Command()::run);

因为Resilience4J中的每个特征都被建模为一个函数,所以组合这些特征只需要应用上述的函数组合原理。

这相当于面向对象编程中的Decorator模式:目标被“包装”到装饰器对象中。

在这里,我们应用此设计来组成三个函数调用。第一个调用HTTP端点,第二个调用Circuit Breaker,第三个调用,如果调用失败则重试。

var cb = CircuitBreaker.ofDefaults("circuit-breaker");
var retry = Retry.ofDefaults("retry");
var cbSupplier = CircuitBreaker.decorateSupplier(cb, new Command()::run);
var retrySupplier = Retry.decorateSupplier(retry, cbSupplier);
var result = retrySupplier.get();

自定义缓存装饰器

使用Resilience4J实现缓存功能,我们的要求是:只有在修饰函数调用失败时才应从缓存返回。设计我们自己的缓存实现功能非常简单。“函数”这个词很重要,因为根据Resilience4J的设计原则,状态 - 缓存 - 应该是外部的并传递给函数以保持其纯净。为了简化实现,缓存将保留一个值,当装饰函数成功返回时,可能会替换该值:

public class Cache<T> {

    private T value;

    static <T> Supplier<T> decorateSupplier(Cache<T> cache, Supplier<T> supplier) {
        return Try.ofSupplier(supplier)
                .fold(
                        throwable -> () -> cache.value,
                        value -> {
                            cache.value = value;
                            return () -> value;
                        });
    }
}

本Try类来自于 Vavr库 ,函数编程API的Java语言和Resilience4J唯一的依赖。它需要两个lambdas:

  • 第一个接受一个 Throwable并返回一个返回结果的函数
  • 第二个接受该值,并返回一个返回结果的函数

请注意,两者都是惰性的:它们不直接返回结果,而是返回Supplier结果。使用此自定义缓存,现在可以装饰Circuit Breaker调用,以便在电路打开时返回缓存值:

var cb = CircuitBreaker.ofDefaults("circuit-breaker");
var cache = new Cache<Long>();
var cbDecorated = CircuitBreaker.decorateSupplier(cb, new Command()::run);
var cacheDecorated = Cache.decorateSupplier(cache, cbDecorated);
cacheDecorated.get();

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Blockchain Basics

Blockchain Basics

Daniel Drescher / Apress / 2017-3-16 / USD 20.99

In 25 concise steps, you will learn the basics of blockchain technology. No mathematical formulas, program code, or computer science jargon are used. No previous knowledge in computer science, mathema......一起来看看 《Blockchain Basics》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具