Bạn đang sử dụng DynamoDB và gặp vấn đề khi nhiều yêu cầu cập nhật cùng lúc vào một thuộc tính, dẫn đến mất dữ liệu? Đây là một thách thức phổ biến trong các ứng dụng có tính đồng thời cao. Bài viết này sẽ cung cấp cho bạn các giải pháp thiết thực và hiệu quả để giải quyết vấn đề này, đảm bảo tính toàn vẹn dữ liệu trong DynamoDB.
Khi một người dùng thực hiện nhiều yêu cầu cập nhật gần như đồng thời vào cùng một mục (item) trong DynamoDB, có thể xảy ra tình trạng mất dữ liệu. Ví dụ, giả sử bạn có một trường "counter" (bộ đếm) cho mỗi người dùng, và mỗi yêu cầu sẽ tăng giá trị của bộ đếm này. Nếu 5 yêu cầu được gửi cùng lúc với giá trị tăng là 5, thì bộ đếm lẽ ra phải tăng 25. Tuy nhiên, thực tế có thể chỉ tăng 10 hoặc 15. Điều này xảy ra do các yêu cầu ghi đè lên nhau trước khi tất cả được xử lý.
Nguyên nhân chính là do cách tiếp cận "đọc-thay đổi-ghi" (read-modify-write) thông thường. Khi nhiều tiến trình cùng đọc giá trị cũ, thực hiện tính toán, và sau đó ghi giá trị mới, kết quả có thể không chính xác nếu một tiến trình ghi trước, và các tiến trình khác ghi đè lên giá trị đó mà không biết đến sự thay đổi.
Optimistic Locking là một kỹ thuật hiệu quả để ngăn chặn việc ghi đè dữ liệu không mong muốn. Ý tưởng cơ bản là thêm một thuộc tính "version" (phiên bản) vào mỗi mục trong DynamoDB. Mỗi khi bạn đọc một mục, bạn cũng ghi lại số phiên bản của nó. Khi bạn muốn cập nhật mục đó, bạn bao gồm số phiên bản hiện tại trong điều kiện cập nhật. DynamoDB sẽ chỉ thực hiện cập nhật nếu số phiên bản trong yêu cầu của bạn khớp với số phiên bản hiện tại trong cơ sở dữ liệu.
Nếu có một sự khác biệt về phiên bản (version mismatch), điều đó có nghĩa là một người khác đã sửa đổi mục trước bạn. Yêu cầu cập nhật của bạn sẽ thất bại, và bạn cần phải thử lại bằng cách đọc lại mục và thử cập nhật lại. Điều này giúp ngăn bạn vô tình ghi đè lên những thay đổi đã được thực hiện bởi người khác.
UpdateItem
tới DynamoDB, bao gồm một điều kiện (ConditionExpression) để chỉ cập nhật nếu version = 3
.UpdateItem
.Đối với các trường hợp đơn giản như tăng hoặc giảm một bộ đếm, bạn có thể sử dụng toán tử ADD
trong lệnh UpdateItem
của DynamoDB. Toán tử này cho phép bạn thực hiện các thao tác số học một cách an toàn, mà không cần phải đọc giá trị hiện tại trước. DynamoDB sẽ tự động xử lý các vấn đề đồng thời cho bạn.
Ví dụ, để tăng giá trị của trường "counter" thêm 5, bạn có thể sử dụng lệnh sau:
aws dynamodb update-item \
--table-name your_table_name \
--key '{"user_id": {"S": "user123"}}' \
--update-expression "ADD counter :val" \
--expression-attribute-values '{":val": {"N": "5"}}'
Lệnh này sẽ đảm bảo rằng bộ đếm được tăng thêm 5, ngay cả khi có nhiều yêu cầu được gửi cùng lúc.
Nếu bạn cần thực hiện các phép toán phức tạp hơn, hoặc cần đảm bảo rằng một số điều kiện nhất định phải được đáp ứng trước khi cập nhật, bạn có thể sử dụng Conditional Updates. Điều này cho phép bạn chỉ thực hiện cập nhật nếu giá trị của một hoặc nhiều thuộc tính thỏa mãn một điều kiện nhất định. DynamoDB sẽ kiểm tra điều kiện này trước khi thực hiện cập nhật, đảm bảo tính nhất quán của dữ liệu.
Ví dụ, bạn có thể cập nhật trường "balance" (số dư) của một tài khoản, nhưng chỉ khi số dư hiện tại lớn hơn hoặc bằng một số tiền nhất định:
aws dynamodb update-item \
--table-name your_table_name \
--key '{"account_id": {"S": "account456"}}' \
--update-expression "SET balance = balance - :amount" \
--condition-expression "balance >= :amount" \
--expression-attribute-values '{":amount": {"N": "100"}}'
Nếu số dư không đủ, yêu cầu sẽ thất bại và bạn sẽ nhận được một ngoại lệ ConditionalCheckFailedException
.
Việc xử lý cập nhật đồng thời trong DynamoDB đòi hỏi sự cẩn trọng để tránh mất dữ liệu. Bằng cách sử dụng Optimistic Locking, toán tử ADD
, hoặc Conditional Updates, bạn có thể đảm bảo tính toàn vẹn dữ liệu và xây dựng các ứng dụng mạnh mẽ và đáng tin cậy trên nền tảng DynamoDB. Hãy lựa chọn giải pháp phù hợp nhất với trường hợp cụ thể của bạn để đạt được hiệu quả tối ưu.
Bài viết liên quan