生菜RedisCache抛出java.util.concurrent.RejectedExecutionException超出线程限制,替换了阻塞的工作程序

时间:2019-01-28 13:51:46

标签: java spring-boot spring-data-redis lettuce

我正在使用带有Redis-Cache的Spring Boot,具有Lettuce的默认配置,并在服务器启动几分钟后收到以下RejectedExecutionException:

org.springframework.data.redis.RedisSystemException: Unknown redis exception; nested exception is java.util.concurrent.RejectedExecutionException: Thread limit exceeded replacing blocked worker
        at org.springframework.data.redis.FallbackExceptionTranslationStrategy.getFallback(FallbackExceptionTranslationStrategy.java:53)
        at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:43)
        at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:257)
        at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.convertLettuceAccessException(LettuceStringCommands.java:718)
        at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.get(LettuceStringCommands.java:63)
        at org.springframework.data.redis.connection.DefaultedRedisConnection.get(DefaultedRedisConnection.java:210)
        at org.springframework.data.redis.cache.DefaultRedisCacheWriter.lambda$get$1(DefaultRedisCacheWriter.java:109)
        at org.springframework.data.redis.cache.DefaultRedisCacheWriter.execute(DefaultRedisCacheWriter.java:242)
        at org.springframework.data.redis.cache.DefaultRedisCacheWriter.get(DefaultRedisCacheWriter.java:109)
        at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:82)
        at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
        at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
        at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:525)
        at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:490)
        at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:372)
        at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:316)
        at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
        at my.controller.MyController.lambda$myFunc$0(MyController.java:60)
        at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
        at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.util.concurrent.RejectedExecutionException: Thread limit exceeded replacing blocked worker
        at java.util.concurrent.ForkJoinPool.tryCompensate(ForkJoinPool.java:2011)
        at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3310)
        at java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1775)
        at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1915)
        at io.lettuce.core.protocol.AsyncCommand.await(AsyncCommand.java:81)
        at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:112)
        at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:62)
        at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
        at com.sun.proxy.$Proxy168.get(Unknown Source)
        at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.get(LettuceStringCommands.java:61)
        ... 21 common frames omitted

Lettuce似乎使用了常见的ForkJoinPool,DeferredResult也使用了它,并且所有请求和连接都使池阻塞(如果我错了,请纠正我)。推荐的方法是什么?我应该将生菜移到另一个池中吗?如果可以,怎么办?如果可以提供其他配置或其他信息,请告诉我。

1 个答案:

答案 0 :(得分:1)

Lettuce使用Netty的EventLoop作为其线程基础结构。

这里发生的是您的任务在ForkJoin池中执行。 Lettuce使用CompletableFuture来返回异步结果处理的句柄,同步API调用CompletableFuture.get(timeout, TimeUnit)来等待命令完成。在ForkJoin池上调用阻塞方法需要ManagedBlocker潜在地切换到可以继续工作的其他线程。

如果等待命令完成的线程过多,您最终将以RejectedExecutionException结尾。

我建议您对要调用的lambda使用不同的执行池。