在分布式应用程序中同步数据库访问

时间:2011-01-31 11:15:13

标签: database language-agnostic mutex distributed-computing

我发现自己经常实现的一些常见的编程逻辑类似于以下伪代码:

Let X = some value
Let Database = some external Database handle

if !Database.contains(X):
   SomeCalculation()
   Database.insert(X)

但是,在多线程程序中,我们在这里遇到竞争条件。线程A可能会检查X是否在Database中,发现它不是,然后继续致电SomeCalculation()。同时,线程B还将检查X是否在Database中,发现它不是,并插入重复的条目。

当然,这需要像:

同步
Let X = some value
Let Database = some external Database handle

LockMutex()
if !Database.contains(X):
   SomeCalculation()
   Database.insert(X)
UnlockMutex()

这很好,除非应用程序是分布式应用程序,运行在多台计算机上,所有这些计算机都与同一个后端数据库计算机进行通信?在这种情况下,Mutex是无用的,因为它只将应用程序的单个实例与其他本地线程同步。为了实现这一目标,我们需要某种“全局”分布式同步技术。 (假设在Database中简单地禁止重复是不可行的策略。)

一般来说,这个问题的一些实际解决方案是什么?

我意识到这个问题非常泛型,但我不想让这个问题成为特定于语言的问题,因为这是跨多种语言和多种数据库技术的问题。

我故意避免指定我是在谈论RDBMS还是SQL数据库,而不是像NoSQL数据库那样,因为再次 - 我正在寻找基于行业惯例的通用答案。例如,这种情况是原子存储过程可能解决的吗?还是原子交易?或者这是否需要像“分布式互斥体”这样的东西?或者更一般地说,这个问题通常是由数据库系统解决的,还是应用程序本身应该处理的?

如果事实证明这个问题不可能完全没有回复,请告诉我,我可以修改它。

3 个答案:

答案 0 :(得分:2)

确保数据踩踏的一种可靠方法是锁定数据行。许多数据库允许您通过事务执行此操作。有些人不支持交易。

然而,对于大多数争用率较低的案例而言,这是过度的。您可能希望阅读Isolation levels以获得有关该主题的更多背景信息。

更好的一般方法通常是Optimistic Concurrency。其背后的想法是每个数据行包括签名,时间戳工作正常,但签名不需要时间导向。例如,它可以是哈希值。这是一种通用的并发管理方法,并不仅限于关系存储。

更改数据的应用程序首先读取行,然后执行所需的任何计算,然后在某个时刻将更新的数据写回数据存储。通过乐观并发,应用程序使用规定(在SQL中表示,如果它是SQL数据库)写入更新,只有在临时中未更改签名时才必须更新数据行。并且,每次更新数据行时,也必须更新签名。

结果是更新不会被踩踏。但是有关并发问题的更严格的解释,请参阅有关数据库隔离级别的文章。

所有分布式更新程序必须遵循OCC约定(或更强大的内容,如事务锁定)才能使其正常工作。

答案 1 :(得分:0)

显然,您可以使用特定资源上的独占锁将“synch”部分移动到数据库层本身。

这有点极端(在大多数情况下,当你真正发现有人已插入行时尝试插入和管理异常)会更加充分,我认为。

答案 2 :(得分:0)

好吧,既然你问了一个普遍的问题,我会尝试提供另一种选择。它不是非常正统,但可能有用:您可以“定义”机器或负责这样做的过程。例如:

Let X = some value
Let Database = some external Database handle

xResposible = Definer.defineResponsibleFor(X);

if(xResposible == me)
    if !Database.contains(X):
       SomeCalculation()
       Database.insert(X)

这里的技巧是使defineResponsibleFor始终返回与调用谁无关的相同值。所以,如果你有一个公平的X分布范围和一个公平的Definer,所有的机器都有工作要做。您可以使用简单的线程互斥来避免竞争条件。当然,现在您必须注意容错(如果机器或流程已经停业,您的Definer必须知道并且没有为它定义任何工作)。但是你应该这样做......:)