2016-06-22 4 views
0

私が奇妙な動作に遭遇したときに私のSpring Boot 1.3.5アプリケーションをロードテストしていました。例えば5000リクエスト/秒への要求数が増加すると、スレッドはJacksonのSerializerCacheでブロックを開始しました。ここJProfilerをが私に語ったものだ/statusエンドポイントでの同時要求の束を投げる際にJacksonのSerializerCacheでスレッドがブロックされています

@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; 
    } 
    } 
} 

:最初に私はそれが私の側にいくつかの設定ミスかもしれないと思ったので、私は新鮮な、最小限のアプリケーションを作成し

JProfiler私は、スレッドダンプを取って、ほとんどすべてのスレッドが、この時に立ち往生している:

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) 

Iジャクソンがシリアライザを毎回作成するように見えるので、これは起こっていると私は奇妙に思えます。この現象の原因は何ですか?これはジャクソンやスプリングブーツの側にありますか(または私は本当に設定を変更しませんでしたが)? Jacksonバージョンは2.6.6(Spring Boot 1.3.5のデフォルト)です。

+0

これはどのバージョンのジャクソンですか? 2.4以前では、理想的にはSpringブートのデフォルトである2.7(.5) – StaxMan

+0

2.6.6にアップグレードすることをお勧めします。 –

答えて

1

Jacksonはリクエストごとに新しいシリアライザを作成していません。その特定の行は、単純なのための小さな同期ブロックですgetルックアップからHashMap。スレッドが競合するのに十分長い間、その同期を維持することは奇妙に思えるでしょう。だから、これがプロファイリングのアーティファクトかもしれないのだろうか。

しかし、ObjectMapperが最初のスレッドによって呼び出された後、そのメソッド自体はあまり呼び出されません。最初のルックアップが成功した後、シリアライザが共有マップに追加されますが、さらに生成されるSerializerProviderは、新しくバインドされたシリアライザで読み取り専用コピーを取得する必要があります。だから、なぜそれが継続的にアクセスされるのか困惑しています。

おそらくjackson-databind号の問題追跡ツールで問題を提出できますか? 2.6は、2.7で動作する可能性があります。

+0

ありがとうございました。私はhttps://github.com/FasterXML/jackson-databind/issues/1275で公開しました。 –

+0

問題は2.7.xで解決されたようです。シンプルなテストでは、同期呼び出しは最初のアクセスに対してのみ発生することが示されました。だから状況ははるかに良いはずです。 – StaxMan

関連する問題