`
zhaohaolin
  • 浏览: 1012591 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

一个线程池引发的悲剧【转】

    博客分类:
  • JAVA
阅读更多

在对 Jetty 性能测试 AJP 静态页面发现,压力一上来 LR 端就出现 504 错误,查看 nginx logs 发现 大量请求 upstream timeout ,意思是说在 nginx 上来的请求在 jetty 接收时出现问题。使用 netstat –ano|grep 8009  发现个有意思的东西如下图:

 

Recv-Q 接收队列大量数据等待copy,可以看到每个连接都有 281 个字节在等待,正常状况这个 Recv-Q 应该是 0 ,并且大量服务器连接处于被动关闭状态 CLOSE_WAIT.

  这里就有两个问题:

1、  为什么服务器连接被 nginx 主动给干掉了?

2、  为什么 jetty 后端处理会有这么多等待队列?

 

顺着这两个问题,之前怀疑是 nginx 有什么问题,结果查了半天没查出来,再看这里 ESTABLISHED 只有 10 个,而且非常固定,而 CLOSE_WAIT 连接却在不断增多。

接下来 /opt/java1/bin/jstack 15679|grep ‘poo-’ –c   看了下线程数,恰好只有 10 个线程,恰好是我设置的线程池最小线程数量,按道理压力这么大的情况下,这里的线程数应该大于 10 才对,于是猜测会不会是线程池问题 ( 没其他办法了,完全是乱猜 )

 

一看配置:

  1. <Set name= "ThreadPool" >  
  2. <!-- Default queued blocking threadpool -->  
  3. <New class = "org.eclipse.jetty.util.thread. ExecutorThreadPool" >  
  4.     <Arg>10</ Arg > <!--core线程数-->  
  5. <Arg>200</ Arg ><!—最大线程数-->  
  6. <Arg>60000</ Arg ><!--keeplive-->  
  7. </New>  
  8. </Set>  

 

貌似没什么问题,不过看看 org.eclipse.jetty.util.thread. ExecutorThreadPool 的源代码:

上面代码其实是调用下面这个构造函数:

  1. public  ExecutorThreadPool( int  corePoolSize,  int  maximumPoolSize,  long  keepAliveTime)  
  2.    {  
  3.        this ( new  ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit.MILLISECONDS, new  LinkedBlockingQueue<Runnable>()));  

 

这是使用的 JDK 的自带线程池 ThreadPoolExecutor ,特别注意最后一个参数 new LinkedBlockingQueue<Runnable>() ,这是放任务的队列,而且是一个无边界的队列。为什么要强调这个,请见其最终代码实现,或者看下 JDK 的描述:

无界队列。 使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue )将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize 。(因此, maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

 

就是说这个队列可以放无穷多的任务 ( 只要内存足够大 ) ,只要能放进去任务,那么线程数最多就是我们设置的 corePoolSize, 我们前面设置的是 10 ,这就能解释为什么前面我们的线程数不能超过 10 了,虽然很多任务在等待执行。

于是,我将该线程池重新做了一下设置,服务器恢复正常。

那么 nginx 为什么会主动关闭连接?答案很简单, socket 本身只能接收一定数量的连接请求数据,如果数据没有被处理掉,那么upstream 就不能继续发送,一直等到超时为止,也就是前面出现upstream timeout ,然后nginx关闭了这个连接,因此会出现一大堆的 CLOSE_WAIT

-----------

分享到:
评论

相关推荐

    一个简单线程池的实现

    当有新的任务提交时,线程池会选择一个空闲的线程来执行任务,而不是每次都需要创建新的线程,这样可以避免频繁的线程创建和销毁带来的开销。 `twork_work.cpp`和`twork_work.h`文件可能定义了一个工作单元(Work ...

    一个线程池的设计

    从给定的文件信息中,我们可以深入探讨关于“一个线程池的设计”这一主题的关键知识点。线程池是计算机科学中一种重要的并发编程技术,它能够有效地管理和复用一定数量的线程,以提高系统资源的利用率和响应速度。...

    一个线程池封装类及例子程序

    线程池是多线程编程中的一个重要概念,它是一种高效的线程管理机制,可以提高系统的资源利用率和系统性能。在Java等编程语言中,线程池的实现通常基于Executor框架,允许开发者创建并管理一组可重用的工作线程。本...

    阻塞线程池 阻塞线程池 阻塞线程池

    阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池阻塞线程池...

    VC写的一个线程池的管理实例

    线程池在多任务处理和并发编程中是一个重要的概念,它允许高效地管理和调度大量并发执行的任务。在Windows环境下,Microsoft Visual C++(VC)提供了一套API来支持线程池的实现。在这个"VC写的一个线程池的管理实例...

    python 的一个线程池

    python 的一个线程池,适用于大部分的多线程需求

    100行Java代码构建一个线程池

    当有新任务到达时,线程池会从已存在的线程中选择一个来执行任务,而不是每次都新建线程。这样可以避免频繁创建和销毁线程,提高系统资源利用率,同时还能更好地控制系统的并发程度。 【线程与进程】 线程是操作...

    linux下的一个线程池类

    线程池通过预先创建一组线程,并将它们保存在一个池中,当有新的任务到来时,可以重用这些线程,而不是每次都创建新的线程。这种方式可以减少系统开销,提高系统的响应速度和并发处理能力。 在描述中提到的"linux下...

    vc写的一个线程池操作的类

    标题中的"vc写的一个线程池操作的类"意味着这个压缩包中包含了一个用C++编写的线程池实现,它是专门为VC环境设计的。线程池类通常会包含以下核心功能: 1. **线程创建与销毁**:线程池会预先创建一组线程,当有新...

    LInux c++ 线程池封转框架

    线程池的核心在于预先创建一定数量的线程,存储在一个线程池中,当有任务需要执行时,线程池会分配一个空闲线程执行任务,任务完成后线程并不销毁,而是回到线程池等待下次任务。这样避免了频繁地创建和销毁线程,...

    多线程的使用-一个线程池的Demo

    线程池则是在一组线程上运行任务的抽象,它维护了一个工作线程的集合,用于执行用户提交的任务。 线程池的工作流程通常包括以下几个步骤: 1. 初始化线程池:创建一定数量的线程并将其放入池中等待任务。 2. 提交...

    很不错的一个linux下的线程池

    一旦任务分配给一个线程,它就会执行任务并返回到待命状态,直到被分配下一个任务。 3. **任务队列**:用于存储待处理的任务。当有新的任务加入时,它会被放入队列中,由线程池管理器调度分配给空闲线程。 4. **...

    课程作业基于C语言编写的一个线程池源码+详细注释.zip

    课程作业基于C语言编写的一个线程池源码+详细注释.zip课程作业基于C语言编写的一个线程池源码+详细注释.zip课程作业基于C语言编写的一个线程池源码+详细注释.zip课程作业基于C语言编写的一个线程池源码+详细注释.zip...

    一个线程池的Code

    一个线程池的Code,从网上看到的!自己下来编译一下!

    Java线程池使用说明

    3. ThreadPoolExecutor:是ExecutorService的一个重要实现,提供了创建线程池的核心功能,包括线程池的维护、任务队列的管理等。 4. ScheduledExecutorService:继承自ExecutorService,用于处理需要定时或周期性...

    一个通用的Java线程池类

    环境:Windows XP ...这里本人翻写一个通用的线程池类,它可以用来作为工具类处理许多多线程问题。代码注释非常详尽,一行注释一行代码。 阅读对象:非常熟悉Java的基本概念,并且熟悉命令行编写代码的人员。

    一个Ubuntu下的C线程池

    标题中的“一个Ubuntu下的C线程池”指的是在Ubuntu操作系统上使用C语言实现的一个线程池库。线程池是一种程序设计模式,它管理一组预先创建的线程,以便高效地处理并发任务。在Linux环境下,C语言是系统编程的常用...

    一个简单的线程池例子

    线程池是多线程编程中的一个重要概念,它在Windows操作系统以及其他支持多线程操作系统的环境中广泛应用。线程池是一种管理线程资源的有效方式,通过预先创建并维护一定数量的线程来处理任务,而不是每次需要执行新...

    线程池  

    下面我们将详细探讨如何在VC++中构建一个简单的线程池。 首先,线程池的核心组件包括: 1. **线程池对象**:这是管理所有线程的容器,负责线程的创建、调度和销毁。 2. **任务队列**:线程池中存放待处理任务的...

    Java代码构建一个线程池

    ### Java代码构建一个线程池 在现代软件开发中,多线程编程是提升程序性能、提高资源利用率的重要手段之一。特别是在服务器端应用中,合理地管理线程资源能够极大地提高系统的响应能力和处理效率。本文将详细介绍...

Global site tag (gtag.js) - Google Analytics