使用线程池和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服务的主要内容,如果未能解决你的问题,请参考以下文章