我们公司正在运行Java应用程序(在单CPU Windows服务器上)从TCP / IP套接字读取数据并检查特定条件(使用正则表达式),如果找到匹配项,则将数据存储在MySQL数据库。数据量巨大,读取速度为800条记录/秒,约70%的记录将匹配记录,因此涉及大量数据库写入。该程序使用LinkedBlockingQueue来处理数据。生产者类只读取记录并将其放入队列,消费者类从队列中删除并进行处理。
所以问题是:如果我使用多个消费者线程而不是单个线程,它会有帮助吗?在上面的场景中线程是否真的有用(因为我使用的是单CPU)?我正在寻找有关如何加速(不改变硬件)的建议。
任何建议都会非常感激。感谢
答案 0 :(得分:2)
简单:试一试,看看。
这是你在争论的任何一方争论几点的问题之一。但听起来你已经建立了大部分的基础设施。只需创建另一个消费者线程,看看是否有帮助。
但是你需要先问自己的第一个问题:
什么更好?
你如何更好地衡量?
回答这两个问题,然后尝试。
答案 1 :(得分:1)
单线程可以跟上传入的数据吗?数据库可以跟上传出数据吗?
换句话说,瓶颈在哪里?如果你需要多线程,那么在并发实用程序中查看Executor概念(在Executors帮助器类中有很多可供选择),因为这将处理你自己并不特别感兴趣的线程的所有繁琐细节。
我个人的直觉是瓶颈是数据库。索引和RAM有很多帮助,但这是一个不同的问题。
答案 2 :(得分:1)
多线程很可能会有所帮助,但很容易测试。使其成为可配置参数。通过1个线程,2个线程,4个线程,8个线程等,了解每秒可以执行的操作数量
答案 3 :(得分:1)
首先:
使用java 5 concurrent api
如果您的应用程序是围绕ExecutorService创建的,则更改使用的线程数非常容易。例如:您可以创建一个线程池,其中线程数由配置指定。因此,如果您想要更改线程数,则只需更改某些属性。
关于您的问题:
- 关于套接字的读取:据我所知,有两个线程从一个套接字读取数据是没有用的(如果可能的话)。只需使用一个读取套接字的线程,但在该线程中尽可能少地执行操作(例如读取套接字 - 将数据放入队列 - 读取套接字 - 等)。
- 关于消耗队列:如上所述构造此部件是明智的,这样可以很容易地改变消耗线程的数量。
- 注意:你无法真正预测什么是更好的,可能还有另一个部分是瓶颈,等等。只有监控/分析才能让您真实地了解您的情况。但是如果您的应用程序是如上构造的,那么使用不同数量的线程进行测试非常容易。
简而言之:
- 生产者部分:一个只从套接字读取并放入队列的线程
- 消费者部分:围绕ExecutorService创建,因此很容易调整消费线程的数量
然后使用分析确定瓶颈,并使用A-B测试来定义系统的最佳消费线程数
答案 4 :(得分:0)
作为我之前问题的更新:
我们确实在单个使用者线程和多个线程(添加5,10,15等)之间运行了一些比较测试,并监视了尚未处理的记录的队列大小。差异很小,而且更多..在线程数超过25(与运行5个线程相比)之后,que大小变得略大。让我得出结论:维护线程的开销超过了处理的好处。也许这对我们的场景来说可能是特别的,但只是提到了我的观察结果。
当然(正如其他人所指出的)瓶颈是数据库。这是通过在mySQL中使用multiple-insert语句而不是单个插入来处理的。如果我们没有开始,我们就无法处理这个负载。
最终结果:我仍然不相信多线程如何为处理时间带来好处。也许它有其他好处......但我只是从处理时间因素看。如果您有任何相反的经验,请让我们听听。
再次感谢您的所有投入。
答案 5 :(得分:0)
在你的场景中a)处理是最小的b)只有一个CPU c)数据直接进入数据库,添加更多线程的可能性不大。换句话说,前端和后端线程是I / O绑定的,中间处理最少。这就是为什么你没有看到太多改进。
你可以做的是尝试有三个阶段:第一个是从套接字中提取数据的单个线程。第二个是进行处理的线程池。 3rd是为DB输出提供服务的单个线程。如果输入速率变化,这可能产生更好的CPU利用率,但代价是输出队列的临时增长。如果没有,吞吐量将受到写入数据库的速度的限制,无论您拥有多少线程,然后您只需一个读取进程写入线程即可。