java - 如何防止 Spring Boot Tomcat Jackson 中的 flushBuffer 并发锁定?
问题描述
从部署到 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());
}
我正在使用 Spring Boot 1.5.4 Java 1.8 Jackson 2.9.7 Tomcat 8.5.33
解决方案
查看源代码,UTF8JsonGenerator._flushBuffer()
没有任何提示LockSupport.parkNanos()
。所以它可能已经被 JIT 编译器从OutputStream.write()
.
我的猜测是,对于您的应用程序,Tomcat 通常会等待,直到客户端接受了所有输出(除了适合典型连接缓冲区大小的最后一部分),然后它才能关闭连接。
过去,我们对慢速客户有过不好的经历。在他们检索到所有输出之前,他们会阻塞 Tomcat 中的一个线程。在 Tomcat 中阻塞几十个线程会严重降低繁忙 Web 应用程序的吞吐量。
增加线程数并不是最好的选择,因为阻塞的线程也占用了大量的内存。所以你想要的是Tomcat可以尽快处理一个请求,然后继续下一个请求。
我们通过配置我们的反向代理解决了这个问题,我们总是在 Tomcat 前面使用它来立即消耗来自 Tomcat 的所有输出并以客户端的速度将其传递给客户端。反向代理在处理慢速客户端方面非常有效。
在我们的例子中,我们使用了nginx。我们还查看了Apache httpd。但在当时,它没有能力做到这一点。
附加说明
意外断开连接的客户端对于服务器来说也看起来像慢速客户端,因为它需要一些时间才能完全确定连接已断开。
推荐阅读
- python - 在重复键上添加计数以进行合并
- java - 如何将字节数组存储到 Java 中的 SQL Server varbinary(MAX) 字段中?
- python - selenium size['width'] 为元素返回零
- corda - API调用出错:事务哈希的附件解析失败
- amazon-web-services - 如何通过 ebextensions 覆盖 Elastic Beanstalk 环境变量?
- rust - 有没有办法检查用户是否使用 text_io 的 read!() 宏输入了一个整数?
- python - 如何区分 Django 中的帐户类型?
- shell - 将日志文件中的字符串路径替换为当前文件夹名称
- java - 使用 java 8 流在 2 个列表中查找元素匹配并从另一个列表值更新一个列表值
- javascript - this.functionName 不是函数错误