Google App Engine 文档包含以下段落:
注意:如果您的应用程序在提交时收到异常
交易失败并不总是意味着交易失败。你
可以接收DatastoreTimeoutException,
ConcurrentModificationException 或 DatastoreFailureException
事务已提交的情况下的例外情况
最终都会申请成功。只要有可能,就让你的
数据存储事务是幂等的,因此如果您重复事务,
最终结果是一样的。
等等,什么?似乎有一类非常重要的事务根本无法实现幂等,因为它们依赖于当前的数据存储状态。例如,一个简单的计数器,如“like”按钮。事务需要读取当前计数,将其递增,然后再次写出计数。如果交易看起来“失败”,但实际上并没有失败,并且我无法在客户端告诉这一点,那么我需要重试,这将导致一次点击生成两个“喜欢”。 GAE 肯定有办法防止这种情况发生吗?
Edit:
这似乎是分布式系统固有的问题,正如 Guido van Rossum 所言——请参阅此链接:
App Engine 数据存储区事务异常
因此,如果您想要高度的可靠性,设计幂等事务几乎是必须的。
我想知道是否有可能在整个应用程序中实现一个全局系统以确保幂等性。关键是在数据存储中维护事务日志。客户端将生成一个 GUID,然后将该 GUID 包含在请求中(在重试同一请求时将重新发送相同的 GUID)。在服务器上,在每个事务开始时,它将在数据存储中查找事务实体组中具有该 ID 的记录。如果它找到了,那么这是一个重复的事务,所以它会返回而不做任何事情。
当然,这需要启用跨组事务,或者将单独的事务日志作为每个实体组的子级。此外,如果失败的实体键查找速度很慢,性能也会受到影响,因为几乎每个事务都会包含失败的查找,因为大多数 GUID 都是新的。
就额外数据存储交互方面的额外成本而言,这可能仍然比我必须使每个事务幂等的情况要少,因为这需要大量检查每个级别的数据存储中的内容。
丹·威尔克森、西蒙·戈德史密斯等人设计了一个彻底的全球交易系统在应用程序引擎的本地(每个实体组)事务之上。在较高的层次上,它使用与您描述的 GUID 类似的技术。丹处理了“潜艇写入”,即您描述的报告失败但后来显示成功的事务,以及数据存储的许多其他理论和实践细节。埃里克·阿姆布鲁斯特 (Erick Armbrust) 实现了丹的设计木薯.
我不一定建议你实现他的设计或使用tapioca-orm,但你肯定会对这项研究感兴趣。
回答你的问题:很多人实现的 GAE 应用程序使用的数据存储没有幂等性。仅当您需要具有某些类型的保证(如您所描述的保证)的交易时,这一点才重要。了解何时确实需要它们,但通常不需要它们,这一点绝对很重要。
数据存储是在megastore之上实现的,对此进行了深入描述在本文中。简而言之,它使用多版本并发控制在每个实体组内和Paxos用于跨数据中心的复制,这两者都有助于海底写入。我不知道数据存储中是否有关于潜艇写入频率的公众号,但如果有,使用这些术语进行搜索并在数据存储邮件列表上应该可以找到它们。
亚马逊的 S3 并不是一个真正可比的系统;它更像是一个 CDN,而不是分布式数据库。亚马逊的 SimpleDB 与之相当。它最初只提供最终一致性,并最终添加了一种非常有限的交易类型,他们称之为条件写入,但它没有真实的交易。其他 NoSQL 数据库(redis、mongo、couchdb 等)在事务和一致性方面有不同的变化。
基本上,分布式数据库总是在规模、事务广度和一致性保证强度之间进行权衡。这是埃里克·布鲁尔最出名的CAP定理,它表示权衡的三个轴是一致性、可用性和分区容错性。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)