FasterXML / FasterXML/jackson-module-scala

Many threads blocked in LRUMap (with `ScalaObjectMapper`) -- increase type cache size?

Aperta
#428 15 commenti 1 reazione 0 assegnatari Vedi su GitHub
Lingua principale
Scala
Stelle
506
Fork
138
Merge medio
3h 6m
PR unite (30g)
48

Descrizione

(NOTE: moved from `jackson-databind` on 11-Sep-2019 by @cowtowncoder )

Version: Jackson 2.8.11, probably also 2.9.7

We have an API server that receives requests then makes ElasticSearch requests using the elastic4s library. The JSON parsing is done using Jackson under the hood. We’ve noticed a lot of threads blocked on the synchronized blocks in the `LRUMap` data structure, which seems to be contributing to slow performance on our API server.

Several threads are blocked on puts to the map, for example:

```
java.lang.Thread.State: BLOCKED (on object monitor)
at com.fasterxml.jackson.databind.util.LRUMap.putIfAbsent(LRUMap.java:58)
- waiting to lock <0x0000000629be2270> (a com.fasterxml.jackson.databind.util.LRUMap)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1287)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory.constructMapLikeType(TypeFactory.java:807)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:68)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.$anonfun$constructType$1(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$$Lambda$2573/1098099028.apply(Unknown Source)
at scala.collection.immutable.List.map(List.scala:286)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.$anonfun$constructType$1(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$$Lambda$2573/1098099028.apply(Unknown Source)
at scala.collection.immutable.List.map(List.scala:286)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.$anonfun$constructType$1(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$$Lambda$2573/1098099028.apply(Unknown Source)
at scala.collection.immutable.List.map(List.scala:286)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.readValue(ScalaObjectMapper.scala:190)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.readValue$(ScalaObjectMapper.scala:189)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.readValue(JacksonSupport.scala:11)
at com.sksamuel.elastic4s.http.ResponseHandler$.fromEntity(ResponseHandler.scala:34)
at models.es.ESHttpClientBackend$GetMappingHttpExecutable$$anon$1.handle(ESHttpClientBackend.scala:575)
at com.sksamuel.elastic4s.http.HttpClient.$anonfun$execute$1(HttpClient.scala:62)
at com.sksamuel.elastic4s.http.HttpClient$$Lambda$2539/1265612311.apply(Unknown Source)
at scala.util.Success.$anonfun$map$1(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
at scala.concurrent.Future$$Lambda$1146/1816269091.apply(Unknown Source)
at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
at scala.concurrent.impl.Promise$$Lambda$609/1310865036.apply(Unknown Source)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
```

and another thread blocked on `clear()`:

```
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.concurrent.ConcurrentHashMap.clear(ConcurrentHashMap.java:1193)
- locked <0x0000000625710000> (a java.util.concurrent.ConcurrentHashMap$TreeBin)
at com.fasterxml.jackson.databind.util.LRUMap.clear(LRUMap.java:70)
at com.fasterxml.jackson.databind.util.LRUMap.putIfAbsent(LRUMap.java:60)
- locked <0x0000000629be2270> (a com.fasterxml.jackson.databind.util.LRUMap)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1287)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1396)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1400)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1165)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1311)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1254)
at com.fasterxml.jackson.databind.type.TypeFactory.constructMapLikeType(TypeFactory.java:807)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:68)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.$anonfun$constructType$1(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$$Lambda$2573/1098099028.apply(Unknown Source)
at scala.collection.immutable.List.map(List.scala:286)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType(ScalaObjectMapper.scala:64)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.constructType$(ScalaObjectMapper.scala:56)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.constructType(JacksonSupport.scala:11)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.readValue(ScalaObjectMapper.scala:190)
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper.readValue$(ScalaObjectMapper.scala:189)
at com.sksamuel.elastic4s.json.JacksonSupport$$anon$1.readValue(JacksonSupport.scala:11)
at com.sksamuel.elastic4s.http.ResponseHandler$.fromEntity(ResponseHandler.scala:34)
at models.es.ESHttpClientBackend$GetMappingHttpExecutable$$anon$1.handle(ESHttpClientBackend.scala:575)
at com.sksamuel.elastic4s.http.HttpClient.$anonfun$execute$1(HttpClient.scala:62)
at com.sksamuel.elastic4s.http.HttpClient$$Lambda$2539/1265612311.apply(Unknown Source)
at scala.util.Success.$anonfun$map$1(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
at scala.concurrent.Future$$Lambda$1146/1816269091.apply(Unknown Source)
at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
at scala.concurrent.impl.Promise$$Lambda$609/1310865036.apply(Unknown Source)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
```

Based on heap dumps, we see that the `_typeCache` map in `TypeFactory` is getting filled up quickly with type information for the JSON objects we’re parsing, then the map is getting cleared, then the process is repeated quickly. Since the `clear()` operation is relatively expensive and inside a synchronized block, it blocks all other threads from making progress, and this can happen repeatedly in a short period of time.

We could replace the `ConcurrentHashMap` with a synchronized `LinkedHashMap` with an LRU eviction policy, and/or increase the size of the cache. Either way, clearing the cache seems like an inefficient solution, especially when many threads are trying to use the cache.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.