[Lập trình] Optimistic vs Pessimistic Locking

Chắc hẳn nếu ai đã từng lập trình đa luồng (multi thread) thì đã từng nghe đến 2 khái niệm này. Dùng google translate thì chúng ta có thể hiểu nôm na, optimistic locking nghĩa là cơ chế nắm giữ tài nguyên máy tính (lock resource) một cách lạc quan, tích cực. Chính xác hơn, nó cho phép các thread có thể cùng đọc, ghi và sửa đổi dữ liệu tại cùng 1 thời điểm. Trái ngược với optimistic locking, thì ta có pessimistic locking. Pessimistic dịch nghĩa là bi quan. Đúng như vậy, cơ chế pessimistic chỉ cho phép 1 thread(ta gọi là thread chính) có thể truy cập vào 1 tài nguyên để thay đổi nó. Cùng thời điểm đó, các thread khác chỉ có thể đọc dữ liệu do thread chính ban đầu ghi vào mà không có quyền thay đổi dữ liệu đó, trừ khi thread chính đã nhả quyền nắm giữ dữ liệu.


Đối với pessimistic locking, ta có thể hiểu đơn giản như 1 ổ khoá chỉ có duy nhất 1 chìa khoá. Chỉ có người duy nhất nắm giữ chìa khoá đó mới có thể truy cập vào nhà và sử dụng các dịch vụ trong nhà. Những người khác sẽ không thể truy cập trái phép vào nhà nếu không được sự cho phép của chủ nhà (người nắm giữ chìa khoá duy nhất). Đối với cơ chế pessimistic locking, việc quản lý các luồng truy cập đến dữ liệu sẽ vô cùng đơn giản tuy nhiên nó sẽ làm giảm hiệu năng đáng kể của hệ thống, chưa kể việc sẽ gây ra cảm giác khó chịu cho người dùng trong trường hợp có nhiều người cùng đang truy cập vào cùng 1 file.

Ngược lại với cơ chế optimistic locking, tại cùng 1 thời điểm có thể cho phép nhiều luồng cùng ghi dữ liệu vào 1 đích (target). Bài toán này đòi hỏi phải giải quyết được vấn đề: "Dữ liệu nào sẽ được ghi vào?". Ta có thể lấy 1 ví dụ đơn giản để minh hoạ cho cơ chế optimistic locking, đó là Excel online. Khi file excel được share cho 1 nhóm người. Những người được share sẽ có quyền thay đổi nội dung của file được chia sẻ. Excel sẽ có các cơ chế để tránh việc conflict (xung đột) xảy ra đối với chúng.

1. Phương pháp thứ nhất là gắn cờ cảnh báo. Khi ai đó đang sửa nội dung tại một ô, một dòng trong excel, sẽ có một thông báo cho người dùng cùng lúc là "ai đó đang sửa nội dung này". Bạn có thể refresh page hoặc chờ cho người dùng đó thay đổi xong. Tuy nhiên không phải lúc nào người dùng cũng chú ý đến cảnh báo của Excel. Nếu cả hai người dùng cùng thay đổi nội dung ở một dòng thì sao??? Lúc đấy excel sẽ quyết định xem nội dung nào sẽ được hiển thị bằng bài toán versioning.
2. Vậy bài toán versioning là gì? Excel sẽ đánh tag version cho các phiên bản mà người dùng ghi vào. Giả sử tại thời điểm t1, cả 2 người dùng A và B cùng đọc dữ liệu từ file, lúc này version của file đang là v1. Sau đó tại thời điểm t2, người dùng A thay đổi nội dung của file, Excel sẽ kiểm tra version của file xem có khớp với version mà người A ghi xuống ko? Tất nhiên là nó cho phép dữ liệu dược ghi xuống do có cùng v1 và tự động tăng version lên là v2. Tuy nhiêm sau đó, tại thời điểm t3, người B mới ghi dữ liệu của mình vào. Tương tự vậy, Excel sẽ phải kiểm tra version xem có thoả mãn hay ko mới cho phép dữ liệu được ghi xuống. Lúc này, version trước khi ghi vào của người B là v1, trong khi version hiện tại đã là v2 và ngay lập tức dữ liệu sẽ bị rollback và thông báo cho người B là dữ liệu đã bị thay đổi.
Với bài toán versioning, chúng ta có thể đánh version theo số. Ví dụ: 1.1.1, 1.2.0...
Tuy nhiên, chúng ta cũng có thể dùng time để lưu lại lịch sử giao dịch.

Vấn đề: Optimistic exception trong lập trình.
Tại cùng 1 thời điểm, nếu có 2 thread cùng ghi dữ liệu xuống 1 bảng, exception này có thể sẽ xảy ra. Bài toán tôi đưa ra ở đây là: Tôi có 1 timer, cứ 10s lại ghi dữ liệu logging xuống 1 bảng trong database. Tuy nhiên, do lượng dữ liệu quá lớn, trong 10s, thread ghi dữ liệu của tôi không thể hoàn thành được việc ghi dữ liệu xuống database. Chắc chắn Optimistic exception sẽ bắn ra và chúng ta sẽ phải giải quyết vẫn đề này. Vậy với trương hợp này, chúng ta phải xử lý như thế nào?
- Giải pháp thứ 1: Tăng thời gian của timer lên(ví dụ là 30s) hoặc giảm số lượng log file ghi xuống để đảm bảo trong khoảng thời gian configure của timer, toàn bộ dữ liệu có thể ghi xuống được.
- Giải pháp thứ 2: Nếu không thay đổi được configure của timer hay lượng dữ liệu ghi xuống, chúng ta có thể tách nhỏ 1 transaction lớn thành các transaction nhỏ hơn. Trong đó mỗi transaction sẽ ghi dữ liệu xuống database sau đó commit luôn, không chờ các transaction khác vì dữ liệu của chúng là độc lập.
- Giải pháp thứ 3: Chúng ta có thể sử dụng thêm các queue(FIFO) để lưu các dữ liệu cần ghi xuống trước khi sử dụng các thread khác để ghi xuống database.

Như vậy là trên đây mình cũng đã giải thích chi tiết hơn về 2 thuật ngữ rất hay được sử dụng trong lập trình đa luồng. See u :)

Nhận xét

Bài đăng phổ biến từ blog này

[Interview] - Tổng hợp các câu hỏi thú vị trong lần nhảy việc đầu tiên