使用线程池和BlockingQueue重新构建I / O密集型Java Web服务

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用线程池和BlockingQueue重新构建I / O密集型Java Web服务相关的知识,希望对你有一定的参考价值。

我创建并且目前在PROD中存在的Java项目是I / O密集型的。我想重构它以优化性能 - 不是我被要求这样做但我觉得还有改进的余地。所以在为时已晚之前处理它。几个步骤可以并行化并更好地利用多个核心。

什么服务呢?

它是一个Web服务,它只是通过网络(通过Internet而不是公司内部网)提取文件并将它们sftp-ies到远程sftp服务器。有2个sftp站点。因此,服务决定通过请求本身发送的元数据来sftp到哪个服务器。此外,它还定期运行2个作业,在这两个sftp站点上按时间延迟5分钟进行轮询,并提取zip文件(如果有的话)。

做什么工作:Job将所有可用的拉链逐个拉到本地文件夹。然后开始处理每个zip(通过在zips集合上循环)。首先,它提取zip,然后获取1 pdf文件并发送到公司网络内的另一个Web服务(比如服务1)。然后它需要一个xml文件,解析它并从中提取某些数据,然后将该数据提供给另一个服务(比如服务2)。

我打算做什么?在一份工作中要做的工作太多了。我打算拆分它 - > Job只需将zips拉入本地文件夹并将名称推送到BlockingQueue中,这将触发另一个作业,处理将由它完成,即提取zip可以与从远程sftp-server拉取zip并行处理。现在我的问题是拉链从远程拉到本地并在本地处理zip实际上是I / O操作,但由于首先是网络上的I / O和另一个本地文件I / O,我认为使用的数据通道/总线是不同的。因此,如果我将它们并行化,它将提高性能。我需要这样做,因为在未来的拉链数量将会增加1000个拉链,这是当前实施的非常慢。

还将为sftp连接实现连接池(目前没有,我意识到这是必须的)。也为2个提议的工作

1)从遥控器拉动拉链

2)在本地处理拉链

我将使用线程池(根据教程Parallel and Asynchronous Programming ,如果服务是I / O密集数量的线程甚至可以达到核心的10倍。需要进行Offcourse基准测试。但从概念上讲,这对于开头的头部来说是好的)。

这种重组是否有意义?还有什么可以做的?

答案

我会根据活动类型定义一些线程池执行器:

  • 一个用于CPU密集型工作,大小为Runtime.getRuntime().availableProcessors()
  • 一个用于磁盘I / O绑定的作业,小尺寸(1..3)。 HDD在顺序模式下表现最佳。对于SSD,您可以尝试增加池大小,但在执行并行磁盘I / O时无论如何都要使用大缓冲(1MB +),
  • 一个主要用于网络I / O绑定作业(4..20,具体取决于网络带宽和传输距离)。

然后根据任务的性质将流程拆分为子任务。完成后,结束每个任务会将其结果移交给相应池中的新任务。

我还实现了一个backpressure mechanism,不让队列变得太大(默认情况下,ThreadPoolExecutor会愉快地排队无限量的工作)并密切关注堆和磁盘空间的使用情况。磁盘(HDD)往往是最大的瓶颈,尝试在内存中做更多的事情。

以上是关于使用线程池和BlockingQueue重新构建I / O密集型Java Web服务的主要内容,如果未能解决你的问题,请参考以下文章

java线程池和五种常用线程池的策略使用与解析

Java多线程-BlockingQueue

Delphi - OTL - 线程池和工作线程之间的通信

线程池和进程池的通用写法 ProcessPoolExecutor 和 ThreadPoolExecutor

数据库连接池和线程池

Java 线程池和可运行对象创建可运行对象