如何在DynamoDB中创建UUID?

时间:2012-07-30 12:12:52

标签: database node.js nosql amazon-dynamodb

在我的数据库方案中,我需要一个自动增量主键。我怎么能实现这个功能?

PS为了访问DynamoDB,我使用了dynode,模块用于Node.js.

10 个答案:

答案 0 :(得分:19)

免责声明:我是Dynamodb-mapper项目的维护者

自动增量键的直观工作流程:

  1. 获得最后的反击位置
  2. 添加1
  3. 使用新号码作为对象的索引
  4. 保存新的计数器值
  5. 保存对象
  6. 这只是为了解释潜在的想法。永远不要这样做,因为它不是原子的。在某些工作负载下,您可以为2个以上的不同对象分配相同的ID,因为它不是原子的。这会导致数据丢失。

    解决方案是使用原子ADD 操作以及UpdateItem ALL_NEW

    1. 原子地生成ID
    2. 使用新号码作为对象的索引
    3. 保存对象
    4. 在最糟糕的情况下,应用程序在保存对象之前崩溃,但绝不会冒两次分配相同ID的风险。

      还有一个问题:在哪里存储最后一个ID值?我们选择了:

      {
          "hash_key"=-1, #0 was judged too risky as it is the default value for integers.
          "__max_hash_key__y"=N
      }
      

      当然,为了可靠地工作,所有插入数据的应用程序必须知道这个系统,否则你可能(再次)覆盖数据。

      最后一步是自动化流程。例如:

      When hash_key is 0:
          atomically_allocate_ID()
      actual_save()
      

      有关实施细节(Python,抱歉),请参阅https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67

      说实话,我的公司不会在生产中使用它,因为在大多数情况下,最好找到另一个密钥,例如,对于用户,ID,交易,日期时间...... / p>

      我在dynamodb-mapper's documentation中写了一些例子,可以很容易地推断出Node.JS

      如果您有任何疑问,请随时提出。

答案 1 :(得分:5)

如果您的增量ID中存在间隙,并且您只是大致对应于添加行的顺序,那么您可以自己滚动:创建一个名为NextIdTable的单独表,其中一个主键(数字),称之为计数器。

每次要生成新ID时,您都会执行以下操作:

  • 在NextIdTable上执行GetItem以读取Counter的当前值 - > curValue
  • 在NextIdTable上执行PutItem,将Counter的值设置为curValue + 1.将此值设置为条件PutItem,以便在Counter的值发生更改时失败。
  • 如果有条件的PutItem失败,则意味着其他人正在与您同时这样做。重来。
  • 如果成功,则curValue是您的新唯一ID。

当然,如果您的进程在任何地方实际应用该ID之前崩溃,您将“泄漏”它并在您的ID序列中有一个间隙。如果你和其他一些过程同时进行,那么你们中的一个会获得价值39而你们其中一个会获得价值40,并且无法保证它们实际应用于您的数据表中的顺序;得到40岁的那个人可能会在得到39岁的那个人面前写出来。但它确实给你一个粗略的订单。

此处详细介绍了node.js中条件PutItem的参数。 http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html。如果您之前从Counter中读取了值38,则您的条件PutItem请求可能如下所示。

var conditionalPutParams = {
    TableName: 'NextIdTable',
    Item: {
        Counter: {
            N: '39'
        }
    },
    Expected: {
        Counter: {
            AttributeValueList: [
                {
                    N: '38'
                }
            ],
            ComparisonOperator: 'EQ'
        }
    }
};

答案 2 :(得分:4)

另一种方法是使用UUID生成器作为主键,因为这些高度不太可能发生冲突。

IMO您更有可能遇到在高可用DynamoDB表中合并主键计数器的错误,而不是生成的UUID中的冲突。

例如,在Node:

npm install uuid

var uuid = require('uuid');

// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

取自SO answer

答案 3 :(得分:3)

我不相信SQL样式自动递增是可能的,因为这些表是跨多台机器分区的。我在PHP中生成自己的UUID来完成这项工作,我相信你可以在javascript中找到类似like this的东西。

答案 4 :(得分:3)

除了@ yadutaf的回答

AWS支持Atomic Counters

创建一个单独的表(order_id),其中一行包含最新的order_number:

+----+--------------+
| id | order_number |
+----+--------------+
|  0 |         5000 |
+----+--------------+

这将允许将order_number增加1并在AWS DynamoDB的回调中获得递增的结果:

config={
  region: 'us-east-1',
  endpoint: "http://localhost:8000"
};
const docClient = new AWS.DynamoDB.DocumentClient(config); 

let param = {
            TableName: 'order_id',
            Key: {
                "id": 0
            },
            UpdateExpression: "set order_number = order_number + :val",
            ExpressionAttributeValues:{
                ":val": 1
            },
            ReturnValues: "UPDATED_NEW"
        };


docClient.update(params, function(err, data) {
   if (err) {
                console.log("Unable to update the table. Error JSON:", JSON.stringify(err, null, 2));
   } else {
                console.log(data);
                console.log(data.Attributes.order_number); // <= here is our incremented result
    }
  });

请注意,在某些罕见的情况下,他们的调用者点与AWS API之间的连接可能会出现问题。它将导致dynamodb行递增,而您将收到连接错误。因此,可能会出现一些未使用的递增值。

您可以在表格中使用递增的data.Attributes.order_number,例如将{id: data.Attributes.order_number, otherfields:{}}插入order表。

答案 5 :(得分:3)

对于那些使用Java编码的人,documentation现在可以代表您生成唯一的UUID。

  

DynamoDBAutoGeneratedKey

     

将分区键或排序键属性标记为自动生成。   DynamoDBMapper在保存时会生成随机UUID   属性。只有String属性可以标记为自动生成   密钥。

使用DynamoDBMapper这样的注释

@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys { 
    private String id;

    @DynamoDBHashKey(attributeName = "Id")
    @DynamoDBAutoGeneratedKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; } 

正如您在上面的示例中所看到的,您可以将DynamoDBAutoGeneratedKey和DynamoDBHashKey批注应用于同一属性,以生成唯一的散列键。

答案 6 :(得分:2)

我遇到了同样的问题,并为此目的创建了一个小型Web服务。请参阅此博客文章,该文章解释了我如何使用DynamoDB stateful.co来模拟自动增量功能:http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

基本上,您在stateful.co注册一个原子计数器,并在每次需要新值时通过RESTful API递增它。该服务是免费的。

答案 7 :(得分:0)

创建新的file.js并输入以下代码:

exports.guid = function () {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return (_p8() + _p8(true) + _p8(true)+new Date().toISOString().slice(0,10)).replace(/-/g,"");
}

然后,您可以将此功能应用于主键ID。它将生成UUID。

答案 8 :(得分:0)

从性能的角度来看,自动增量是不好的,因为它将使特定的分片过载,同时使其他分片处于空闲状态;如果要将数据存储到Dynamodb,它不会分配均匀。

awsRequestId看起来像它的实际V.4 UUID(随机),下面的代码段可以尝试:

exports.handler = function(event, context, callback) {
    console.log('remaining time =', context.getRemainingTimeInMillis());
    console.log('functionName =', context.functionName);
    console.log('AWSrequestID =', context.awsRequestId);
    callback(null, context.functionName);
};

如果您想自己生成它,可以使用https://www.npmjs.com/package/uuidUlide来基于RFC-4122生成不同版本的UUID

  • V1(基于时间戳)
  • V3(名称空间)
  • V4(随机)

对于Go开发人员,您可以使用Google's UUIDPbormanSatori中的这些软件包。 Pborman的性能更好,请查看这些articles and benchmarks以获取更多详细信息。

有关here的通用唯一标识符规范的更多信息。

答案 9 :(得分:0)

如果您使用NoSQL DynamoDB,然后使用Dynamoose ORM,则可以轻松设置默认唯一ID。这是简单的用户创建示例

// User.modal.js

userData

// User.controller.js

const dynamoose = require("dynamoose");

const userSchema = new dynamoose.Schema(
  {
    id: {
      type: String,
      hashKey: true,
    },
    displayName: String,
    firstName: String,
    lastName: String,
  },
  { timestamps: true },
);

const User = dynamoose.model("User", userSchema);

module.exports = User;