简体   繁体   English

为什么Spring MVC json序列化比手动调用jackson慢10倍?

[英]Why is Spring MVC json serialization 10x slower than calling jackson manually?

Using apachebench with "ab -k -c 50 -n 1000000" options (50 concurrent threads) shows a 10x performance difference between the following 2 methods (manual and spring-managed serialization). 将apachebench与“ ab -k -c 50 -n 1000000”选项(50个并发线程)一起使用时,在以下两种方法(手动和弹簧管理的序列化)之间的性能差异为10倍。 Is it possible to achieve the same performance via configuration of Spring serialization? 通过配置Spring序列化可以实现相同的性能吗?

I'm running the test on Windows 7, JDK8, i7-6700. 我正在Windows 7,JDK8,i7-6700上运行测试。 Embedded Tomcat , similar results with Undertow or Jetty too. 嵌入式Tomcat ,与UndertowJetty相似的结果。 A similar WildFly 10 JAX-RS sample apps performance yields similar results as the manual spring one, so I see no reason why Spring automatic mode should be so slow. 类似的WildFly 10 JAX-RS样本应用程序性能所产生的结果与手动spring相似,因此我认为没有理由说明Spring自动模式应该这么慢。

Full source code: 完整的源代码:

@SpringBootApplication
@Controller
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

  ObjectMapper mapper = new ObjectMapper(new JsonFactory());

  @RequestMapping(value = "/auto", produces = "application/json; charset=utf-8")
  @ResponseBody
  public Lol automaticSerialization() {

    Lol lol = new Lol();
    lol.a = UUID.randomUUID().toString();
    lol.b = System.currentTimeMillis();

    return lol;
  }

  @RequestMapping(value = "/manual", produces = "application/json; charset=utf-8")
  @ResponseBody
  public String manualSerialization() throws JsonProcessingException {

    Lol lol = new Lol();
    lol.a = UUID.randomUUID().toString();
    lol.b = System.currentTimeMillis();

    return mapper.writeValueAsString(lol);
  }

  public static class Lol {

    String a;
    long b;

    public void setA(String a) {
      this.a = a;
    }

    public void setB(long b) {
      this.b = b;
    }

    public String getA() {
      return a;
    }

    public long getB() {
      return b;
    }
  }

}

Edit: Trace of automatic serialization: 编辑:自动序列化的跟踪: 跟踪自动序列化

Trace of manual serialization: 手动序列化的痕迹: 手动序列化的痕迹

The only idea that I have is that Spring's default ObjectMapper is configured a bit differently than the one you use in your benchmark. 我唯一的想法是,Spring的默认ObjectMapper的配置与您在基准测试中使用的配置有所不同。 Like the comments mention, you'd probably see a bit of overhead if you let Spring handle the mapping automatically but it shouldn't have more than a few percent's worth of impact. 就像提到的评论一样,如果让Spring自动处理映射,您可能会看到一些开销,但是影响不应该超过百分之几。

To be sure that the comparison is fair, add this bean definition to your configuration: 为了确保比较是公平的,请将以下bean定义添加到您的配置中:

@Bean
@Primary
ObjectMapper objectMapper() {
    return new ObjectMapper(new JsonFactory());
}

and replace ObjectMapper mapper = new ObjectMapper(new JsonFactory()); 并替换ObjectMapper mapper = new ObjectMapper(new JsonFactory()); with an autowired field: 具有自动连接的字段:

@Autowired
ObjectMapper mapper;

and see if the benchmarks return the same value. 并查看基准是否返回相同的值。

EDIT 编辑

I wanted to verify this for myselt so I wrote a JMeter plan and executed each endpoint exactly 5kk times, with a 1-minute warm-up period. 我想为自己进行验证,因此我编写了一个JMeter计划,并在5分钟内准确地执行了每个端点,预热了1分钟。 The results were as expected, no major differences between the approaches: 结果符合预期,两种方法之间没有重大差异:

Label,# Samples,Average,Min,Max,Std. Dev.,Error %,Throughput,KB/sec,Avg. Bytes
Auto Request,5000000,2,0,108,5.88,0.00%,15577.3,3088.08,203.0
Manual Request,5000000,2,0,149,5.99,0.00%,15660.2,2813.94,184.0

The important thing to note is the throughput difference - auto's 15577.3 vs. manual's 15660.2. 要注意的重要一点是吞吐量的差异-自动的15577.3与手动的15660.2。

Here's my JMeter test plan , if you'd like to test it yourself, I was running on port 8081. If I find the time, I'll try another benchmarking framework, perhaps Gatling. 这是我的JMeter测试计划 ,如果您想自己测试,我正在8081端口上运行。如果有时间,我将尝试另一个基准测试框架,也许是加特林。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM