Verwendung der automatischen Inkrementierung für die Primärschlüssel-ID in Dynamodb

Antworten:

62

DynamoDB bietet dies nicht sofort an. Sie können in Ihrer Anwendung etwas generieren, z. B. UUIDs, die für die meisten Systeme eindeutig genug sein sollten.

Ich habe festgestellt, dass Sie Node.js verwenden (ich habe Ihr Tag entfernt). Hier ist eine Bibliothek, die UUID-Funktionalität bietet: Node- UUID

Beispiel aus README

var uuid = require('node-uuid');
var uuid1 = uuid.v1();
var uuid2 = uuid.v1({node:[0x01,0x23,0x45,0x67,0x89,0xab]});
var uuid3 = uuid.v1({node:[0, 0, 0, 0, 0, 0]})
var uuid4 = uuid.v4();
var uuid5 = uuid.v4();
Tier1
quelle
2
FWIW Ich verwende diesen Ansatz (UUID als Hash-Schlüssel) mit Dynamo und er hat großartig funktioniert.
RPMartz
8
Diese Antwort sollte als die richtige Antwort markiert werden. Es ist auch erwähnenswert, warum: Sie möchten eine gleichmäßige Verteilung der Schlüssel, und eine automatische Inkrementierung würde zu einer ungleichmäßigen Verteilung führen. Weitere Informationen finden Sie in diesem Artikel: forums.aws.amazon.com/thread.jspa?messageID=312527 und die AWS-Dokumente hier: docs.aws.amazon.com/amazondynamodb/latest/developerguide/…
Lane Rettig
Verwenden Sie uuid, da node-uuid jetzt veraltet ist.
node_saini
54

Dies ist ein Anti-Pattern in DynamoDB, das so aufgebaut ist, dass es über viele Partitionen / Shards / Server skaliert. DynamoDB unterstützt aufgrund von Skalierungsbeschränkungen keine automatisch inkrementierten Primärschlüssel und kann nicht auf mehreren Servern garantiert werden.

Die bessere Option besteht darin, den Primärschlüssel aus mehreren Indizes zusammenzusetzen. Der Primärschlüssel kann bis zu 2048 Byte betragen. Es gibt nur wenige Optionen:

  1. Verwenden Sie die UUID als Schlüssel - möglicherweise eine zeitbasierte UUID, die sie eindeutig, gleichmäßig verteilt und zeitlich wertvoll macht
  2. Verwenden Sie zufällig generierte Zahlen oder Zeitstempel + zufällig (möglicherweise bitverschiebend) wie: ts << 12 + random_number
  3. Verwenden Sie einen anderen Dienst oder DynamoDB selbst, um eine inkrementelle eindeutige ID zu generieren (erfordert zusätzlichen Aufruf).

Der folgende Code erhöht den Zähler in DynamoDB automatisch und kann dann als Primärschlüssel verwendet werden.

var documentClient = new AWS.DynamoDB.DocumentClient();
var params = {
  TableName: 'sampletable',
  Key: { HashKey : 'counters' },
  UpdateExpression: 'ADD #a :x',
  ExpressionAttributeNames: {'#a' : "counter_field"},
  ExpressionAttributeValues: {':x' : 1},
  ReturnValues: "UPDATED_NEW" // ensures you get value back
};
documentClient.update(params, function(err, data) {});
// once you get new value, use it as your primary key

Mein persönlicher Favorit ist die Verwendung von Zeitstempel + Zufall, inspiriert von der Sharding ID-Generierung von Instagram unter http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram

Die folgende Funktion generiert eine ID für einen bestimmten Shard (als Parameter bereitgestellt). Auf diese Weise können Sie einen eindeutigen Schlüssel erhalten, der aus dem Zeitstempel, Splitter Nr. und etwas Zufälligkeit (0-512).

var CUSTOMEPOCH = 1300000000000; // artificial epoch
function generateRowId(shardId /* range 0-64 for shard/slot */) {
  var ts = new Date().getTime() - CUSTOMEPOCH; // limit to recent
  var randid = Math.floor(Math.random() * 512);
  ts = (ts * 64);   // bit-shift << 6
  ts = ts + shardId;
  return (ts * 512) + randid;
}
var newPrimaryHashKey = "obj_name:" + generateRowId(4);
// output is: "obj_name:8055517407349240"
vladaman
quelle
1
Können Sie am Ende weitere Details zu Ihrem 2. Punkt und dem Code hinzufügen? Soll subIdes sich um eine Shard-ID handeln oder so?
Andrhamm
@andrhamm Es sieht auf jeden Fall aus wie die Shard ID obwohl 4? Der Referenzartikel verwendet die Formel userId% shardTotal (13 Bit).
Eli Peters
1
Könnten Sie bitte die Verwendung der Bitverschiebung erklären?
Rangfu
2
@vladaman Was ist der Sinn der Verwendung var randid = Math.floor(Math.random() * 512); ... randid % 512 sollte eine Zahl zwischen 0 und 511 in der ersten Zeile angeben . Die Verwendung von Modulo 512 für eine solche Nummer ändert die Nummer nicht.
BennyHilarious
Beachten Sie, dass Sie mit diesem Ansatz den Zeitstempel nicht aus der ID abrufen können (wie im Beispiel des Instagram), da Sie den zufälligen Teil nicht kennen.
Mark Hkr
1

Sie können wahrscheinlich AtomicCounters verwenden .

Mit AtomicCounters können Sie die UpdateItem-Operation verwenden, um einen Atomzähler zu implementieren - ein numerisches Attribut, das bedingungslos erhöht wird, ohne andere Schreibanforderungen zu beeinträchtigen. (Alle Schreibanforderungen werden in der Reihenfolge angewendet, in der sie empfangen wurden.) Bei einem Atomzähler sind die Aktualisierungen nicht idempotent. Mit anderen Worten, der numerische Wert erhöht sich jedes Mal, wenn Sie UpdateItem aufrufen.

Sie können einen Atomzähler verwenden, um die Anzahl der Besucher einer Website zu verfolgen. In diesem Fall würde Ihre Anwendung einen numerischen Wert unabhängig von seinem aktuellen Wert erhöhen. Wenn ein UpdateItem-Vorgang fehlschlägt, kann die Anwendung den Vorgang einfach wiederholen. Dies würde dazu führen, dass der Zähler zweimal aktualisiert wird, aber Sie könnten wahrscheinlich eine leichte Über- oder Unterzählung von Website-Besuchern tolerieren.

so zufälliger Typ
quelle
1
Dies kann zu Hotkey-Problemen führen, da eine Partition höchstens 3000 IOPS haben kann. 1 RCU = 1 IOPS. 1 WCU = 3 IOPS. Außerdem wird es langsam sein, AtomicCounter als ID-Generator zu verwenden, da Inkremente seriell ausgeführt werden.
Guangtong Shen
1
Nur um es zusammenzufassen (für mich selbst und um anderen zu helfen): @vladamans Antwort zeigt tatsächlich diese AtomicCounter-Technik. Und genau wie @ guangtongShen erwähnt hat, ist diese Technik NICHT skalierbar! (Ich verwende es nur bei Operationen mit geringer Intensität. ZB wenn "Erstellen eines Elements" sehr, sehr selten vorkommt. Und normalerweise sollte dieser Ansatz zugunsten von UUIDs vermieden werden (wie auch in der Anfrage von vladaman erwähnt)
Dimitry K
0

Wenn Sie NoSQL Dynamo DB verwenden und dann Dynamoose verwenden, können Sie einfach die eindeutige Standard-ID festlegen. Hier ist das einfache Beispiel für die Benutzererstellung

// User.modal.js

const dynamoose = require("dynamoose");
const { v4: uuidv4 } = require("uuid");

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;

// User.controller.js

exports.create = async (req, res) => {
  const user = new User({ id: uuidv4(), ...req.body }); // set unique id
  const [err, response] = await to(user.save());
  if (err) {
    return badRes(res, err);
  }
  return goodRes(res, reponse);
};
Hammad Tariq
quelle