1

我正在提供由 servlet 提供的 RESTful 服务(在 Tomcat 7.0.X 和 Ubuntu Linux 中运行)。我每小时已经收到大约 20,000 个查询,而且还会增长得更高。servlet 接收请求,准备响应,在 MySQL 数据库表中插入记录并传递响应。数据库中的日志是绝对强制性的。直到最近,所有这一切都以同步的方式发生。我的意思是,在 Tomcat 线程传递响应之前,它必须在数据库表中创建记录。问题是这个日志过去占用了总时间的 90% 以上,甚至更糟:当数据库变慢时,服务大约需要 10-15 秒而不是 20 毫秒。

我最近做了一个改进:每个 Tomcat 线程都会创建一个额外的线程来执行“(new Thread(new certain Object)).start();” 它以异步方式处理 SQL 插入,因此响应更快地到达客户端。但是当 MySQL 运行速度较慢并且线程成倍增加时,这些线程占用了太多 RAM,而 JVM Tomcat 运行的内存有数千个。

我需要的是能够接受尽可能多的 HTTP 请求,尽可能快地记录每个请求(不同步),并在 MySQL 变慢并插入时使一切都变得快速并且 RAM 使用率非常低需要排队。当http请求的速度高于数据库日志中的插入速度时,我想我需要某种队列来缓冲条目。

我正在考虑这些想法:

1-自己创建某种 FIFO 队列,可能使用一些 Apache 公共集合,以及轮询集合并创建数据库记录的某种线程。但是我应该使用什么集合?我应该如何对轮询它的线程进行编程,这样它就不会独占 CPU?我认为“Do while (true)....”会占用 CPU 周期。那是关于让它线程安全的吗?怎么做?我认为自己做这件事太费力了,很可能我会重新发明轮子。

2-log4J?我从未直接使用过它,但似乎这个框架的算法旨在创建与数据库对话的“附加程序”。那会是这样做的方法吗?

3-使用某种专门从事此工作的任何其他框架?

你有什么建议?

提前致谢!

4

3 回答 3

0

一定要看看使用 ThreadPoolExecutor。您可以提供线程池大小,它将为您处理所有并发和排队。唯一可能的问题是,如果您的 JVM 因任何原因崩溃,您将丢失池中的所有排队项目。

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

我也肯定会尽可能地优化 MySQL 数据库。每小时 20k 个条目很快就会变得很棘手。您的硬件、操作系统和索引优化得越好,您的插入越快,您的队列就越小。

于 2013-01-26T05:22:28.320 回答
0

首先:非常感谢您的宝贵建议!

到目前为止,我已经找到了满足我需求的部分解决方案,并且我已经成功实现了它:

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html

现在我正在考虑使用队列提供程序(如果它已满)作为故障转移解决方案。到目前为止,我一直在考虑亚马逊的排队服务,但它需要花钱。我还将检查 Ryan 建议的队列解决方案。

于 2013-01-27T03:42:23.503 回答
0

马上想到的是你说的队列。您可以使用 ActiveMQ http://activemq.apache.org/或 RabbitMQ http://www.rabbitmq.com/之类的东西。

这个想法是开火然后忘记。发送消息应该几乎没有开销。

然后您可以连接一些“离线”以从队列中提取消息并以您需要的速度将它们写入数据库。

我觉得我整天都在 Stack Overflow 上插入这个,但我们在工作中使用 Mule (http://www.mulesoft.org/) 来执行此操作。Mule 的一大优点是您可以显式设置从队列中读取的线程数和写入数据库的线程数。它允许您对限制消息进行细粒度控制。

于 2013-01-26T05:10:59.563 回答