3

我很少有座位可以由用户保留。一次,只有一个用户可以参与预订过程,因此同一座位不会被多个用户预订。在我的 Java 代码中,我使用了“同步”关键字来完成它。这行得通。

但是,现在我的代码部署在两台服务器上,比如 S1 和 S2。假设,假设有最后一个座位可用。两个用户,比如 U1 和 U2,想要保留最后一个座位。负载均衡器可能会将用户 U1 发送到服务器 S1,将用户 U2 发送到服务器 S2。现在,“本地”同步仍然可以以相同的方式工作,但在进行预订时将无法阻止其他用户。这将使两个用户都保留最后一个座位,这是有问题的。

所以问题是如何确保多个用户在多服务器环境中保留席位而不会发生任何冲突?

4

2 回答 2

3

在语言层面上很难做到。一些分布式缓存可能会有所帮助,例如Terracotta确实处理集群环境中的同步关键字,但我还没有尝试过,而且肯定会造成性能损失。我会非常小心地让实例等待一些重要的时间,就像你的情况一样。

否则,分布式 JNDI、分布式单例或类似的东西可以使服务器实例进行通信并在此过程中检查是否有帮助。

但在实践中,通常通过乐观锁定来避免这个问题。您可能会简单地假设这只发生在一些不寻常/不太可能的时刻,并像在一个实例中那样做事情。并找出一种方法,当它没有时该怎么做。这变得更像是业务逻辑场景,最好的方法就是找到一种让用户最不可能不满意的方法。

通常在持久性/数据库级别保证一致性,所以你可以把它写在那里。我当然不会使用 synchronized 关键字来阻止可能保持几分钟或更长时间的实例,因为它要求内存泄漏或任何其他资源耗尽。

我个人喜欢在使用处理此问题的 JPA/Hibernate 时使用L2 缓存。当 OpenJPA 只通知其他实例实体已更改并且他们应该从其 L1 缓存中撤消它时,它有一种性能友好的方式来执行 L2 工作。在您的情况下,这可能是比使用同步 Java 语言关键字“同步”更好的方法。

考虑如何处理它是一种很好的态度,因为根据我的经验,它在许多应用程序中都被忽略了。它经常成为一种低概率的情况,业务导向的经理很难理解为什么应该投资它。但它具有强烈反弹的能力,以防生产中出现问题。

于 2013-02-19T01:31:03.323 回答
2

分布式系统基本上有四种通信方式:

  1. 共享数据库。
  2. 远程过程调用
  3. 消息传递。
  4. 共享文件系统。

考虑共享数据库方法。. 如果您不需要大规模扩展,最简单的方法是使用关系数据库,因为它们几乎都提供了一定程度的 ACID(原子性、一致性、隔离性和持久性)。. .

您可以设置事务,并在发生冲突时回滚/处理 - 这称为乐观锁定策略。

如果你使用 Spring + JPA/Hibernate,所有的辛苦工作都已经为你完成了,你只需要在你的更新方法中添加一个 @Transactional 注释。. . 一本关于 Spring 的好书是《Spring in Action》。

另一种选择是使用分布式缓存。

于 2013-02-19T01:07:27.593 回答