Joã*_*ida 5 sql postgresql concurrency locking node.js
让\xe2\x80\x99s 说我有一个名为Withdrawals (id, amount, user_id, status) 的表。
\n\n每当我发起提款时,流程如下:
\n\n但是,我在此流程中遇到并发问题。\n让\xe2\x80\x99s 假设用户在大约 50 毫秒的差异内发出 2 个全额余额提款请求:
\n\n要求1
\n\n请求 2(约 50 毫秒后)
\n\n目前,我们使用 Redis 将提款锁定在 x 毫秒内的特定用户,以避免这种情况,但这不是最稳健的解决方案。由于我们现在正在为企业开发 API,因此使用我们当前的解决方案,我们将阻止可能同时请求的提款。\n是否有任何方法可以锁定并确保后续插入查询根据 user_id 等待提款表?
\n这是事务隔离的属性。关于它的文章有很多,我强烈推荐设计数据密集型应用程序中的概述。我发现这是对提高我个人理解最有帮助的描述。
默认的 postgres 级别是READ COMMITTED,它允许每个并发事务看到类似的(资金可用状态),即使它们应该是相关的。
解决这个问题的一种方法是将每个事务标记为“可串行化”一致性。
SERIALIZABLE 当前事务的所有语句只能看到在该事务中执行第一个查询或数据修改语句之前提交的行。如果并发可序列化事务之间的读写模式会造成这些事务的任何串行(一次一个)执行不会发生的情况,则其中一个事务将被回滚并出现serialization_failure错误。
这应该以牺牲可用性为代价来强制应用程序的正确性,即在这种情况下,第二个事务将不允许修改记录并将被拒绝,这将需要重试。对于 POC 或低流量应用程序,这通常是完全可以接受的第一步,因为您现在可以确保正确性。
另外,在上面引用的书中,我认为有一个 ATM 如何处理可用性的示例。他们允许这种竞争条件,如果用户无法连接到中央银行,则可以透支,但会限制最大提款以最小化爆炸半径!
解决此问题的另一种架构方法是使事务脱机并使它们异步,以便将每个用户调用的事务发布到队列,然后通过拥有队列的单个使用者,您自然可以避免任何竞争条件。这里的权衡是类似的,单个工作人员可以使用固定的吞吐量,但它确实有助于解决目前的正确性问题:P
跨机器锁定(就像跨 postgres/grpc 使用 redis)称为分布式锁定,并且有大量关于它的文章https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
| 归档时间: |
|
| 查看次数: |
9217 次 |
| 最近记录: |