3

我有一个将文件写入磁盘和将其他内容写入数据库的网络服务。每次写入整个操作需要 1-2 秒。

该服务可以同时从多个客户端调用,但这是不太可能的。假设有 20 个客户端同时调用 web 服务,写操作必须同步。在这种情况下,某些客户端可能会出现超时异常,因为它们必须等待很多秒。

有什么好的做法可以解决这类情况吗?就像现在一样,这些方法是同步的(这可能导致饥饿/超时)。

我是否应该通过删除关键字让所有线程进入 write 方法synchronized并将它们的任务放入任务队列以避免超时?这是解决这个问题的正确方法吗?

4

3 回答 3

1

Francis Upton's practice is indeed an accepted practice.

Another one, is making more fine grained synchronization. Instead of synchronizing all read/write methods of a class, you can synchronize access of the exact invariants that should be synchronized.

And yet even better, is to get rid of synchronization altogether. This is possible using the java.util.concurrent package. This package introduce new collections that use Non-Blocking Algorithms (implemented in java using Compare-Ans-Swap atomic instructions). These collections, such as ConcurrentHashMap, enable much better throughput when scaling.

You can read more about it in this article.

于 2012-04-30T08:14:18.637 回答
1

删除synchronized并将其放入任务队列本身对您没有帮助(因为这实际上是同步为您做的)。但是,如果您在将 Web 请求放入队列后立即对其进行响应,那么您将缩短响应时间。但是以牺牲一些可靠性为代价,因为用户将确认工作已完成,而工作实际上并未完成(系统可能在工作完成之前崩溃)。

于 2012-04-30T07:40:31.867 回答
1

在这种类型的实现中(负载增加下的缓慢服务),您希望尽可能多地异步,包括超时处理(如果基于服务器)和所需的 I/O。不要让客户端响应线程等待这些耗时的操作,以保持服务器对新请求的响应,而是触发所需的操作(可能是动态线程池)并让回调处理结果,无论是超时、完成 I/O 还是错误。

根据首先发生的情况发送适当的响应,但如果您发送错误/超时消息然后完成的 I/O 到达(由于 I/O 和计时器之间的竞争条件),请准备回滚 I/O。这意味着服务器中需要事务语义。

这是一个随着负载增长而变得越来越复杂的领域,但早期的良好设计应该允许您随着负载的增长而扩展。理想情况下,客户端服务线程根本不应该阻塞。

于 2012-04-30T11:03:48.947 回答