2012-07-30 25 views
17

Trong lược đồ db của tôi, tôi cần một khóa chính autoincrement. Làm thế nào tôi có thể nhận ra tính năng này?Làm thế nào để tạo UUID trong DynamoDB?

PS Để truy cập vào DynamoDB, tôi sử dụng dynode, mô-đun cho Node.js.

+0

Hãy xem thuật toán [twitters snowflake] (https://github.com/twitter/snowflake) –

Trả lời

15

Disclaimer: Tôi là nhà duy trì của dự án Dynamodb-mapper

workflow trực quan của một chìa khóa tự động tăng:

  1. có được truy cập cuối cùng vị trí
  2. thêm 1
  3. sử dụng số mới làm chỉ mục của đối tượng
  4. lưu giá trị bộ đếm mới
  5. lưu đối tượng

Đây chỉ là để giải thích ý tưởng cơ bản. Không bao giờ làm theo cách này bởi vì nó không phải nguyên tử. Theo khối lượng công việc nhất định, bạn có thể phân bổ cùng một ID cho 2+ đối tượng khác nhau vì nó không phải là nguyên tử. Điều này sẽ dẫn đến mất dữ liệu.

Các giải pháp là sử dụng Thanh nguyên tử hoạt động cùng với ALL_NEW của UpdateItem:

  1. nguyên tử tạo ra một ID
  2. sử dụng số điện thoại mới như chỉ số của đối tượng
  3. tiết kiệm đối tượng

Trong trường hợp xấu nhất, ứng dụng treo trước khi đối tượng được lưu nhưng không bao giờ có nguy cơ phân bổ cùng một ID hai lần.

Có một vấn đề còn lại: nơi lưu trữ giá trị ID cuối cùng? Chúng tôi đã chọn:

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

Tất nhiên, bạn phải ghi đè dữ liệu.

bước cuối cùng là tự động hóa quy trình. Ví dụ:

When hash_key is 0: 
    atomically_allocate_ID() 
actual_save() 

Để biết chi tiết thi hành (Python, xin lỗi), xem https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67

Để cho bạn biết sự thật, công ty của tôi không sử dụng nó trong sản xuất vì, hầu hết thời gian nó là tốt hơn để tìm phím khác như thế nào, cho người dùng, ID, cho một giao dịch, một datetime, ...

tôi đã viết một số ví dụ trong dynamodb-mapper's documentation và nó có thể dễ dàng suy luận để Node.js

Nếu bạn có bất kỳ câu hỏi , hãy hỏi.

+1

Thật tuyệt, nhưng bây giờ tôi đang sử dụng dấu thời gian và số ngẫu nhiên. Cảm ơn PS lớn vì câu trả lời tuyệt vời này và cảm ơn vì đã cải tiến DynamoDB. – NiLL

+3

Một cách giải quyết khác là sử dụng bộ đếm Redis, vì vậy bạn giảm A LOT sự căng thẳng và hoạt động của DynamoDB. Khi bạn làm một chèn, bạn yêu cầu Redis bộ đếm hiện tại và tăng nó. Nếu redis không có bộ đếm, nó sẽ hỏi DynamoDB ID mới nhất, và sau đó lưu nó. –

2

Tôi không tin rằng có thể tự động tăng kiểu SQL vì các bảng được phân đoạn trên nhiều máy. Tôi tạo ra UUID của riêng tôi trong PHP mà không công việc, tôi chắc chắn bạn có thể đến với một cái gì đó tương tự like this trong javascript.

2

Tôi đã gặp sự cố tương tự và đã tạo một dịch vụ web nhỏ chỉ nhằm mục đích này. Xem bài viết trên blog này, giải thích làm thế nào tôi đang sử dụng stateful.co với DynamoDB để mô phỏng chức năng auto-increment: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

Về cơ bản, bạn đăng ký một quầy nguyên tử tại stateful.co và tăng nó mỗi khi bạn cần một giá trị mới, thông qua API RESTful. Dịch vụ này miễn phí.

+0

Ổn định này được sử dụng như thế nào trong sản xuất? Thống kê thời gian hoạt động là gì? – Mirage

+0

@Mirage thống kê 1000 ngày cuối cùng từ statuscake.com: https://www.statuscake.com/App/button/index.php?Track=vAZJhwOtwc&Days=1000&Design=1 – yegor256

4

Nếu bạn đồng ý với khoảng trống trong id gia tăng của mình và bạn không sao với nó chỉ tương ứng với thứ tự các hàng được thêm vào, bạn có thể cuộn riêng: Tạo bảng riêng biệt có tên NextIdTable, với một khóa chính (số), gọi nó là Counter.

Mỗi khi bạn muốn tạo một id mới, bạn sẽ làm như sau:

  • Thực hiện GetItem trên NextIdTable để đọc các giá trị hiện tại của Counter -> curValue
  • Thực hiện PutItem trên NextIdTable để đặt giá trị của Counter thành curValue + 1. Đặt nó thành một PutItem có điều kiện để nó sẽ thất bại nếu giá trị của Counter đã thay đổi.
  • Nếu điều đó PutItem có điều kiện không thành công, điều đó có nghĩa là người khác đang làm việc này cùng lúc với bạn. Bắt đầu lại.
  • Nếu thành công, thì curValue là ID duy nhất mới của bạn.

Tất nhiên, nếu quá trình của bạn bị treo trước khi thực sự áp dụng ID đó ở bất kỳ đâu, bạn sẽ "rò rỉ" và có khoảng trống trong chuỗi ID của bạn. Và nếu bạn đang làm điều này đồng thời với một số quy trình khác, một trong số bạn sẽ nhận được giá trị 39 và một trong số bạn sẽ nhận được giá trị 40 và không có đảm bảo về thứ tự nào sẽ thực sự được áp dụng trong bảng dữ liệu của bạn; người có 40 người có thể viết nó trước khi anh chàng có 39. Nhưng nó cho bạn một thứ tự thô.

Các tham số cho một điều kiện PutItem trong node.js được nêu chi tiết tại đây. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html. Nếu trước đây bạn đã đọc giá trị 38 từ Counter, yêu cầu PutItem có điều kiện của bạn có thể trông như thế này.

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

Tạo mới file.js và đặt mã này:

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

Sau đó, bạn có thể áp dụng chức năng này để id khóa chính. Nó sẽ tạo ra UUID.

1

bổ sung @ yadutaf của câu trả lời

AWS hỗ trợ Atomic Counters.

Tạo một bảng riêng biệt (order_id) với một hàng giữ ORDER_NUMBER mới nhất:

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

này sẽ cho phép để tăng ORDER_NUMBER bởi 1 và nhận được kết quả tăng lên trong một callback từ 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 
    } 
    }); 

Xin lưu ý rằng trong một số trường hợp hiếm hoi trường hợp của họ có thể là sự cố với kết nối giữa điểm người gọi và API AWS của bạn.Nó sẽ dẫn đến hàng dynamodb được tăng lên, trong khi bạn sẽ nhận được một lỗi kết nối. Do đó, có thể xuất hiện một số giá trị tăng dần không sử dụng.

Bạn có thể sử dụng số tăng thêm data.Attributes.order_number trong bảng của mình, ví dụ: để chèn {id: data.Attributes.order_number, otherfields:{}} vào bảng order.

1

Cách tiếp cận khác là sử dụng trình tạo UUID cho khóa chính, vì đây là cao không thể đụng độ.

IMO bạn có nhiều khả năng gặp lỗi khi hợp nhất các bộ đếm khóa chính trên bảng DynamoDB có sẵn cao hơn so với các xung đột trong số UUID s được tạo.

Ví dụ, trong 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' 

Taken từ SO answer.

0

Đối với những mã này trong Java, DynamoDBMapper hiện có thể tạo UUID duy nhất nhân danh bạn.

DynamoDBAutoGeneratedKey

Đánh dấu một chìa khóa phân vùng hoặc tài sản loại chìa khóa như là tự động tạo ra. DynamoDBMapper sẽ tạo ra một UUID ngẫu nhiên khi lưu các thuộc tính này. Chỉ các thuộc tính Chuỗi có thể được đánh dấu là các khóa được tạo tự động.

Sử dụng DynamoDBAutoGeneratedKey chú thích như thế này

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

Như bạn có thể thấy trong ví dụ trên, bạn có thể áp dụng cả DynamoDBAutoGeneratedKey và DynamoDBHashKey chú thích vào thuộc tính tương tự để tạo ra một chìa khóa băm độc đáo.