Optimistic hay Pessimistic Locking ?

Problem: Giả sử 2 user A và B đều đọc chung dữ liệu Customer từ Database, sau đó cả 2 cùng thay đổi dữ liệu 1 bản ghi (customer x trong Database) và cùng cố gắng ghi dữ liệu (đã thay đổi) của mình vào Database. Vậy thì thay đổi nào sẽ được thực hiện: của A, B, cả 2 hay không ai cả.

Solution: Các Developer sẽ sử dụng locking để quản lý việc truy cập dữ liệu dùng chung. Vậy chúng ta nên dùng cơ chế locking nào để sử dụng. Ở bài viết này, tôi sẽ trình bày 2 cơ chế locking cơ bản là Optimistic và Pessimistic.

I. Optimistic Offline Lock


a. Mục đích: ngăn ngừa conflict giữa các transactions nghiệp vụ đồng thời bằng việc phát hiện ra conflict và thực hiện rollback transaction.
Vấn đề tương tranh giữa các transaction thường xảy ra trong hệ thống có nhiều transactions đồng thời. Chúng ta không thể chỉ phụ thuộc vào việc quản lý database để đảm bảo các transaction nghiệp vụ sẽ ghi dữ liệu nhất quán được. Tính toàn vẹn của dữ liệu dễ ảnh hưởng bởi 2 session cùng hoạt động (update) trên các records, hoặc cũng có thể 1 session sửa dữ liệu và 1 session đọc dữ liệu không nhất quán cũng dễ xảy ra tương tự. Optimistic Offline Lock giải quyết được problem trên bằng việc xác thực các thay đổi về việc commited trên từng session để không conflict đến session khác.
b. Cách thức hoạt động:
* Optimistic Offline Lock chứa 1 điều kiện validate. Tại 1 thời điểm, 1 session load dữ liệu của 1 record, session khác không được thay thế nó.
* Cài đặt phổ biến nhất là sử dụng version number cho với mỗi record trong hệ thống. Khi 1 record được load thì number đại diện cho version chứa được bởi session cùng với tất cả các trạng thái của session. Optimistic Offline Lock sẽ quan tâm đến việc so sánh dữ liệu number version lưu trong session data và current session trong record data. Nếu 2 giá trị number version bằng nhau tức việc verify thành công thì tất cả các thay đổi, bao gồm cả việc tăng version sẽ được committed.
* Đối với Database RDBMS, 1 câu lệnh SQL có thể thực hiện lock và update dữ liệu record. Transaction nghiệp vụ sẽ kiểm tra giá trị row_count trả về bởi SQL execution. Nếu row_count = 1 tức là cập nhật thành công, row_count = 0 tức là record đã bị changed hoặc deleted. Với row_count = 0, transaction nghiệp vụ bắt buộc phải thực hiện rollback lại system transaction để ngăn ngừa các thay đổi tác động vào record data.
* Ngoài thông tin version number của mỗi record, thông tin lưu trữ còn có thêm như user thực hiện modified record cuối cùng hoặc timestamp thời gian thay đổi.
* Có thể sử dụng câu điều kiện update vào tất cả các trường trong row:
UPDATE Customer SET …, version = (session’s copy of version + 1) WHERE id=? and version= session’s copy of version

II. Pessimistic Offline Lock


a. Mục đích: Với cách tiếp cận Optimistic Offline Locking không giải quyết triệt để được với các trường hợp người dùng truy cập cùng một dữ liệu trong một transaction (1 transaction sẽ commit thành công và 1 transaction sẽ failed => rollback). Bởi vì sự phát hiện conflict xảy ra ở giai đoạn cuối transaction, do đó dữ liệu đã xử lý của transaction failed sẽ là lãng phí ?
Pessimistic Offline Lock đã ngăn ngừa việc conflict giữa chúng với nhau bằng cách khi thực hiện transaction sẽ lock dữ liệu trước khi sử dụng nó, trong thời gian transaction sử dụng dữ liệu đó sẽ đảm bảo chắc chắn việc không có xung đột nào xảy ra.

b. Cách thức hoạt động:
Để cài đặt được Pessimistic Offline Lock cần làm:
– Xác định kiểu của lock mà bạn cần dùng
– Xây dựng lock manager
– Xác định đối tượng cho transaction để sử dụng locks.

Về lock type, chúng ta có 3 sự lựa chọn:
– Exclusive Write Lock: chỉ cho phép 1 transaction được thực thi việc ghi dữ liệu. Nó sẽ tránh được conflict bởi không cho phép 2 transactions nghiệp vụ nào được thay đổi cùng 1 dữ liệu đồng thời.
– Exclusive Read Lock: chỉ có phép 1 transaction được thực thi đọc dữ liệu. 2 transactions sẽ không được đọc dữ liệu đồng thời
– Exclusive Read and Write Lock: 1 record không thể bị thực hiện write-lock khi 1 transaction khác đang sở hữu read lock trên nó và ngược lại. Concurrent read locks được chấp nhận. Tồn tại 1 single read lock ngăn ngừa business transaction từ việc sửa dữ liệu, nó sẽ không ảnh hưởng gì trong việc cho phép các sessions khác cùng đọc.

Xây dựng lock manager: Công việc của Lock Manager là grant hoặc deny bất kỳ request nào bởi transaction nghiệp vụ cho việc thực thi hoặc release 1 lock. Để làm công việc đó, Lock Manager cần biết rõ những gì sẽ bị lock như là ý định của người lock. Session và business transaction gần tương đương và có thể thay thế. Lock Manager không nên chứa nhiều hơn 1 table quản lý các lock của owner. Đơn giản nhất là 1 in-memory hash table hoặc 1 database table. Các transaction chỉ nên tương tác với lock manager và không được tương tác với lock object.

Chúng ta thường lock các object hoặc record, nhưng thật ra thứ cần lock thực sự là ID hoặc Primary Key (thứ để xác định tìm ra object). Nó cho phép chúng ta chứa lock trước khi load chúng.

Đối với Database RDBMS, ví dụ như MySQL có hỗ trợ 2 cơ chế lock là:
* Shared Lock Statement: LOCK IN SHARED MODE. Ví dụ: Có 2 bảng PARENT và CHILD, khi transaction thực hiện insert dữ liệu vào bảng CHILD cần đảm bảo rằng dữ liệu parent_id phải tồn tại ở bảng PARENT tại thời điểm đó.

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

Sau khi LOCK IN SHARE MODE, câu query sẽ trả về giá trị Jones và transaction có thể an toàn thực hiện insert dữ liệu vào bảng CHILD. Trong thời điểm đó các transaction khác thực hiện UPDATE, DELETE lên row chứa giá trị Jones sẽ phải chờ transaction ban đầu hoàn thành.
* Exclusive Lock Statement: FOR UPDATE. Cách giải quyết trên sẽ gặp phải vấn đề nếu 2 transaction cùng thực hiện đọc bảng PARENT với row Jones, và đều đọc được dữ liệu sau đó insert sẽ bị duplicate giá trị. Cách khắc phục triệt để là sử dụng SELECT FOR UPDATE:

SELECT * FROM parent WHERE NAME = 'Jones' FOR UPDATE;

Khi thực hiện FOR UPDATE, transaction khác sẽ không tìm thấy dữ liệu từ bảng parent với row có name là Jones.

Kết luận

Chúng ta sẽ sử dụng mỗi cơ chế locking vào mỗi nghiệp vụ khác nhau:
* Optimistic Locking sử dụng phù hợp trong các trường hợp có nghiệp vụ xác suất conflict giữa 2 transaction là thấp. Nhược điểm của Optimistic Offline Locking là chỉ verify trên các câu lệnh UPDATE và DELETE, vẫn có thể gây ra inconsistent khi read dữ liệu.
* Pessimistic Locking sử dụng phù hợp trong các nghiệp vụ có khả năng xảy ra conflict cao. Nếu bạn sử dụng Pessimistic Lock, bạn nên cân nhắc đến việc xử lý timeout cho các long transaction để tránh deadlock.

References

  • Patterns of Enterprise Application Architecture (https://martinfowler.com/eaaCatalog/optimisticOfflineLock.html) (https://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html)
  • https://blog.couchbase.com/optimistic-or-pessimistic-locking-which-one-should-you-pick/

Add a Comment

Scroll Up