- vừa được xem lúc

MVCC là gì? Hiểu đơn giản về Kiểm Soát Đồng Thời Đa Phiên bản

0 0 7

Người đăng: Phúc Lâm

Theo Viblo Asia

KHÁI NIỆM

  1. Định Nghĩa:

    • MVCC (Multi-Version Concurrency Control) hay Kiểm Soát Đồng Thời Đa Phiên bản, là một phương pháp kiểm soát đồng thời được sử dụng trong các hệ quản trị cơ sở dữ liệu để cung cấp khả năng truy cập đồng thời vào dữ liệu mà không cần sử dụng khóa truyền thống.

    • Hiểu đơn giản MVCC là tạo một bản ghi trong CSDL để bạn có thể đọc và thay đổi dữ liệu đồng thời vào cùng một thời điểm.

  2. Cơ Chế:

    • MVCC lưu trữ nhiều phiên bản của một dữ liệu nhất định, cho phép các giao dịch đọc dữ liệu mà không cần khóa dữ liệu đó. Nó sẽ tạo một bản ghi mới từ dữ liệu gốc mà không cần ghi đè lên dữ liệu gốc.

    • => Điều này đạt được bằng cách gắn thẻ phiên bản dữ liệu với thông tin về giao dịch đã tạo ra nó. Khi một giao dịch truy cập dữ liệu, nó sẽ chọn phiên bản dữ liệu phù hợp với trạng thái "nhìn thấy" của giao dịch đó.

  3. Lợi Ích:

    • Với MVCC, các thao tác đọc và ghi cơ sở dữ liệu không chặn lẫn nhau, và điều này cải thiện đáng kể trải nghiệm người dùng.

    • Đọc Dữ Liệu: Nhờ MVCC, việc đọc và ghi dữ liệu có thể diễn ra đồng thời một cách mượt mà, nâng cao đáng kể trải nghiệm người dùng.

    • Isolation (Cô lập): Hỗ trợ tốt cho các mức cô lập khác nhau như Read Committed và Snapshot Isolation, giúp tránh các vấn đề như "dirty read", "non-repeatable read" và "phantom read".

  4. Nhược Điểm:

    • Quản lý và Dọn Dẹp Phiên Bản: MVCC lưu trữ nhiều phiên bản của mỗi dữ liệu, dẫn đến việc cần phải dọn dẹp các phiên bản cũ không còn sử dụng.

    • Tiêu Thụ Tài Nguyên: Việc lưu trữ nhiều phiên bản của dữ liệu làm tăng yêu cầu về dung lượng lưu trữ.

      • Trong Postgres sẽ sử dụng cơ chế VACUUM để xóa những dữ liệu không cần.
      • Trong Mysql sẽ sử dụng cơ chế InnoDB Purge Process để dọn dẹp.
    • Khả Năng Mở Rộng: MVCC có thể gặp vấn đề về khả năng mở rộng do lượng lớn các phiên bản xuất hiện sẽ cần được quản lý và dọn dẹp.

    • Độ Phức Tạp trong Quản Lý: MVCC phức tạp hơn so với các cơ chế khóa truyền thống trong việc triển khai và quản lý. Việc gỡ lỗi các vấn đề liên quan đến đồng thời trong hệ thống MVCC có thể phức tạp hơn do sự tồn tại của nhiều phiên bản dữ liệu và các snapshot khác nhau.

[!NOTE] VACUUM : Khi một dòng dữ liệu bị xóa hoặc cập nhật, MVCC không xóa vật lý phiên bản cũ ngay lập tức. VACUUM sẽ loại bỏ các phiên bản "chết" này, trả lại không gian lưu trữ cho hệ thống.

![[mvcc_conflict_1.png]] Ví dụ về MVCC và xung đột giao dịch:

Giả sử chúng ta có bảng users với các cột id (khóa chính), namebalance.

  • Giao dịch #1 (XID=41):

    • Bắt đầu giao dịch.
    • Đọc tài khoản Bob (id=100).
    • Cập nhật balance của Bob lên 1000 (giả sử ban đầu là 500).
    • Giao dịch #1 commit thành công.
  • Giao dịch #2 (XID=42):

    • Bắt đầu giao dịch.
    • Đọc tài khoản Bob (id=100).
    • Cập nhật balance của Bob lên 2000.
    • Giao dịch #2 gặp lỗi do xung đột.

Giải thích:

  • Snapshot Isolation: Khi giao dịch #2 bắt đầu, nó "nhìn thấy" một snapshot của dữ liệu ở thời điểm đó. Snapshot này bao gồm thông tin về giao dịch #1 đang hoạt động (XID=41).
  • Xung đột: Khi giao dịch #2 cố gắng cập nhật tài khoản Bob, PostgreSQL phát hiện rằng giao dịch #1 (XID=41) đã tạo ra một phiên bản mới của tài khoản Bob.
  • Xử lý xung đột: Do đó, PostgreSQL báo lỗi cho giao dịch #2 vì nó không thể ghi đè lên phiên bản mới của Bob. Giao dịch #2 sẽ phải được xử lý lại (retry) hoặc có thể bị bỏ qua (abort).

KẾT QUẢ MONG MUỐN ĐẠT ĐƯỢC SAU BÀI HỌC

  • Hiểu rõ cơ chế hoạt động của MVCC.
  • Nắm được ưu điểm của MVCC trong việc xử lý đồng thời.
  • Nhận thức được ứng dụng của MVCC trong các hệ quản trị CSDL hiện đại.

Hiểu Hơn MVCC trong PostgreSQL

1. Bản Gốc của Đồng Thời: Snapshot và Phiên Bản Dữ Liệu:

  • Cập nhật dữ liệu: Khi bạn cập nhật một dòng dữ liệu, PostgreSQL không ghi đè lên dữ liệu cũ. Thay vào đó, nó tạo ra một "phiên bản" (tuple) mới cho dòng đó. Phiên bản cũ được đánh dấu là "hết hạn" và trỏ đến phiên bản mới.
  • Lợi ích của lưu trữ phiên bản: Việc lưu trữ phiên bản cũ cho đến khi không còn cần thiết cho phép mỗi giao dịch "nhìn thấy" một "ảnh chụp" (snapshot) nhất quán của dữ liệu tại thời điểm nó bắt đầu, bất kể những thay đổi từ các giao dịch khác

2. Xmin và Xmax:

Mỗi dòng dữ liệu trong PostgreSQL đều có hai cột ẩn quan trọng: xminxmax.

  • xmin: Ghi lại "ID giao dịch" (Transaction ID - XID) đã tạo ra dòng dữ liệu hoặc cập nhật lần cuối.
  • xmax: Ghi lại XID của giao dịch đã đánh dấu dòng dữ liệu là "đã xóa" (nếu có). Khi một dòng được tạo, xmax mặc định là 0, cho đến khi nó bị xóa.
  • Default: Khi một dòng dữ liệu được tạo mới, giá trị xmax được đặt là 0 (chưa có giao dịch nào xóa nó).

Tại sao là transaction ID?

  • Các lệnh DML đều là transaction: Trong PostgreSQL, tất cả các lệnh DML (Data Manipulation Language) như INSERT, UPDATE, DELETE đều được thực hiện trong một transaction, ngay cả khi bạn không khai báo BEGIN TRANSACTIONCOMMIT rõ ràng.
  • Transaction ID là duy nhất: Mỗi transaction được gán một transaction ID duy nhất để theo dõi các thay đổi dữ liệu.

3. Xmin & Xmax: Chìa Khóa Xác Định Phiên Bản Dữ Liệu

  • Truy vấn dữ liệu: Khi một giao dịch truy vấn dữ liệu, PostgreSQL sẽ tìm kiếm phiên bản phù hợp nhất dựa trên transaction ID của giao dịch hiện tại và giá trị xminxmax của dòng dữ liệu.
  • Xác định phiên bản: PostgreSQL sử dụng giá trị xminxmax để xác định phiên bản nào là mới nhất, dựa trên trạng thái của transaction (in-progress, committed, aborted).

4. Ví dụ thực tế:

Giả sử chúng ta có bảng users với cột balance.

  1. Giao dịch 1 (XID = 100): Đọc số dư của Alice (balance = 1500).
  2. Giao dịch 2 (XID = 101): Cập nhật số dư của Alice lên 2000. PostgreSQL tạo một phiên bản mới với balance = 2000, phiên bản cũ (balance = 1500) được đánh dấu là "hết hạn", xmax được cập nhật thành 101.
  3. Giao dịch 1: Nếu đọc lại dữ liệu lúc này, giao dịch 1 vẫn thấy balance = 1500 vì nó vẫn đang "nhìn" vào snapshot ban đầu.
  4. Giao dịch 2: Commit thành công. Phiên bản mới (balance = 2000) trở thành phiên bản hiện tại, xmax của phiên bản cũ được đặt về 0.
  5. Giao dịch 1: Bây giờ đọc lại, giao dịch 1 sẽ thấy balance = 2000 vì thay đổi từ giao dịch 2 đã được áp dụng.

[!NOTE]

  • BEGIN (Begin Transaction ) : Câu lệnh này đánh dấu bắt đầu một giao dịch. Từ thời điểm này, mọi thay đổi bạn thực hiện trên cơ sở dữ liệu (như INSERT, UPDATE, DELETE) sẽ chưa được áp dụng vĩnh viễn.

  • COMMIT (Commit Transaction) : Câu lệnh này đánh dấu kết thúc một giao dịch và áp dụng tất cả các thay đổi bên trong giao dịch vào cơ sở dữ liệu một cách vĩnh viễn.

Kết luận:

MVCC, với sự hỗ trợ đắc lực của xminxmax, cho phép PostgreSQL đạt được sự đồng thời cao và tính nhất quán dữ liệu mà không cần khóa liên tục, giúp tối ưu hóa hiệu suất hệ thống.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Nhập môn lý thuyết cơ sở dữ liệu - Phần 1 : Tổng quan

# Trong bài viết này mình sẽ tập trung vào chủ đề tổng quan về Cơ sở dữ liệu. Phần 1 lý thuyết nên hơi chán các bạn cố gắng đọc nhé, chắc lý thuyết mới làm bài tập được, kiến thức còn nhiều các bạn cứ

0 0 112

- vừa được xem lúc

002: Hiểu về Index để tăng performance với PostgreSQL P1

Bài viết nằm trong series Performance optimization với PostgreSQL. Từ bài này sẽ liên quan nhiều đến practice nên các bạn chuẩn bị env và data trước.

0 0 500

- vừa được xem lúc

003: Hiểu về Index để tăng performance với PostgreSQL P2

Bài viết nằm trong series Performance optimization với PostgreSQL. . . B-Tree index.

0 0 527

- vừa được xem lúc

010: Exclusive lock và Shared lock

Bài viết nằm trong series Performance optimization với PostgreSQL. Nếu execute single query:. UPDATE TABLE X SET COLUMN = 'Y' WHERE ID = 1;. .

0 0 50

- vừa được xem lúc

009: Optimistic lock và Pessimistic lock

Bài viết nằm trong series Performance optimization với PostgreSQL. Nghe có vẻ nguy hiểm nhưng cách giải quyết không có gì phức tạp, sử dụng các cơ chế mutual exclusion là giải quyết được vấn đề này.

0 0 57

- vừa được xem lúc

011: PostgreSQL multi-version concurrency control

Bài viết nằm trong series Performance optimization với PostgreSQL. Vậy có cách nào không cần lock mà vẫn concurrent read/write không.

0 0 44