带有非流应用程序/json的Spring WebFlux Flux行为 [英] Spring WebFlux Flux behavior with non streaming application/json

查看:151
本文介绍了带有非流应用程序/json的Spring WebFlux Flux行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring Webflux进行评估,但我们必须支持希望使用application/json而不是application/stream + json的客户端.我不清楚在需要application/json的客户端中,Spring WebFlux如何处理序列化Flux.

I am evaluating using Spring Webflux but we have to support clients that expect application/json, not application/stream+json. I am unclear how Spring WebFlux handles serializing a Flux in the case of a client that needs application/json.

如果将Flux序列化为application/json而不是application/stream + json,这是否是阻塞操作?

If a Flux is being serialized as application/json rather than application/stream+json is it a blocking operation?

下面,我整理了一个示例控制器来演示我所看到的.当流是无限的并且产生application/json时,什么都不会返回到浏览器.这似乎很合理,因为它可能正在等待流终止.当流是无限的并产生application/stream + json时,我会按预期在浏览器中连续看到JSON对象.当Flux是有限的(例如100个元素)并且类型为application/json时,它将一次按预期呈现.问题是,它是否必须等待Flux终止才能进行序列化,是否会导致阻塞操作.返回正常的application/json时,使用Flux对性能和可伸缩性有什么影响?

Below I've put together a sample controller to demonstrate what I am seeing. When the stream is infinite and produces application/json nothing is returned to browser. This seems reasonable as it is probably waiting on the stream to terminate. When the stream is infinite and produces application/stream+json I see JSON objects continuously in the browser as expected. When the Flux is finite, at say 100 elements, and the type is application/json it renders as expected all at once. The question is, does it have to wait for the Flux to terminate before serializing, and does that cause a blocking operation. What are the implications to performance and scalability using Flux when returning normal application/json?

@RestController
public class ReactiveController {

    /* Note: In the browser this sits forever and never renders */
    @GetMapping(path = "/nonStreaming", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Person> getPeopleNonStreaming() {
        return Flux.interval(Duration.ofMillis(100))
                .map(tick -> new Person("Dude", "Dude", tick));
    }

    /* Note: This renders in the browser in chunks forever */
    @GetMapping(path = "/streaming", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux<Person> getPeopleStreaming() {
        return Flux.interval(Duration.ofMillis(100))
                .map(tick -> new Person("Dude", "Dude", tick));
    }

    /* Note: This returns, but I can't tell if it is done in a non blocking manner. It
     * appears to gather everything before serializing. */
    @GetMapping(path = "/finiteFlux", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Person> finiteFlux() {
        return Flux.range(0, 100)
                .map(tick -> new Person("Dude", "Dude", tick));
    }
}

更新:

我在下面添加了其他日志记录信息:

I've added additional logging information below:

流式传输似乎正在使用两个不同的线程

The streaming appears to be using two different threads

2019-02-13 16:53:07.363 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [dac80fd4] HTTP GET "/streaming"
2019-02-13 16:53:07.384 DEBUG 3416 --- [ctor-http-nio-2] s.w.r.r.m.a.RequestMappingHandlerMapping : [dac80fd4] Mapped to public reactor.core.publisher.Flux<io.jkratz.reactivedemo.Person> io.jkratz.reactivedemo.ReactiveController.getPeopleStreaming()
2019-02-13 16:53:07.398 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.r.r.m.a.ResponseBodyResultHandler  : Using 'application/stream+json;q=0.8' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [application/stream+json]
2019-02-13 16:53:07.398 DEBUG 3416 --- [ctor-http-nio-2] o.s.w.r.r.m.a.ResponseBodyResultHandler  : [dac80fd4] 0..N [io.jkratz.reactivedemo.Person]
2019-02-13 16:53:07.532 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@6b3e843d]
2019-02-13 16:53:07.566 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/stream+json;q=0.8;charset=UTF-8
2019-02-13 16:53:07.591 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.629 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@217d62db]
2019-02-13 16:53:07.630 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.732 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@741c0c88]
2019-02-13 16:53:07.732 DEBUG 3416 --- [ctor-http-nio-2] r.n.channel.ChannelOperationsHandler     : [id: 0xdac80fd4, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52398] Writing object 
2019-02-13 16:53:07.832 DEBUG 3416 --- [     parallel-1] o.s.http.codec.json.Jackson2JsonEncoder  : [dac80fd4] Encoding [io.jkratz.reactivedemo.Person@7b8532e5]

使用JSON的有限方法仅使用一个线程.

While the finite with JSON is only using a single thread.

2019-02-13 16:55:34.431 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [5b048f46] HTTP GET "/finiteFlux"
2019-02-13 16:55:34.432 DEBUG 3416 --- [ctor-http-nio-3] s.w.r.r.m.a.RequestMappingHandlerMapping : [5b048f46] Mapped to public reactor.core.publisher.Flux<io.jkratz.reactivedemo.Person> io.jkratz.reactivedemo.ReactiveController.finiteFlux()
2019-02-13 16:55:34.434 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.r.r.m.a.ResponseBodyResultHandler  : Using 'application/json;q=0.8' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [application/json]
2019-02-13 16:55:34.435 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.r.r.m.a.ResponseBodyResultHandler  : [5b048f46] 0..N [io.jkratz.reactivedemo.Person]
2019-02-13 16:55:34.439 DEBUG 3416 --- [ctor-http-nio-3] o.s.http.codec.json.Jackson2JsonEncoder  : [5b048f46] Encoding [[io.jkratz.reactivedemo.Person@425c8296, io.jkratz.reactivedemo.Person@22ae73df, io.jkratz.reactived (truncated)...]
2019-02-13 16:55:34.448 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/json;q=0.8;charset=UTF-8
2019-02-13 16:55:34.448 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object 
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [5b048f46] Completed 200 OK
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Last HTTP response frame
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Writing object EmptyLastHttpContent
2019-02-13 16:55:34.450 DEBUG 3416 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] Decreasing pending responses, now 0
2019-02-13 16:55:34.451 DEBUG 3416 --- [ctor-http-nio-3] r.n.channel.ChannelOperationsHandler     : [id: 0x5b048f46, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:52991] No ChannelOperation attached. Dropping: EmptyLastHttpContent

推荐答案

对于流式模仿类型(application/stream+json),Spring WebFlux中默认配置的JSON编解码器将序列化为JSON并在网络上刷新每个元素Flux输入的值.当流无限或要在可用时将信息推送到客户端时,此行为很方便.请注意,这会降低性能,因为调用序列化程序并多次刷新会占用资源.

In the case of a streaming mimetype (application/stream+json), the JSON codec configured by default in Spring WebFlux will serialize to JSON and flush on the network each element of the Flux input. This behavior is handy when the stream is infinite, or when you want to push information to the client as soon as it's available. Note that this has a performance cost, as calling the serializer and flushing multiple times takes resources.

对于非流传输类型(application/json),在Spring WebFlux中默认配置的JSON编解码器将序列化为JSON并一次性刷新到网络.它将Flux<YourObject>缓冲在内存中,并在一次通过中将其序列化. 这并不意味着操作正在阻塞,因为结果Flux<Databuffer>以反应方式写入网络.这里没有任何障碍.

In the case of a non-streaming type (application/json), the JSON codec configured by default in Spring WebFlux will serialize to JSON and flush to the network in one go. It will buffer the Flux<YourObject> in memory and serialize it in one pass. This doesn't mean the operation is blocking, since the resulting Flux<Databuffer> is written in a reactive fashion to the network. nothing is blocking here.

这只是流数据和使用更多资源"与缓冲和更有效地使用资源"之间的折衷.

This is just a tradeoff between "streaming data and using more resources" vs. "buffering and using resources more efficiently".

在流式传输的情况下,由于工作项在不同的时间间隔可用,因此更有可能由不同的工作线程处理事物.对于简单的JSON响应-它也可能由一个或多个线程处理:无论远程客户端运行缓慢与否,都取决于有效负载大小.

In the case of streaming, things are more likely to be processed by different worker threads, since work items are available at different intervals. In the case of the simple JSON response - it might be processed by one or more threads as well: it depends on the payload size, if the remote client is slow or not.

这篇关于带有非流应用程序/json的Spring WebFlux Flux行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆