Two-Phase Locking (2PL) là gì? Cơ chế khóa hai pha trong Database
1. Two-Phase Locking (2PL) là gì?
Two-Phase Locking (2PL — khóa hai pha) là một giao thức quản lý khóa trong Database, quy định cách một transaction được phép lấy và giải phóng lock trong quá trình thực thi.
Khi nhiều transaction cùng truy cập hoặc thay đổi dữ liệu, chúng có thể xung đột với nhau. Nếu không có cơ chế kiểm soát phù hợp, thứ tự đọc và ghi dữ liệu có thể tạo ra kết quả không nhất quán.
Locking giúp kiểm soát những truy cập đồng thời này. Tuy nhiên, việc sử dụng lock đơn thuần chưa đủ để đảm bảo mọi lịch thực thi đều có thể tương đương với một thứ tự thực hiện tuần tự.
Two-Phase Locking giải quyết vấn đề này bằng cách đặt ra quy tắc về thời điểm transaction được lấy và giải phóng lock.
Ý tưởng cốt lõi của 2PL là transaction phải trải qua hai pha:
- Growing Phase (pha tăng trưởng): Transaction được lấy thêm lock nhưng không được giải phóng lock đã lấy.
- Shrinking Phase (pha thu hẹp): Transaction được giải phóng lock nhưng không được lấy thêm lock mới.
Theo giao thức 2PL, sau khi transaction giải phóng lock đầu tiên, nó không được lấy thêm lock nào nữa.
Mục tiêu quan trọng của 2PL là đảm bảo Conflict Serializability (khả năng tuần tự hóa theo xung đột), giúp lịch thực thi đồng thời tương đương với một thứ tự thực hiện tuần tự của các transaction.
2. Tại sao cần Two-Phase Locking?
Để hiểu tại sao cần 2PL, trước hết cần xem xét một tình huống khi hai transaction cùng thao tác trên dữ liệu.
Giả sử tài khoản A có số dư 1.000.000 đồng. Hai transaction cùng thực hiện:
- Transaction T1: Trừ 200.000 đồng từ A.
- Transaction T2: Trừ 300.000 đồng từ A.
Nếu cả hai transaction đều đọc số dư ban đầu là 1.000.000 đồng rồi tính toán dựa trên giá trị đó, chúng có thể ghi đè kết quả của nhau nếu không có cơ chế kiểm soát phù hợp.
Kết quả có thể không phản ánh đúng việc cả hai giao dịch đều đã được thực hiện.
Trong thực tế, Database sử dụng các cơ chế như lock, MVCC và những quy tắc kiểm soát đồng thời khác để ngăn chặn các tình huống xung đột.
2PL là một giao thức quan trọng trong lý thuyết kiểm soát đồng thời. Nó quy định cách transaction quản lý lock nhằm bảo đảm tính tuần tự hóa theo xung đột.
3. Hai pha của Two-Phase Locking
3.1. Growing Phase — Pha tăng trưởng
Trong pha này, transaction có thể lấy thêm lock khi cần truy cập dữ liệu, nhưng không được giải phóng bất kỳ lock nào đã lấy.
Ví dụ:
- T1 lấy lock trên dòng dữ liệu A.
- T1 tiếp tục lấy lock trên dòng dữ liệu B.
- T1 có thể lấy thêm lock trên dòng dữ liệu C.
Trong suốt pha tăng trưởng, số lượng lock mà transaction nắm giữ có thể tăng lên.
Điều quan trọng là transaction chưa được phép bắt đầu giải phóng lock.
3.2. Shrinking Phase — Pha thu hẹp
Pha thu hẹp bắt đầu khi transaction giải phóng lock đầu tiên.
Từ thời điểm này, transaction có thể giải phóng những lock đang nắm giữ, nhưng không được lấy thêm lock mới.
Ví dụ:
- T1 giải phóng lock trên A.
- T1 tiếp tục giải phóng lock trên B.
- T1 không được lấy thêm lock trên C nếu trước đó chưa lấy lock này.
Nếu T1 cần truy cập C sau khi đã bắt đầu giải phóng lock, thao tác lấy lock mới sẽ vi phạm quy tắc 2PL.
3.3. Lock Point — Điểm chuyển pha
Lock Point là thời điểm transaction lấy lock cuối cùng.
Trước thời điểm này, transaction đang ở pha tăng trưởng. Sau khi bắt đầu giải phóng lock, transaction bước vào pha thu hẹp.
Lock Point có ý nghĩa trong việc xác định thứ tự tuần tự tương đương của các transaction khi áp dụng 2PL.
4. Ví dụ minh họa hoạt động của 2PL
Giả sử transaction T1 cần đọc và cập nhật hai tài khoản A và B.
Quá trình thực thi có thể được mô tả như sau:
| Bước | Thao tác | Pha |
|---|---|---|
| 1 | T1 lấy lock trên A | Growing |
| 2 | T1 đọc số dư A | Growing |
| 3 | T1 lấy lock trên B | Growing |
| 4 | T1 đọc số dư B | Growing |
| 5 | T1 cập nhật A và B | Growing |
| 6 | T1 giải phóng lock trên A | Shrinking |
| 7 | T1 giải phóng lock trên B | Shrinking |
T1 đã lấy tất cả lock cần thiết trước khi bắt đầu giải phóng lock.
Đây là nguyên tắc cốt lõi của 2PL. Trong một hệ thống áp dụng 2PL, transaction không thể giải phóng một lock rồi tiếp tục lấy thêm lock mới.
Cách quản lý này giúp kiểm soát thứ tự truy cập dữ liệu giữa các transaction, nhưng cũng có thể khiến transaction khác phải chờ nếu dữ liệu cần thiết đang bị khóa.
5. Các loại lock liên quan đến 2PL
2PL quy định cách transaction lấy và giải phóng lock. Các loại lock cụ thể lại xác định những thao tác nào có thể được thực hiện đồng thời.
Hai loại lock cơ bản thường được đề cập là:
5.1. Shared Lock (S Lock)
Shared Lock là khóa dùng để kiểm soát quyền đọc dữ liệu.
Nhiều transaction có thể cùng giữ shared lock trên một dữ liệu nếu không có exclusive lock xung đột.
Ví dụ, T1 và T2 cùng đọc một dòng dữ liệu. Nếu cả hai chỉ cần shared lock, Database có thể cho phép chúng đọc đồng thời.
5.2. Exclusive Lock (X Lock)
Exclusive Lock là khóa độc quyền, thường được sử dụng khi transaction cần ghi hoặc cập nhật dữ liệu.
Khi một transaction giữ exclusive lock trên một dòng dữ liệu, các transaction khác không thể lấy những lock xung đột trên dòng đó cho đến khi khóa được giải phóng.
Ví dụ, T1 đang cập nhật số dư tài khoản A. T2 muốn cập nhật cùng tài khoản có thể phải chờ T1 hoàn tất, tùy theo cơ chế quản lý đồng thời của Database.
Shared Lock và Exclusive Lock có quy tắc tương thích khác nhau. Việc sử dụng chúng giúp Database kiểm soát các thao tác đọc và ghi xung đột.
6. Strict 2PL là gì?
Strict Two-Phase Locking (Strict 2PL) là một biến thể của 2PL, trong đó transaction giữ các exclusive lock đến khi commit hoặc rollback.
Trong 2PL cơ bản, transaction có thể bắt đầu giải phóng lock trước khi kết thúc. Strict 2PL bổ sung một ràng buộc đối với exclusive lock, nhằm tránh việc transaction khác đọc hoặc ghi đè lên dữ liệu đã bị thay đổi bởi một transaction chưa hoàn tất.
Ví dụ:
- T1 lấy exclusive lock trên tài khoản A.
- T1 cập nhật số dư A.
- T1 chưa commit.
- T2 muốn cập nhật A và phải chờ.
- T1 commit, sau đó T2 mới có thể tiếp tục khi lock được giải phóng.
Strict 2PL giúp đơn giản hóa việc phục hồi dữ liệu và ngăn các transaction khác truy cập dữ liệu đã ghi nhưng chưa được commit theo những cách có thể gây ra vấn đề khi rollback.
Cần phân biệt Strict 2PL với 2PL cơ bản: Strict 2PL giữ exclusive lock đến khi transaction kết thúc, còn 2PL cơ bản chỉ yêu cầu không lấy thêm lock sau khi đã bắt đầu giải phóng lock.
7. Nhược điểm của Two-Phase Locking
Mặc dù 2PL cung cấp bảo đảm quan trọng về khả năng tuần tự hóa, giao thức này cũng có một số hạn chế.
7.1. Deadlock — Bế tắc
Deadlock xảy ra khi các transaction chờ lock do transaction khác nắm giữ, tạo thành một chu trình chờ.
Ví dụ:
- T1 giữ lock trên A và chờ lock trên B.
- T2 giữ lock trên B và chờ lock trên A.
T1 không thể tiếp tục nếu T2 chưa giải phóng B, trong khi T2 cũng không thể tiếp tục nếu T1 chưa giải phóng A.
Nếu không có cơ chế phát hiện và xử lý deadlock, cả hai transaction có thể tiếp tục chờ nhau.
2PL không loại bỏ deadlock. Database thường cần cơ chế phát hiện deadlock, hủy một transaction để phá vỡ chu trình, hoặc sử dụng chiến lược phòng tránh phù hợp.
7.2. Giảm khả năng thực thi đồng thời
Khi một transaction giữ lock trên dữ liệu, transaction khác có thể phải chờ nếu muốn thực hiện thao tác xung đột.
Nếu transaction giữ lock quá lâu, thời gian chờ tăng lên và thông lượng của hệ thống có thể giảm.
7.3. Tăng chi phí quản lý lock
Database phải theo dõi các lock đang được nắm giữ, kiểm tra xung đột và quản lý những transaction đang chờ.
Trong hệ thống có nhiều transaction đồng thời, chi phí này có thể ảnh hưởng đến hiệu năng.
8. Two-Phase Locking liên quan gì đến Transaction và Isolation Level?
2PL thường được học cùng Transaction, Locking và Isolation Level vì các khái niệm này đều liên quan đến việc kiểm soát truy cập dữ liệu đồng thời. Tuy nhiên, mỗi khái niệm giải quyết một vấn đề khác nhau.
| Khái niệm | Vai trò |
|---|---|
| Transaction | Gom các thao tác Database thành một đơn vị xử lý. |
| Locking | Cơ chế khóa nhằm kiểm soát các truy cập xung đột. |
| Two-Phase Locking | Quy định thời điểm transaction được lấy và giải phóng lock. |
| Isolation Level | Xác định các bảo đảm về mức độ cô lập giữa các transaction. |
| Deadlock | Tình trạng các transaction chờ nhau theo một chu trình. |
Isolation Level và 2PL không phải là hai tên gọi của cùng một cơ chế.
2PL là giao thức quản lý lock có thể được sử dụng để đảm bảo conflict serializability. Isolation Level mô tả các bảo đảm mà Database cung cấp khi nhiều transaction thực thi đồng thời.
Các hệ quản trị cơ sở dữ liệu hiện đại có thể kết hợp nhiều cơ chế, chẳng hạn locking và MVCC. Vì vậy, không nên mặc định rằng mọi Database hoặc mọi Isolation Level đều được triển khai hoàn toàn bằng 2PL.
9. Khi nào cần quan tâm đến 2PL trong Backend?
Khi phát triển Backend, lập trình viên thường làm việc với transaction, cập nhật dữ liệu và xử lý nhiều request đồng thời.
Ví dụ, một API bán hàng chỉ còn một sản phẩm trong kho. Hai request đến gần như cùng lúc và đều muốn mua sản phẩm cuối cùng.
Nếu hệ thống không kiểm soát đúng việc cập nhật dữ liệu, có thể xảy ra tình trạng cả hai request đều được xử lý như thể sản phẩm vẫn còn.
Trong thực tế, lập trình viên có thể dùng transaction kết hợp với các cơ chế như conditional update, row-level lock hoặc những tính năng kiểm soát đồng thời khác do Database cung cấp.
Ví dụ trong PostgreSQL:
BEGIN;
UPDATE products
SET stock = stock - 1
WHERE id = 1
AND stock > 0;
COMMIT;
Câu lệnh chỉ giảm tồn kho khi giá trị stock lớn hơn 0. Ứng dụng cần kiểm tra số dòng bị ảnh hưởng để biết thao tác có thành công hay không.
Ví dụ này minh họa một cách kiểm soát cập nhật tồn kho an toàn hơn trong điều kiện cạnh tranh. Tuy nhiên, nó không tự chứng minh rằng toàn bộ hệ thống đang sử dụng giao thức 2PL.
Điều quan trọng với Backend Developer là hiểu khi nào dữ liệu có thể bị tranh chấp, cách Database xử lý các thao tác xung đột và cách thiết kế transaction phù hợp với yêu cầu nghiệp vụ.
10. Kết luận
Two-Phase Locking là giao thức quản lý khóa quan trọng trong Database. Nó chia quá trình quản lý lock của một transaction thành hai pha: pha tăng trưởng, nơi transaction có thể lấy thêm lock nhưng không giải phóng lock; và pha thu hẹp, nơi transaction có thể giải phóng lock nhưng không được lấy thêm lock mới.
2PL giúp đảm bảo conflict serializability, nhưng không loại bỏ các vấn đề như deadlock hoặc giảm hiệu năng do thời gian chờ lock.
Strict 2PL là một biến thể giữ exclusive lock đến khi transaction commit hoặc rollback, giúp tránh một số vấn đề liên quan đến việc truy cập dữ liệu chưa được commit.
Hiểu 2PL giúp lập trình viên nhìn rõ hơn mối liên hệ giữa Transaction, Locking, Isolation Level và xử lý đồng thời. Đây là nền tảng quan trọng khi xây dựng các hệ thống Backend phải xử lý nhiều request cùng lúc và duy trì tính nhất quán của dữ liệu.







Khoá học lập trình game con rắn cho trẻ em




