处理并发全局“库存”更新的常用策略

问题描述 投票:0回答:1

举一个简化的例子:

我有一个包含一个表的数据库:名称,其中有100万条记录,每条记录包含一个普通的男孩或女孩的名字,每天都有更多的记录。

我有一个应用程序服务器,它使用我的网站“名称选择器”从父母那里获取http请求。对于每个请求,我需要从数据库中获取一个名称并将其返回,然后不将该名称提供给另一个父项。服务器是并发的,因此可以处理大量请求,但必须遵守“每个请求的唯一名称”,并且仍然具有高可用性。

此用例的体系结构的主要组件和策略是什么?

database architecture scalability
1个回答
1
投票

据我所知,您有两个操作:添加名称和选择名称。

我有几个问题:

  • 问题1:父母是仅选择姓名还是添加姓名?
  • 问题2如果他们添加了名称,这是否意味着当添加名称时,它还应标记为已选择?

假设您不想让所有名称选择请求彼此等待(通过锁定排队):

在仅选择名称的情况下解决并发性的一种解决方案是使用Optimistic offline lock

最常见的实现是向表中添加版本字段,并在将名称标记为已选择时递增此版本。您将需要数据库支持,但大多数数据库都为此提供了一种机制。 MongoDB默认情况下会向文档添加版本字段。对于RDBMS(如SQL),您必须自己添加此字段。

您尚未指定使用的技术,因此我将使用伪代码为SQL DB提供示例。对于MongoDB,您可以检查数据库如何为您进行这些检查。

NameRecord {
  id,
  name,
  parentID,
  version,
  isChosen,

  function chooseForParent(parentID) {

    if(this.isChosen){
      throw Error/Exception;
    }

    this.parentID = parentID
    this.isChosen = true;
    this.version++;
  }
}

NameRecordRepository {

  function getByName(name) { ... }

  function save(record) {

    var oldVersion = record.version - 1;

    var query = "UPDATE records SET ..... 
                 WHERE id = {record.id} AND version = {oldVersion}";

    var rowsCount = db.execute(query);

    if(rowsCount == 0) {
      throw ConcurrencyViolation
    }
  }
}

// somewhere else in an object or module or whatever...

function chooseName(parentID, name) {

   var record = NameRecordRepository.getByName(name);

   record.chooseForParent(parentID);

   NameRecordRepository.save(record);
}

在将whis对象保存到DB之前,必须执行版本比较。 SQL提供了一种基于某些条件执行查询的方法,并返回受影响行的行数。在我们的例子中,我们检查数据库中的版本是否与更新前的旧版本相同。如果不是,则表示其他人已更新记录。

在这个简单的例子中,您甚至可以删除版本字段并在SQL查询中使用isChosen标志,如下所示:

    var query = "UPDATE records SET ..... 
                 WHERE id = {record.id} AND isChosend = false";

向数据库添加新名称时,您将需要一个可解决并发问题的Unique约束。

© www.soinside.com 2019 - 2024. All rights reserved.