1、背景

在我们的项目中有这么一个场景,需要消费kafka中的消息,并生成对应的工单数据。早些时候程序运行的好好的,但是有一天,我们升级了容器的配置,结果导致部分消息无法消费。而消费者的代码是使用CompletableFuture.runAsync(() -> {while (true){ ..... }}) 来实现的。

即:

  1. 需要消费Kafka topic的个数: 7个,每个线程消费一个topic
  2. 消费方式:使用线程池异步消费
  3. 消费池:默认的 ForkJoin 线程池???,并且没有做任何配置
  4. 是否会释放线程池中的核心线程: 不会释放
  5. 没出问题时容器配置: 2核4G
  6. 出问题时容器配置:4核8G,影响的结果:只有3个topic的数据可以消费。

2、容器2核4G可以正常消费

即:此时程序会启动7个线程来进行消费。

3、容器4核8G只有部分可以消费

即:此时程序会启动3个线程来进行消费。

4、问题原因分析

1、通过上面的背景我们可以知道,是因为升级了容器的配置,才导致我们消费kafka中的消息失败了。

2、针对kafka中的每个topic,我们都会使用一个单独的线程来消费,并且不会释放这个线程。

3、而线程的启动方式是通过CompletableFuture.runAsync()方法来启动的,那么通过这种方式启动的线程,是每个任务一个启动一个线程,还是只启动固定的线程呢?.

通过以上分析,那么问题肯定是出现在线程池身上,那么我们默认使用的是什么线程池呢?查看CompletableFuture.runAsync()的源码可知,有一定的几率是ForkJoinPool。那么我们一起看下源码。

5、源码分析

1、确认使用什么线程池

public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

通过上述源码可知,我们可能使用的ForkJoin线程池,也可能使用的是ThreadPerTaskExecutor线程池。

  1. ThreadPerTaskExecutor 这个是每个任务,一个线程。
  2. ForkJoinPool 那么就需要确定启动了多少个线程。

2、确认是否使用 ForkJoin 线程池

需要确定 useCommonPool 字段是如何赋值的。

private static final boolean useCommonPool =
(ForkJoinPool.getCommonPoolParallelism() > 1);

通过上面代码可知,是否使用ForkJoin线程池,是由 ForkJoinPool.getCommonPoolParallelism()的值确定的。(即并行度是否大于1,大于则使用ForkJoin线程池)

public static int getCommonPoolParallelism() {
return commonParallelism;
}

3、commonParallelism 的赋值

1、从上图中可知parallelism的设置有2种方式

  • 通过Jvm的启动参数java.util.concurrent.ForkJoinPool.common.parallelism进行设置,且这个值最大为 MAX_CAP即32727。
  • 若没有通过Jvm的参数配置,则有2种情况,若cpu的核数<=1,则返回1,否则返回cpu的核数-1

2、commonParallelism的取值

common = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<ForkJoinPool>() {
public ForkJoinPool run() { return makeCommonPool(); }});
int par = common.config & SMASK; // report 1 even if threads disabled
commonParallelism = par > 0 ? par : 1;

SMASK 的值是 65535。

common.config 的值就是 (parallelism & SMASK) | 0的值,即最大为65535,若parallelism的值为0,则返回0。

int par = common.config & SMASK ,即最大为 65535

commonParallelism = par > 0 ? par : 1 的值就为 parallelism的值或1

6、结论

结论:

由上面的知识点,我们可以得出,当我们的容器是2核4G时,程序选择的线程池是ThreadPerTaskExecutor,当我们的容器是4核8G时,程序选择的线程池是ForkJoinPool

ForkJoinPool在生产环境中使用遇到的一个问题的更多相关文章

  1. Confluence 6 从生产环境中恢复一个测试实例

    请参考 Restoring a Test Instance from Production 页面中的内容获得更多完整的说明. 很多 Confluence 的管理员将会使用生产实例运行完整数据和服务的 ...

  2. .NET跨平台之旅:在生产环境中上线第一个运行于Linux上的ASP.NET Core站点

    2016年7月10日,我们在生产环境中上线了第一个运行于Linux上的ASP.NET Core站点,这是一个简单的提供后端服务的ASP.NET Core Web API站点. 项目是在Windows上 ...

  3. 理解Docker(6):若干企业生产环境中的容器网络方案

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  4. .NET跨平台之旅:生产环境中第2个跑在Linux上的ASP.NET Core站点

    今天我们在生产环境中上线了第2个跑在Linux上的ASP.NET Core站点.这是一个简单的Web API站点,通过命令行的方式调用安装在Linux服务器上的程序完成操作.之前用的是nodejs,现 ...

  5. 【原】Storm Local模式和生产环境中Topology运行配置

    Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...

  6. 生产环境中CentOS7部署NET Core应用程序

    NET Core应用程序部署至生产环境中(CentOS7) 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. ...

  7. 生产环境中使用Docker Swarm的一些建议

    译者按: 实践中会发现,生产环境中使用单个Docker节点是远远不够的,搭建Docker集群势在必行.然而,面对Kubernetes, Mesos以及Swarm等众多容器集群系统,我们该如何选择呢?它 ...

  8. [virtualenv]生产环境中使用virtualenv

    virtualenv 对于python开发和部署都是好工具,可以隔离多个python版本和第三方库的版本,这里作者总结了几个常用python服务怎么样结合virtual部署 原文链接 Python 中 ...

  9. Kubernetes 在生产环境中常用架构

    Kubernetes 在生产环境中常用架构 首先,我们来梳理下Kubernetes生产架构,其设计适用于绝大多数环境.如下图所示 在该架构中,我们可以将其分为四层,如下: Client层:即Kuber ...

  10. Dubbo Mesh 在闲鱼生产环境中的落地实践

    本文作者至简曾在 2018 QCon 上海站以<Service Mesh 的本质.价值和应用探索>为题做了一次分享,其中谈到了 Dubbo Mesh 的整体发展思路是“借力开源.反哺开源” ...

随机推荐

  1. 提高Java开发生产力,我选Stream API,真香啊

    Java 8 引入的Stream API提供了一种新的数据处理方式,它以声明式.函数式的编程模型,极大地简化了对集合.数组或其他支持数据源的操作.Stream可以被看作是一系列元素的流水线.允许你高效 ...

  2. 【framework】Activity启动流程

    1 前言 ATMS启动流程 介绍了 ActivityTaskManagerService(ATMS)的启动和初始化流程,本文将介绍 Activity 的启动流程.由于 Activity 启动流程复杂, ...

  3. 【OpenGL ES】绘制立方体

    1 前言 ​ 本文主要介绍使用 OpenGL ES 绘制立方体,读者如果对 OpenGL ES 不太熟悉,请回顾以下内容: 绘制三角形 绘制彩色三角形 绘制正方形 绘制圆形 ​ 在绘制立方体的过程中, ...

  4. 【OpenGL ES】绘制圆形

    1 前言 ​ [OpenGL ES]绘制三角形 中介绍了绘制三角形的方法,[OpenGL ES]绘制正方形中介绍了绘制正方形的方法,本文将介绍绘制圆形的方法. ​ OpenGL 以点.线段.三角形为图 ...

  5. shell脚本实现进度条程序

    1.实现效果 2.shell脚本 #!/bin/bash i=0 bar='' index=0 arr=( "|" "/" "-" &quo ...

  6. [BUUCTF][Web][极客大挑战 2019]Havefun 1

    打开靶机的URL,看到一个页面 右键查看源代码,看到有用信息 <html> ... <!-- $cat=$_GET['cat']; echo $cat; if($cat=='dog' ...

  7. 项目实战:Qt+FFmpeg录屏应用(支持帧率、清晰度设置)

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109827936各位读者,知识无穷而人力有穷,要 ...

  8. django中的一些装饰器用法

    1.require_http_methods() 1.要求视图只接受特定的请求方法 2.该装饰器允许传递多个请求方法参数,以列表的形式,请求方法名要大写 from django.views.decor ...

  9. Python全栈面试题及知识点总结

    Python全栈面试题 Python全栈阶段总结:https://github.com/HkwJsxl/PythonFullStack/tree/master/Notes Python基础 基础 逻辑 ...

  10. 最经典的TCP性能问题

    目录 问题描述 问题的原因 什么是delay ack 什么是Nagle算法 如果client启用Nagle,并且server端启用了delay ack会有什么后果呢? 再来看一个经典例子和数据分析 回 ...