2012-07-30 26 views
17

En mi esquema db, necesito una clave primaria autoincrement. ¿Cómo puedo realizar esta característica?¿Cómo hacer un UUID en DynamoDB?

PD Para acceder a DynamoDB, uso dynode, módulo para Node.js.

+0

Eche un vistazo al algoritmo [twitters snowflake] (https://github.com/twitter/snowflake) –

Respuesta

15

responsabilidad: yo soy el mantenedor del proyecto DynamoDB mapeador

flujo de trabajo intuitivo de una clave de incremento automático:

  1. obtener el último contador de posición
  2. añadir al menos 1
  3. utilice el nuevo número como el índice del objeto
  4. guardar el nuevo valor de contador
  5. guardar el objeto

Esto es solo para explicar la idea subyacente. Nunca lo hagas de esta manera porque no es atómico. Bajo cierta carga de trabajo, puede asignar la misma ID a más de 2 objetos diferentes porque no es atómica. Esto daría como resultado una pérdida de datos.

La solución es utilizar la atómica ADD operación junto con ALL_NEW de UpdateItem:

  1. generan atómicamente un ID
  2. utilizar el nuevo número que el índice del objeto
  3. Guardar el objeto

En el peor de los casos, la aplicación se bloquea antes de que se guarde el objeto, pero nunca se arriesga a asignar la misma ID dos veces.

Existe un problema: ¿dónde almacenar el último valor de ID? Elegimos:

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

Por supuesto, para funcionar de forma fiable, todas las aplicaciones de inserción de datos debe estar al tanto de este sistema lo contrario puede que (de nuevo) sobrescribir los datos.

el último paso es automatizar el proceso. Por ejemplo:

When hash_key is 0: 
    atomically_allocate_ID() 
actual_save() 

para detalles de implementación (Python, lo siento), ver https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67

A decir verdad, mi empresa no lo utiliza en la producción, ya que, la mayoría de las veces es mejor encontrar otra clave como, para el usuario, una identificación, para una transacción, una fecha y hora, ...

me escribió algunos ejemplos en dynamodb-mapper's documentation y se puede fácilmente extrapolar a Node.JS

Si usted tiene cualquier pregunta , Siéntete libre de preguntar.

+1

Es bueno, pero ahora estoy usando una marca de tiempo y números aleatorios. PD Muchas gracias por esta gran respuesta, y gracias por mejorar DynamoDB. – NiLL

+3

Otra solución sería usar el contador Redis, por lo que se reduce MUCHO el estrés y las operaciones a DynamoDB. Cuando haces un inserto, le pides a Redis el contador actual y lo aumentas. Si redis no tiene el contador, le pide a DynamoDB la última identificación, y luego la almacena. –

2

No creo que sea posible realizar un autoincremento de estilo SQL porque las tablas están divididas en varias máquinas. Genero mi propio UUID en PHP que hace el trabajo, estoy seguro de que podrías encontrar algo similar like this en javascript.

2

He tenido el mismo problema y he creado un pequeño servicio web solo para este propósito. Ver esta entrada del blog, que explica cómo estoy usando stateful.co con DynamoDB con el fin de simular la funcionalidad de incremento automático: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

Básicamente, se registra un contador atómica en stateful.co y se incrementará cada vez que necesita un nuevo valor, a través de API RESTful El servicio es gratis

+0

¿Qué tan estable es esto para ser utilizado en producción? ¿Cuáles son las estadísticas de tiempo de actividad? – Mirage

+0

@Mirage las últimas estadísticas de 1000 días de statuscake.com: https://www.statuscake.com/App/button/index.php?Track=vAZJhwOtwc&Days=1000&Design=1 – yegor256

4

Si está de acuerdo con las lagunas en su ID de incremento, y está de acuerdo con que solo aproximadamente en el orden en que se agregaron las filas, puede hacer las suyas propias: Cree una tabla separada llamada NextIdTable, con una tecla principal (numérica), llámalo Contador.

Cada vez que desee generar una nueva identificación, lleve a cabo lo siguiente:

  • Hacer un GetItem en NextIdTable para leer el valor actual del contador -> curValue
  • Hacer un PutItem en NextIdTable para establecer el valor de Counter en curValue + 1. Establezca este putItem condicional para que falle si el valor de Counter ha cambiado.
  • Si ese PutItem condicional falló, significa que alguien más estaba haciendo esto al mismo tiempo que usted. Comenzar de nuevo.
  • Si tiene éxito, entonces curValue es su nueva identificación única.

Por supuesto, si su proceso se bloquea antes de realmente aplicar ese ID en cualquier lugar, lo "filtrará" y tendrá un espacio en su secuencia de identificaciones. Y si está haciendo esto simultáneamente con algún otro proceso, uno de ustedes obtendrá el valor 39 y uno de ustedes obtendrá el valor 40, y no hay garantías sobre qué orden se aplicará realmente en su tabla de datos; el chico que tiene 40 podría escribirlo antes que el chico que tiene 39. Pero te da un orden aproximado.

Los parámetros para un PutItem condicional en node.js se detallan aquí. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html. Si anteriormente había leído un valor de 38 en el contador, su solicitud condicional de elemento de imagen podría verse así.

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

crear el nuevo file.js y poner este código:

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,""); 
} 

continuación, puede aplicar esta función a la identificación de clave primaria. Generará el UUID.

1

adición a @ de yadutaf respuesta

AWS apoya Atomic Counters.

Crear una tabla separada (order_id) con un registro que tiene la última número_pedido:

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

Esto permitirá incrementar número_pedido por 1 y obtener el resultado incrementado en una devolución de llamada desde 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 
    } 
    }); 

Tenga en cuenta que en algunos casos raros pueden haber problemas con la conexión entre su punto de llamada y la API de AWS.Dará como resultado que la fila dynamodb se incremente, mientras que obtendrá un error de conexión. Por lo tanto, es posible que aparezcan algunos valores incrementales no utilizados.

Puede usar incrementado data.Attributes.order_number en su tabla, p. para insertar {id: data.Attributes.order_number, otherfields:{}} en la tabla order.

1

Otro enfoque es utilizar un generador UUID para las claves principales, ya que son altamente poco probable que entren en conflicto.

IMO es más probable que experimente errores al consolidar los contadores de claves primarias en las tablas de alta disponibilidad DynamoDB que en los conflictos generados en UUID s.

Por ejemplo, en el Nodo:

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' 

Tomado de SO answer.

0

Para aquellos que codifican en Java, DynamoDBMapper ahora puede generar UUID únicos en su nombre.

DynamoDBAutoGeneratedKey

marca una clave de partición o la propiedad clave de ordenación por ser generada automáticamente. DynamoDBMapper generará un UUID aleatorio al guardar estos atributos . Solo las propiedades de cadena se pueden marcar como claves autogeneradas .

Utilice la anotación DynamoDBAutoGeneratedKey como esto

@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; } 

Como se puede ver en el ejemplo anterior, se puede aplicar tanto a la DynamoDBAutoGeneratedKey y anotación DynamoDBHashKey para el mismo atributo para generar una clave hash único.