如何防止Spring Boot Tomcat Jackson中并发锁定flushBuffer?

时间:2018-11-12 20:34:49

标签: java spring spring-boot tomcat jackson

从部署到Tomcat 8的Spring Boot WAR应用程序写JSON时,我在并发性方面遇到问题。在AppDynamics的屏幕快照中,当杰克逊库执行_flushBuffer时,似乎要等待很长时间。

即使是少量(<10)用户,在负载测试下也会出现此问题。

我已经在我的配置类中配置了messageConverters。

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter(
            new Jackson2ObjectMapperBuilder().dateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ")).mixIn(LiquidAssignment.class,
                    InventoryProviderAssignmentMixin.class)
                    .deserializerByType(ActionData.class, new ActionDataDeserializer()).build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter());
    }

我正在使用 春季启动1.5.4 Java 1.8 杰克逊2.9.7 Tomcat 8.5.33

AppDynamics screenshot

1 个答案:

答案 0 :(得分:1)

看着UTF8JsonGenerator._flushBuffer()的{​​{3}},没有LockSupport.parkNanos()的指示。因此,OutputStream.write()的JIT编译器可能已经内联了它。

我的猜测是-对于您的应用程序-Tomcat通常在它可以关闭连接之前,等待客户端接受所有输出(期望最后一个适合典型连接缓冲区大小的输出)。

过去,我们在处理慢速客户方面经验很差。在获取所有输出之前,它们将阻塞Tomcat中的线程。并且在Tomcat中阻塞几十个线程会严重降低繁忙的Web应用程序的吞吐量。

增加线程数量不是最佳选择,因为被阻塞的线程也占用大量内存。因此,您想要的是Tomcat可以尽快处理请求,然后继续下一个请求。

我们已经解决了这个问题,方法是配置反向代理(我们一直在Tomcat前面),以立即使用Tomcat的所有输出并将其以客户机的速度传递给客户机。反向代理在处理慢速客户端方面非常有效。

在我们的例子中,我们使用了 nginx 。我们还查看了 Apache httpd 。但是当时,它无法做到这一点。

附加说明

意外断开连接的客户端对于服务器来说也似乎是缓慢的客户端,因为它需要一些时间才能完全确定连接断开。