Подтвердить что ты не робот

Как сделать UUID в DynamoDB?

В моей схеме db мне нужен первичный ключ автоинкремента. Как я могу реализовать эту функцию?

PS Для доступа к DynamoDB я использую dynode, модуль для Node.js.

4b9b3361

Ответ 1

Отказ от ответственности: я являюсь разработчиком проекта Dynamodb-mapper

Интуитивно понятный рабочий процесс ключа автоматического инкремента:

  • получить последнюю позицию счетчика
  • добавить 1
  • используйте новый номер в качестве индекса объекта
  • сохранить новое значение счетчика
  • сохранить объект

Это просто объяснение основной идеи. Никогда не делайте этого так, потому что это не атомный. При определенной рабочей нагрузке вы можете назначить один и тот же идентификатор двум другим объектам, потому что они не являются атомарными. Это приведет к потере данных.

Решение состоит в использовании операции атомной ADD и ALL_NEW UpdateItem:

  • атомно генерировать идентификатор
  • используйте новый номер в качестве индекса объекта
  • сохранить объект

В худшем случае приложение аварийно завершает работу до того, как объект будет сохранен, но никогда не рискует дважды назначить один и тот же идентификатор.

Остается одна проблема: где сохранить последнее значение идентификатора? Мы выбрали:

{
    "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

По правде говоря, моя компания не использует его в производстве, потому что большую часть времени лучше найти другой ключ, например, для пользователя, идентификатор для транзакции, дату-время,...

Я написал несколько примеров в документации dynamodb-mapper и его можно легко экстраполировать на Node.JS

Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.

Ответ 2

Если у вас все в порядке с пробелами в увеличивающемся идентификаторе, и вы в порядке с ним, только приблизительно соответствующим порядку, в котором были добавлены строки, вы можете свернуть свою собственную: создайте отдельную таблицу с именем NextIdTable с одним первичным ключом ( числовой), назовите его Counter.

Каждый раз, когда вы хотите сгенерировать новый идентификатор, вы должны сделать следующее:

  • Сделайте GetItem для NextIdTable, чтобы прочитать текущее значение Counter → curValue
  • Сделайте PutItem для NextIdTable, чтобы установить значение Counter равным curValue + 1. Сделайте этот условный PutItem таким образом, чтобы он не работал, если значение Counter изменилось.
  • Если этот условный PutItem не удался, это означает, что кто-то другой делал это одновременно с вами. Начать сначала.
  • Если это удалось, то curValue - это ваш новый уникальный идентификатор.

Конечно, если ваш процесс завершится сбоем до фактического применения этого идентификатора в любом месте, вы "утечете" его и в вашей последовательности идентификаторов будет пробел. И если вы делаете это одновременно с каким-то другим процессом, один из вас получит значение 39, а другой - 40, и нет никаких гарантий относительно того, в каком порядке они будут фактически применяться в вашей таблице данных; парень, получивший 40, мог бы написать это раньше, чем парень, получивший 39. Но это дает вам грубый порядок.

Параметры условного PutItem в node.js подробно описаны здесь. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html. Если вы ранее прочитали значение 38 из Counter, ваш условный запрос PutItem может выглядеть следующим образом.

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

Ответ 3

Другим подходом является использование генератора UUID для первичных ключей, поскольку они вряд ли могут столкнуться.

IMO, вы с большей вероятностью столкнетесь с ошибками, консолидирующими счетчики первичных ключей в высокодоступных таблицах DynamoDB, чем из столкновений в сгенерированных UUID s.

Например, в 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.

Ответ 4

Я не верю, что это возможно для автоматического приращения стиля SQL, потому что таблицы разбиты на несколько машин. Я создаю свой собственный UUID в PHP, который выполняет эту работу, я уверен, что вы могли бы придумать что-то подобное как это в javascript.

Ответ 5

Дополнение к ответу @yadutaf

AWS поддерживает атомные счетчики.

Создайте отдельную таблицу (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
    }
  });

🛈 Имейте в виду, что в некоторых редких случаях могут возникнуть проблемы с соединением между точкой вызова и API AWS. Это приведет к увеличению строки динамодб, в то время как вы получите ошибку соединения. Таким образом, могут появиться некоторые неиспользованные увеличенные значения.

Вы можете использовать увеличенные data.Attributes.order_number в своей таблице, например, чтобы вставить {id: data.Attributes.order_number, otherfields:{}} в таблицу order.

Ответ 6

Для этих кодировок в Java DynamoDBMapper теперь может генерировать уникальные UUID от вашего имени.

DynamoDBAutoGeneratedKey

Помечает ключ раздела или свойство ключа сортировки как автоматически сгенерированный. DynamoDBMapper генерирует случайный UUID при сохранении этих атрибутов. Только свойства String могут быть помечены как автоматически сгенерированные ключи.

Используйте комментарий DynamoDBAutoGeneratedKey, подобный этому

@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 к тому же атрибуту для генерации уникального хеш-ключа.

Ответ 7

У меня была такая же проблема, и я создал небольшую веб-службу именно для этой цели. См. Это сообщение в блоге, в котором объясняется, как я использую stateful.co с DynamoDB, чтобы имитировать функции автоматического увеличения: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

В принципе, вы регистрируете атомный счетчик в stateful.co и увеличиваете его каждый раз, когда вам нужно новое значение, через RESTful API. Услуга бесплатна.

Ответ 8

Создайте новый 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,"");
}

Затем вы можете применить эту функцию к идентификатору первичного ключа. Он будет генерировать UUID.

Ответ 9

Используя схему AWS dynamodb data mapper в Node.js, хеш-ключ (id) будет сгенерирован автоматически. Автогенерируемые идентификаторы основаны на uuid v4.

Подробнее см. следующий пакет aws.

Data Mapper с аннотацией

Пакет Data Mapper для Javascript

Пример снайпера

@table('my_table')
class MyDomainClass {
    @autoGeneratedHashKey()
    id: string;

    @rangeKey({defaultProvider: () => new Date()})
    createdAt: Date;
}

Ответ 10

Автоинкремент не очень хорош с точки зрения производительности, поскольку он перегружает отдельные фрагменты, в то время как другие не работают. Он не обеспечивает равномерного распределения, если вы храните данные в Dynamodb.

awsRequestId выглядит как его V.4 UUID (Random), фрагмент кода ниже, чтобы попробовать это:

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/uuid или Ulide для генерации различных версий UUID на основе RFC-4122.

  • V1 (на основе отметки времени)
  • V3 (Пространство имен)
  • V4 (случайный)

Для разработчиков Go вы можете использовать эти пакеты от Google UUID, Pborman или Satori. Pborman лучше работает, проверьте эти статьи и тесты для получения более подробной информации.

Более подробную информацию о спецификации универсального уникального идентификатора можно найти здесь.