vendredi 24 juin 2016

Threads getting blocked in Jackson's SerializerCache

I was load-testing my Spring Boot 1.3.5 application when I came across an odd behaviour. Upon increasing the number of requests to, say, 5000 requests/second, threads started to block on Jackson's SerializerCache. At first I thought it could be some misconfiguration on my side, so I created a fresh, minimal application: @SpringBootApplication public class DojoRestApplication { public static void main(String[] args) { SpringApplication.run(DojoRestApplication.class, args); } @RestController public static final class StatusController { @RequestMapping(method = GET, path = "/status", produces = "application/json") public ResponseEntity<ApplicationStatus> get() { final ApplicationStatus result = new ApplicationStatus(); result.setTimestamp(Instant.now()); result.setVersion("1.0.0"); return ResponseEntity.ok(result); } } public static final class ApplicationStatus { private Instant timestamp; private String version; public Instant getTimestamp() { return timestamp; } public String getVersion() { return version; } public void setTimestamp(Instant timestamp) { this.timestamp = timestamp; } public void setVersion(String version) { this.version = version; } } } Upon throwing a bunch of simultaneous requests at the /status endpoint here's what JProfiler tells me: I took a thread dump and almost all the threads are stuck at this: com.fasterxml.jackson.databind.ser.SerializerCache.untypedValueSerializer(java.lang.Class) (line: 84) com.fasterxml.jackson.databind.SerializerProvider._findExplicitUntypedSerializer(java.lang.Class) (line: 1124) com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.hasSerializerFor(java.lang.Class, java.util.concurrent.atomic.AtomicReference) (line: 422) com.fasterxml.jackson.databind.ObjectMapper.canSerialize(java.lang.Class, java.util.concurrent.atomic.AtomicReference) org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canWrite(java.lang.Class, org.springframework.http.MediaType) (line: 178) org.springframework.http.converter.AbstractGenericHttpMessageConverter.canWrite(java.lang.reflect.Type, java.lang.Class, org.springframework.http.MediaType) org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse) (line: 215) org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest) (line: 183) org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest) (line: 81) org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(org.springframework.web.context.request.ServletWebRequest, org.springframework.web.method.support.ModelAndViewContainer, java.lang.Object[ ]) (line: 126) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.web.method.HandlerMethod) (line: 832) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.web.method.HandlerMethod) (line: 743) org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object) org.springframework.web.servlet.DispatcherServlet.doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 961) org.springframework.web.servlet.DispatcherServlet.doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 895) org.springframework.web.servlet.FrameworkServlet.processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 967) org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 858) javax.servlet.http.HttpServlet.service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 622) org.springframework.web.servlet.FrameworkServlet.service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 843) javax.servlet.http.HttpServlet.service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 729) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 292) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.apache.tomcat.websocket.server.WsFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 52) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.springframework.web.filter.RequestContextFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 99) org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 87) org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 77) org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 121) org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240) org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207) org.apache.catalina.core.StandardWrapperValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 212) org.apache.catalina.core.StandardContextValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 106) org.apache.catalina.authenticator.AuthenticatorBase.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 502) org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 141) org.apache.catalina.valves.ErrorReportValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 79) org.apache.catalina.core.StandardEngineValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 88) org.apache.catalina.connector.CoyoteAdapter.service(org.apache.coyote.Request, org.apache.coyote.Response) (line: 522) org.apache.coyote.http11.AbstractHttp11Processor.process(org.apache.tomcat.util.net.SocketWrapper) (line: 1095) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(org.apache.tomcat.util.net.SocketWrapper, org.apache.tomcat.util.net.SocketStatus) (line: 672) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun() (line: 1502) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run() (line: 1458) java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) (line: 1142) java.util.concurrent.ThreadPoolExecutor$Worker.run() (line: 617) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() (line: 61) java.lang.Thread.run() (line: 745) It seems strange to me that this is happening, as it looks like Jackson is creating a serializer every single request or something. What can be causing this behaviour? Is this on Jackson's or Spring Boot's side (or mine, though I didn't really change any config)? The Jackson version in use is 2.6.6 (Spring Boot 1.3.5's default).

Aucun commentaire:

Enregistrer un commentaire