【问题标题】:Conditional synchronization of multiple application requests多个应用请求的条件同步
【发布时间】:2011-12-29 07:37:18
【问题描述】:

我有以下问题:

我有一个多线程服务器端应用程序,其中每个请求都执行一个新线程(标准情况)。基于此请求,应用程序检查所需的数据是否已缓存在数据库中。如果是,它将获取它并将其发送回客户端。如果没有,则调用远程服务,将响应存储在数据库中,然后将其提取并返回给客户端。

该服务需要一段时间来计算数据,并且由于对我的应用程序的请求是异步执行的,因此我陷入了一个请求检查数据库的陷阱,发现那里没有任何内容,然后调用该服务。然而,与此同时,具有相同输入的另一个请求将检查数据库,并且由于服务需要一段时间,因此那里仍然没有任何内容......因此它将启动对服务的另一个调用。结果,数据被写入数据库两次,这会破坏任何成功的操作,依赖于它的唯一性(不能有两条具有相同数据的记录)

我应该选择什么解决方案? 一种想法是将特定的 UNIQUE 字段约束放在数据库中。这样,即使应用程序尝试写入两次,数据库也会简单地拒绝它,并且应用程序会抛出异常。但是,该服务仍会执行多次。

我想到的另一个解决方案是同步调用 Web 服务的方法。这样,对我的应用程序的每个连续请求都将在前一个操作完成之前放入等待堆栈。这样,如果另一个具有相同输入数据的请求进来,而第一个请求仍在等待远程服务的结果,它将坐下来等待操作完成。然后,当第二个请求检查数据库时,数据已经存在,无需再次调用服务。这也将防止在数据库中有多个相同的记录。这样做的问题是我的服务器应用程序的速度将不可避免地降低,因为每个请求都必须等待,即使是那些通常不应该等待的请求(那些,据说我们已经在数据库中有数据)

还有其他建议吗?我被困住了。如何实现某种条件同步?

【问题讨论】:

    标签: java database web-services hibernate spring


    【解决方案1】:

    只要实现这个算法:

    • 从数据库中获取数据
    • 如果数据存在,则返回数据
    • 如果数据不存在,则获取与数据id相关的锁以获取 //阻塞调用
    • 获得锁后,检查数据库中是否有数据,如果有,则返回数据。否则,调用服务并将数据放入数据库中
    • 释放锁

    这样,您仅在数据库中不存在数据时才等待锁定。第一个获得锁的并发线程是唯一调用服务的线程,所有其他线程都从数据库中获取数据。

    这不应妨碍您正确设计数据库,并为数据使用唯一的主键。如果您有一个服务器集群,仍然需要它。

    【讨论】:

      【解决方案2】:

      您可以只同步计算部分,即使用双重检查锁定:

      boolean dataExists = checkDB();
      if( !dataExists ) {
        synchronized( someSharedObject ) {
          //another thread might have been waiting too and now has put the data into the DB
          //thus check again
          if( !checkDB() ) {
            calculateDataAndWriteToDB();
          }  
        }
      }
      //do whatever you want with the existing data
      

      【讨论】:

      • 您的 someSharedObject 应该是您从最终用户输入中的输入。否则它是很好的方法/
      【解决方案3】:

      您描述的用例看起来像典型的缓存用例。在缓存中,数据通常具有一些键和值,其中键定义了唯一性。如果其他请求更新数据,它不会创建新记录,而是使用相同的键更新现有记录。如果你这样做,你付出的代价只是调用服务两次,但它不应该影响逻辑。那么,您是否有理由每次都创建新记录而不是更新?

      我强烈建议不要在您的用例中使用任何方法同步,因为它会自动使您的解决方案无法在多个盒子上扩展。

      【讨论】:

      • 当多个线程同时准备要插入的数据并尝试插入if时,更新是没有意义的。当数据已经在数据库中时(因此当你知道你可以更新它时)OP 不想采取任何行动。
      • 我同意。您可以使用锁定和许多其他优化。我描述了最简单的情况。
      【解决方案4】:

      在您的第一种方法中,在数据库中使用 UNIQUE 字段约束将无法解决您的问题,因为最终用户将不得不等待远程服务调用返回,并且将不必要地使用资源。

      另一种方法是取消具有相同输入数据的请求,并告诉最终用户在一段时间后刷新请求。但这不好,因为它会增加您的服务器停机时间。

      所以你离开了你的第二种方法。我只是建议你同步你的输入数据。 或者您可以检查一下输入数据是否相同,然后等到请求返回,然后从 db 读取输出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2019-01-05
        • 1970-01-01
        • 2015-10-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多