美文网首页用Java构建...
用Java构建响应式微服务3-构建响应式微服务

用Java构建响应式微服务3-构建响应式微服务

作者: ApolloYang2017 | 来源:发表于2018-04-22 14:34 被阅读0次

    在这一章节里,我们将用Vert.X构建我们的第一个微服务。像大多数采用http交互的微服务系统,我们打算从http微服务开始。因为系统由多个互相通信的微服务构成,我们将构建另一个微服务,它作为第一个微服务的消费者。然后,我们将展示为何这样的设计并不完全符合响应式微服务。最后,我们将实现基于消息的微服务,看看消息是怎样提升了响应性。

    第一个微服务

    在这一章节,我们打算实现同类的微服务两个。第一个微服务暴露一个hello服务,我们称它为hello微服务。另一个消费这个服务两次(并发地)。消费者将被称为hello消费者微服务。这个小系统不仅展示了一个服务是怎样提供服务的,而且展示它是怎样被消费的。在图3-1的左边,微服务用http交互,hello消费者微服务作为http客户端向hello微服务发请求;在图的右边,hello消费者微服务用消息与hello微服务交互。这个不同影响了系统的响应性。

    图3-1

    在前一章节,我们看到两种不同的方式使用Vert.X API: 回调和RxJava。展示它们的不同有助于你发现更佳途径,hello微服务是使用基于回调开发模式实现,而hello消费者微服务是用RxJava实现。

    实现http微服务

    微服务通常通过http暴露他们的API,通过http请求来消费。让我们看看用Vert.X怎样实现这些http交互。这个部分开发的代码在代码仓库的microservices/hello-microservice-http目录下可获得。

    开始

    创建hello-microservice-http目录,然后生成工程结构:

    mkdir hello-microservice-http

    cd hello-microservice-http

    mvn io.fabric8:vertx-maven-plugin:1.0.5:setup \

    -DprojectGroupId=io.vertx.microservice \

    -DprojectArtifactId=hello-microservice-http \

    -Dverticle=io.vertx.book.http.HelloMicroservice \

    -Ddependencies=web

    这个命令生成maven工程,配置Vert.X Maven插件。另外,它加上vertx-web依赖。Vert.X Web是一个模块,它提供你基于Vert.X构建流行的web应用的一切。

    Verticle

    打开src/main/java/io/vertx/book/http/HelloMicroservice.java,这个被生成的verticle代码没做什么很有趣的事,但它是一个起点:

    package io.vertx.book.http;

    import io.vertx.core.AbstractVerticle;

    public class HelloMicroservice extendsAbstractVerticle {

             @Override

             publicvoid start() {

             }

    }

    现在,执行下面的maven命令:

    mvn compile vertx:run

    你现在可以编辑verticle,每次你保存文件后,应用将被重新编译并自动重启。

    http微服务

    是时候让MyVerticle做点什么了。让我们启动一个http server。正如你前面章节看到的,用Vert.X创建一个http server仅仅:

    @Override

    public void start() {

             vertx.createHttpServer()

             .requestHandler(req-> req.response().end("hello"))

             .listen(8080);

    }

    一旦加上这些代码并保存,在浏览上访问http://localhost:8080你应该能看到hello。这段代码创建一个http server监听端口8080,注册了一个请求处理器,每一个http请求进来时它会被调用。现在,我们仅仅输出hello到http响应。

    使用路由和参数

    许多服务是通过web url调用的,因此,检查路径是重要的,以知道请求在要求什么。然而,在请求处理器里面做路径检查以实现不同的动作可能会变得复杂。幸运地,Vert.X Web提供了一个路由器,通过它你可以注册路由。路由是Vert.X Web检查路径、调用相关动作的机制。让我们重写start方法,用两个路由:

    @Override

    public void start() {

             Routerrouter = Router.router(vertx);

             router.get("/").handler(rc-> rc.response().end("hello"));

             router.get("/:name").handler(rc-> rc.response().end("hello " + rc.pathParam("name")));

             vertx.createHttpServer()

             .requestHandler(router::accept)

             .listen(8080);

    }

    我们创建了路由器对象后,我们注册了两个路由:第一个处理根路径的请求仅仅输出hello,第二个路由有一个路径参数(:name),处理器追加参数值到欢迎中。最后,我们更改请求处理器(requestHandler),使用路由器的accept方法。

    如果你没有停止vertx:run,你打开浏览器:

    访问http://localhost:8080,你应该会看到hello

    访问http://localhost:8080/vert.x,你应该会看到hello vert.x

    生成JSON

    在微服务里,JSON是常用的。让我们修改前一个类,生成JSON:

    @Override

    public void start() {

             Routerrouter = Router.router(vertx);

             router.get("/").handler(this::hello);

             router.get("/:name").handler(this::hello);

             vertx.createHttpServer()

             .requestHandler(router::accept)

             .listen(8080);

    }

    private void hello(RoutingContext rc) {

             Stringmessage = "hello";

             if(rc.pathParam("name") != null) {

                       message+= " " + rc.pathParam("name");

             }

             JsonObjectjson = new JsonObject().put("message", message);

             rc.response()

             .putHeader(HttpHeaders.CONTENT_TYPE,"application/json")

             .end(json.encode());

    }

    Vert.X提供一个JsonObject类来创建和操作JSON。放上这段代码,你打开浏览器:

    访问http://localhost:8080,你应该会看到{“message”:“hello”}

    访问http://localhost:8080/vert.x,你应该会看到{“message”: “hello vert.x”}

    打包和运行

    按CTRL+C,停止vertx:run的执行,在同一目录下执行下面的命令:

    mvn package

    这生成一个fat jar在target目录下:hellomicroservice-http-1.0-SNAPSHOT.jar。fat jar之所以胖,因为jar包有一个合理的大小(约6.3MB),包含了运行应用所需的一切:

    java -jar target/hello-microservice-http-1.0-SNAPSHOT.jar

    你可以通过访问http://localhost:8080来检查确定它是运行起来的。保持住运行,因为下一个微服务将调用它。

    消费http微服务

    一个微服务不构成一个应用,你需要一个微服务系统。现在我们有了一个运行中的微服务,让我们写第二个微服务来消费它。第二个微服务也提供了一个http请求接口,每一个请求会调用我们刚刚实现的微服务。这个章节展示的代码可以从代码仓库的microservices/helloconsumer-microservice-http目录获得。

    创建工程

    一样地,让我们创建一个新工程:

    mkdir hello-consumer-microservice-http

    cd hello-consumer-microservice-http

    mvn io.fabric8:vertx-maven-plugin:1.0.5:setup

    \

    -DprojectGroupId=io.vertx.microservice \

    -DprojectArtifactId=hello-consumer-microservice-http \

    -Dverticle=io.vertx.book.http.HelloConsumerMicroservice \

    -Ddependencies=web,web-client,rx

    最后的命令增加了其它的依赖:Vert.X web客户端,异步的http客户端。我们将使用这个客户端来向第一个微服务发请求。这个命令也增加的Vert.X RxJava绑定,我们打算在后面使用它。

    现在编辑src/main/java/io/vertx/book/http/HelloConsumerMicroservice.java文件,更改它的内容:

    package io.vertx.book.http;

    import io.vertx.core.AbstractVerticle;

    import io.vertx.core.json.JsonObject;

    import io.vertx.ext.web.*;

    import io.vertx.ext.web.client.*;

    import io.vertx.ext.web.codec.BodyCodec;

    public class HelloConsumerMicroservice extends AbstractVerticle {

             private WebClientclient;

             @Override

             public void start(){

                      client = WebClient.create(vertx);

                       Routerrouter = Router.router(vertx);

                       router.get("/").handler(this::invokeMyFirstMicroservice);

                       vertx.createHttpServer()

                       .requestHandler(router::accept)

                       .listen(8081);

             }

             private voidinvokeMyFirstMicroservice(RoutingContext rc) {

                       HttpRequestrequest = client

                       .get(8080,"localhost","/vert.x")

                       .as(BodyCodec.jsonObject());

                       request.send(ar-> {

                       if(ar.failed()) {

                                rc.fail(ar.cause());

                       } else {

                                rc.response().end(ar.result().body().encode());

                       }

                       });

             }

    }

    在start方法,我们创建一个WebClient,一个Router,我们注册了一个根路径的route,启动http server,传递router的accept方法给requestHandler。这个方法用web客户端来调用第一个微服务的指定路径(/vert.x),输出结果到http响应。

    一旦http请求被创建,我们调用send方法来发出请求,无论是响应返回或者是有错误发生,我们设定的处理器会被调用。If-else块检查请求成功与否。不要忘了这是一个远程交互,有很多原因导致失败。例如,第一个微服务可能没有运行。当它成功时,我们输入收到的数据到响应,否则,我们返回一个500的http响应。

    多次调用服务

    现在让我们改变当前的行动,用两个不同的路径参数请求hello微服务两次:

    HttpRequest request1 = client

    .get(8080, "localhost", "/Luke")

    .as(BodyCodec.jsonObject());

    HttpRequest request2 = client

    .get(8080, "localhost", "/Leia")

    .as(BodyCodec.jsonObject());

    这两个请求是独立的,能够并发地执行。可是这里我们想输出一个把这两个请求的结果装配起来的响应。需要调用两次服务、把两个结果装配起来的代码可以变得复杂。当我们接收到其中一个响应时,我们需要检查另一个请求完成与否。当然,对于两个请求,这个代码仍然是可管理的。当我们需要处理更多的时候,它变得极其复杂。幸运地,正如前一章节所讲,我们能够使用响应式编程,RxJava使代码变得简单。

    我们介绍了vertx-mavan-plugin插件引入Vert.X RxJava API。在HelloConsumerMicroservice里,我们替换重要的import语句:

    import io.vertx.core.json.JsonObject;

    import io.vertx.rxjava.core.AbstractVerticle;

    import io.vertx.rxjava.ext.web.*;

    import io.vertx.rxjava.ext.web.client.*;

    import io.vertx.rxjava.ext.web.codec.BodyCodec;

    import rx.Single;

    用RX, 我们要写的调用两个请求、构造他们的结果成一个响应的复杂代码变得比较简单:

    private voidinvokeMyFirstMicroservice(RoutingContext rc) {

             HttpRequestrequest1 = client

             .get(8080,"localhost", "/Luke")

             .as(BodyCodec.jsonObject());

             HttpRequestrequest2 = client

             .get(8080,"localhost", "/Leia")

             .as(BodyCodec.jsonObject());

             Singles1 = request1.rxSend().map(HttpResponse::body);

             Singles2 = request2.rxSend().map(HttpResponse::body);

             Single.zip(s1,s2, (luke, leia) -> {

                       //We have the results of both requests in Luke and Leia

                       returnnew JsonObject()

                       .put("Luke",luke.getString("message"))

                       .put("Leia",leia.getString("message"));

             })

             .subscribe(

                       result-> rc.response().end(result.encodePrettily()),

                       error-> {

                                error.printStackTrace();

                                rc.response()

                                .setStatusCode(500).end(error.getMessage());

                       }

             );

    }

    注意rxSend方法调用。Vert.X里,RxJava方法加上了rx前缀,以更容易识别。rxSend方法的结果是一个Single,可订阅的单个元素,代表一个操作的延期结果,single.zip方法用一组Single作为参数,一旦所有的Single收到它们的值,就用这些值来调用一个函数。最后,订阅(subscribe),这个方法用两个函数作为参数:

    第1个函数是用zip函数的结果(一个json对象)作为参数被调用,我们输出接收到的json内容到http响应;

    第2个函数是某种失败(超时,异常等等)发生时被调用,在这里,我们用空的json对象做出响应。

    这段代码生效后,hello微服务仍在运行,如果我们打开http://localhost:8081我们应该会看到:

    {

    "Luke" : "hello Luke",

    "Leia" : "hello Leia"

    }

    这是响应式微服务吗?

    现在我们有两个微服务。他们是可独立部署和修改的。他们也使用轻量级的http协议交互。但是他们是响应式微服务吗?不,他们不是。记住,响应式微服务必须是:

    . 自治的

    . 异步的

    . 可恢复的

    . 弹性的

    当前设计的主要问题是两个微服务是紧耦合的。Web客户端是显示地配置了第一个微服务的地址。如果第一个微服务失败了,我们不能够通过请求另一个来恢复服务。我们想降低负载,创建一个新的hello微服务实例将帮助不了我们。感谢Vert.X web客户端,交互是异步的。然而,我们没有用一个虚拟的目标地址来调用微服务、而是直接用它的URL,这不能提供我们需要的可恢复性和弹性。

    不要失望,在下一章节我们将朝响应式微服务迈出一大步。

    Vert.X事件总线---一个消息后端

    Vert.X提供了事件总线,允许一个应用的不同组件用消息来交互。消息被送到地址,有消息头和消息体。一个地址是一个字符串,代表一个目标地址。消息消费者注册它们自己到这个地址、以接收消息。事件总线也是集群的,意味着它能够跨越网络、在分布的发送者和消费者之间传递消息。以集群模式启动Vert.X应用,被连接的节点可以共享数据结构、做停止失败检查、负载均衡。事件总线能够在集群的所有节点间传递消息。为了创建这样一个集群,你可以用Apache Ignite、Apache Zookeeper、Infinispan或者是Hazelcast。在这本书里,我们打算用Infinispan,但是,我们不做高级的配置。如果需要,可参考Infinispan文档(http://infnispan.org/)。Infinispan(或者你选的其他技术)管理节点的发现和存储。事件总线用直接的p2p

    tcp连接通讯。

    事件总线提供了三种传递语法:第一种,send方法允许一个组件送一个消息到一个地址,

    单个消费者将接收它。假如不止一个消费者注册到这个地址,Vert.X将采用轮询策略来选择一个消费者:

    // Consumer

    vertx.eventBus().consumer("address",message -> {

             System.out.println("Received:'" + message.body() + "'");

    });

    // Sender

    vertx.eventBus().send("address","hello");

    与send不同,你可以用publish方法传递消息给所有注册在这个地址的消费者。

    最后,send方法能够带一个应答处理器,这个请求/响应机制允许两个组件间实现基于消息的异步交互:

    // Consumer

    vertx.eventBus().consumer("address",message -> {

             message.reply("pong");

    });

    // Sender

    vertx.eventBus().send("address","ping", reply -> {

             if(reply.succeeded()) {

                       System.out.println("Received:" + reply.result().body());

             }else {

                       //No reply or failure

                       reply.cause().printStackTrace();

             }

    });

    如果你用RX API,你能够用rxSend方法,它返回一个Single,当应用被收到时这个Single接收一个值。我们将很快看到这个方法。

    基于消息的微服务

    让我们重新实现hello微服务,这次用事件总线代替http server来接收请求。微服务应答消息、提供响应。

    创建工程

    让我们创建一个新工程。这次我们将加上Infnispan依赖,一个内存数据网格,被用来管理集群:

    mkdir hello-microservice-message

    cd hello-microservice-message

    mvn io.fabric8:vertx-maven-plugin:1.0.5:setup

    \

    -DprojectGroupId=io.vertx.microservice \

    -DprojectArtifactId=hello-microservice-message \

    -Dverticle=io.vertx.book.message.HelloMicroservice \

    -Ddependencies=infinispan

    一旦生成后,为了构建集群,我们需要配置Infinispan。缺省的配置是用组播的方式来发现节点。

    如果你的网络支持组播,就可以。否则,检查代码仓库的resource/cluster目录。

    写消息驱动的Verticle

    编辑src/main/java/io/vertx/book/message/HelloMicroservice.java文件,修改start方法:

    @Override

    public void start() {

             // Receive messagefrom the address 'hello'

             vertx.eventBus().consumer("hello",message -> {

             JsonObject json =new JsonObject()

             .put("served-by",this.toString());

             // Check whether wehave received a payload in the

             // incoming message

             if (message.body().isEmpty()){

                       message.reply(json.put("message","hello"));

             } else {

                       message.reply(json.put("message","hello" + message.body()));

             }

             });

    }

    这段代码从vertx对象获取事件总线(eventBus),注册一个消费者到地址hello。当接收到一个消息时,它应答它。取决于进来的消息是否有一个空的消息体,我们给以不同的响应。像前面章节的例子一样,我们返回一个json对象。你可能想知道为什么我们在json里面加了served-by。你很快就会明白为什么。现在verticle写好了,是时候启动它:

    mvn compile vertx:run \

    -Dvertx.runArgs="-cluster -Djava.net.preferIPv4Stack=true"

    -cluster选项告诉Vert.X以集群模式启动。

    现在让我们写一个微服务来消费这个服务。

    初始化基于消息的交互

    在这一节里,我们将创建另一个微服务来调用hello微服务,通过送一个消息到hello地址并获得应答。微服务将重新实现与前一章节同样的逻辑,调用服务两次。

    同样地,让我们创建一个新的工程:

    mkdir hello-consumer-microservice-message

    cd hello-consumer-microservice-message

    mvn io.fabric8:vertx-maven-plugin:1.0.5:setup

    \

    -DprojectGroupId=io.vertx.microservice \

    -DprojectArtifactId=hello-consumer-microservice-message \

    -Dverticle=io.vertx.book.message.HelloConsumerMicroservice \

    -Ddependencies=infinispan,rx

    这里我们也加了Vert.X RxJava以便于使用Vert.X提供的RX API。如果在前一节中你更改了Infinispan的配置,你需要拷贝它到这个新工程。

    现在编辑io.vertx.book.message.HelloConsumerMicroservice。因为我们打算用RxJava,改变相应的引入语句为io.vertx.rxjava.core.AbstractVerticle,然后实现start方法:

    @Override

    public void start() {

             EventBus bus =vertx.eventBus();

             Singleobs1 = bus

             .rxSend("hello","Luke")

             .map(Message::body);

             Singleobs2 = bus

             .rxSend("hello","Leia")

             .map(Message::body);

             Single.zip(obs1,obs2, (luke, leia) ->

                       newJsonObject()

                       .put("Luke",luke.getString("message"))

                       .put("Leia",leia.getString("message"))

             )

             subscribe(x ->System.out.println(x.encode()), Throwable::printStackTrace);

    }

    这段代码与前一章节是很类似的,替代用WebClient请求http,我们用事件总线发送消息到hello地址、获取应答内容。我们用zip操作获得两个响应并且构建最终的结果。在subscribe方法,我们打印最终结果到控制台或者是输出异常堆栈。

    让我们把这段代码和http server合并在一起,当接收到http请求时,我们调用hello服务两次、把构建结果作为响应返回:

    @Override

    public void start() {

             vertx.createHttpServer()

             .requestHandler(req-> {

             EventBus bus =vertx.eventBus();

             Singleobs1 = bus

             .rxSend("hello","Luke")

             .map(Message::body);

             Singleobs2 = bus

             .rxSend("hello","Leia")

             .map(Message::body);

             Single.zip(obs1,obs2, (luke, leia) ->

                       newJsonObject()

                       .put("Luke",luke.getString("message") + " from " +luke.getString("served-by"))

                       .put("Leia",leia.getString("message") + " from " +leia.getString("served-by"))

             )

             .subscribe(

                       x ->req.response().end(x.encodePrettily()),

                       t -> {

                                t.printStackTrace();

                                req.response().setStatusCode(500).end(t.getMessage());

                       }

             );

    })

    .listen(8082);

    这段代码仅仅是打包事件总线的交互到请求处理器(requestHandler)并且处理http响应。在失败的情况下,我们返回一个包含错误信息的json对象。

    如果你运行这段代码用

    mvn compile vertx:run -Dvertx.runArgs="-cluster-Djava.net.preferIPv4Stack=true"

    打开你的浏览器访问http://localhost:8082,你应该会看到像这样:

    {

    "Luke" : "hello Luke from ...HelloMicroservice@39721ab",

    "Leia" : "hello Leia from ...HelloMicroservice@39721ab"

    }

    现在是响应式吗?

    这段代码与我们前面写的基于http的微服务很类似,唯一的不同是我们用事件总线代替http。这改变了响应性?的确是,让我们看看为什么。

    弹性

    弹性是http版本的微服务没有的一个特性。因为微服务是被定位到一个指定的微服务实例(用硬编码的URL),它没有提供我们需要的弹性。但是我们现在采用送到一个地址的消息,这改变了游戏。让我们看看这个微服务系统的表现。

    记得前面执行的输出。返回的json对象显示verticle有处理hello消息。输出总是显示是同一个verticle。这个信息表明是同一个实例。我们预计这是因为我们只有一个实例在运行。现在让我们看看用两个实例将发生什么。

    停止hello微服务的vertx:run,运行:

    mvn clean package

    然后,打开两个不同的终端,在hello-microservice-message目录里执行下面的命令:

    java -jar target/hello-microservice-message-1.0-SNAPSHOT.jar \

    --cluster -Djava.net.preferIPv4Stack=true

    这将启动两个Hello微服务实例,返回到你的浏览器刷新页面你应该看到类似这样:

    {

    "Luke" : "hello Luke from...HelloMicroservice@16d0d069",

    "Leia" : "hello Leia from...HelloMicroservice@411fc4f"

    }

    两个Hello实例被调用。Vert.X集群连接不同的节点,事件总线也是被集群的。感谢事件总线轮循,Vert.X事件总线分发消息到可用的实例、在监听同一地址的不同节点间均衡负载。

    因此,通过用事件总线,我们有了我们所需要的弹性特征。

    可恢复性

    可恢复性又如何呢?在当前的代码中,如果hello微服务失败了,我们将得到一个失败、执行这个代码:

    t -> {

    t.printStackTrace();

    req.response().setStatusCode(500).end(t.getMessage());

    }

    尽管用户得到了错误信息,我们没有崩溃,我们没有限制伸缩性,仍然能够处理请求。然而,为了提升用户体验,我们应该总是在适当的时间内响应,即使我们没有从服务中接收到响应。实现这个逻辑,我们可以用timeout增加代码。

    为了展示,让我们修改hello微服务、注入失败。这段代码放在代码仓库的microservices/hello-microservice-faulty目录下。

    这个新的start方法随机地选择3个策略中的一个:1. 用一个显示的失败响应,2.忘了响应,3.发送正确的结果:

    @Override

    public void start() {

    vertx.eventBus().consumer("hello", message-> {

    double chaos = Math.random();

    JsonObject json = new JsonObject().put("served-by",this.toString());

    if (chaos < 0.6) {

    // Normal behavior

    if (message.body().isEmpty()) {

    message.reply(json.put("message", "hello"));

    } else {

    message.reply(json.put("message", "hello "+message.body()));

    }

    } else if (chaos < 0.9) {

    System.out.println("Returning a failure");

    // Reply with a failure

    message.fail(500, "message processing failure");

    } else {

    System.out.println("Not replying");

    // Just do not reply, leading to a timeout on the

    // consumer side.

    }

    });

    }

    重新打包并重启两个hello微服务的实例。

    使用这个故障注入的服务,我们需要改进消费方的容错性。事实上,消费方可能得到超时或是接收到一个显示的失败。在hello消费者微服务里,改变请求hello服务的代码为:

    EventBus bus = vertx.eventBus();

    Single obs1 = bus

    .rxSend("hello", "Luke")

    .subscribeOn(RxHelper.scheduler(vertx))

    .timeout(3, TimeUnit.SECONDS)

    .retry()

    .map(Message::body);

    Single obs2 = bus.

    rxSend("hello", "Leia")

    .subscribeOn(RxHelper.scheduler(vertx))

    .timeout(3, TimeUnit.SECONDS)

    .retry()

    .map(Message::body);

    这段代码放在代码仓库的microservices/hello-consumer-microservice-timeout目录下。如果有给定的时间内没有接收到响应,timeout方法发出一个失败。如果得到一个超时失败或是一个显示的失败,retry方法将试图重试去获取值。subScribeOn方法指明请求需要在哪一个线程上执行。我们用Vert.X事件轮循器来调用callback。没有指定的话,方法将被从缺省的RxJava线程池中取一个线程来执行,破坏了Vert.X的线程模式。RxHelper类是Vert.X提供的。盲目地重试服务调用不是明智的容错策略,它甚至可能是有害的。下一章节阐述不同的方法。

    现在你可以重新加载页面。你总能获得一个结果,即使是失败或者超时。记住当调用服务时线程是不阻塞的,因此,你总是能够接收新的请求、在一个合适的时间内响应。然而,超时重试经常是有害而不是有益,正如我们在下一章节将看到的那样。

    小结

    在这一章节,我们学习了怎样用Vert.X开发一个http微服务,怎样消费它。正如我们所学的,在代码里硬编码被消费服务的URL不是一个明智的主意,因为它破坏了响应式特征之一。在第二部分,我们用消息替换http交互,这展示了消息和Vert.X事件总线怎样构建响应式微服务。

    那么,现在是yes还是no。是的,我们知道怎样构建响应式微服务,但是,这里仍然有一些我们需要关注的缺点:首先,如果你仅仅有http服务,你怎样避免硬编码位置?可恢复性呢?在这一章节我们已经看到了超时和重试,但是熔断器(circuit breaker)、故障转移(failover)、隔仓(bulkhead)呢?让我们继续我们的旅程。

    如果你想更深入这些topic:

    . Vert.X Web文档(http://vertx.io/docs/vertx-web/java)

    . Vert.X Web客户端文档(http://vertx.io/docs/vertx-web-client/java)

    . Vert.X响应式微服务

    相关文章

      网友评论

        本文标题:用Java构建响应式微服务3-构建响应式微服务

        本文链接:https://www.haomeiwen.com/subject/wwqclftx.html