【问题标题】:How do I prevent two Node processes from inserting the exact same database record when running simultaneously?如何防止两个 Node 进程同时运行时插入完全相同的数据库记录?
【发布时间】:2019-09-09 10:44:02
【问题描述】:

我有一个 Lambda,它可以一次接收数千个事件。默认情况下保留并发,这意味着 AWS 将启动多个实例来处理传入事件。 Lambda 获取数据并将一些数据插入到数据库中(如果该数据尚不存在)。 Lambda 是用 Node.js 编写的,并使用 Knex 连接到 Postgres 数据库。

Lambda 本质上包含这个逻辑:

Does a record with ID X exist?     
a. Yes: do nothing
b. No: create a new record with ID X.

问题在于,当 50 个 Lambda 同时启动时,它们会进入竞争条件,例如,其中 3 或 4 个将同时检查现有记录(或彼此相隔几微秒) ) 并没有找到它,因此插入了多个重复的记录。

我知道解决这个问题的一种方法是在表上创建一个唯一约束,以防止多个 ID 为 X 的记录。那么我的逻辑将如下所示:

Does a record with ID X exist? 
a. Yes: do nothing 
b. No: create a new record with ID X.
   b.1. Did that succeed?
      a. Yes: continue on.
      b. No, it threw a unique constraint error: go back to line 1.

这似乎有点做作,但应该可以。有更好的选择吗?

编辑:

这是实际代码:

let location = await Location.query().where({ external_id }).first();
if(!location){
    location = await Location.query().insert({
        name,
        external_id
    });
}

【问题讨论】:

  • 我认为这个问题不一定特定于 aws-lambda 或 postgresql ......它被概括为 consistency models 以及采取哪条路线。 Jespen 有一些图表可以帮助解释每个模型的优势
  • 也许一个很好的初读会是:Correctness。这个链接有更多的图来帮助解释。
  • @JaromandaX 我已经添加了 actual 代码。它确实符合我的解释,但我希望你满意。
  • 某些数据库允许您执行“更新插入”操作,这意味着:“更新如果找到,否则在插入
  • @RichS 这是一个有趣的想法。我认为 Postgres 确实支持这一点,但不确定 Knex 是否支持。我会调查的。谢谢你的想法。

标签: javascript node.js postgresql aws-lambda knex.js


【解决方案1】:

这样的代码:

Does a record with ID X exist?      
a. Yes: do nothing 
b. No: create a new record with ID X.

不以某种方式锁定数据库是一种竞争条件。在查询记录 X 和创建它之间,其他一些请求也可以创建它。永远不要这样做。这很活泼。

您必须查看数据库提供的特定工具,但执行上述序列的常用方法是设置数据库,使其不允许 ID X 重复,然后您只需尝试创建记录ID 为 x。然后,它将自动创建或返回错误,并且没有机会出现竞争条件。您只需查找错误并处理它

【讨论】:

  • 谢谢。所以你的建议是按照我的建议做,创建一个唯一的约束,让插入失败,然后回退到第二次尝试选择记录,什么时候应该存在?
  • @user2719094 - 通常是的。但是,我不知道你第二次选择它是什么意思。如果您尝试创建或更新记录,那么许多数据库都有针对该特定操作的原子操作(有时称为 upsert),它将执行插入或更新。
  • @jfriend00 是的,我意识到这可能不清楚。我确实需要获取插入记录的行 ID,以便可以在其他地方使用它,所以如果插入失败,我仍然需要重试选择,以便获得所需的 ID。
  • 长版:Postgres UPSERT。短版:INSERT ... ON CONFLICT UPDATE
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 2016-08-24
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多