Cơ chế Kiểm soát Đồng thời và Xử lý Xung đột Phiên bản trong ElasticSearch

Nguyên lý Kiểm soát Phiên bản và Đồng thời

ElasticSearch triển khai cơ chế khóa lạc quan (optimistic locking) để quản lý các thao tác cập nhật dữ liệu đồng thời, nhằm ngăn chặn việc ghi đè thông tin không mong muốn. Mỗi tài liệu (document) lưu trữ trong hệ thống đều được gán một số phiên bản nội bộ thông qua trường _version. Khi một document mới được chỉ mục, phiên bản khởi tạo là 1. Các thao tác tiếp theo như cập nhật, xóa hoặc index lại sẽ làm tăng giá trị này lên một đơn vị.

Do tính chất异步 (asynchronous) của quá trình sao chép dữ liệu giữa các node trong cluster, khoảng thời gian từ khi ghi dữ liệu đến khi nó khả dụng cho tìm kiếm phụ thuộc vào cấu hình refresh_interval. Mặc định, khoảng thời gian này là 1 giây. Trong khung thời gian này, nếu có nhiều yêu cầu sửa đổi cùng một document, hệ thống sẽ sử dụng版本号 để xác định tính hợp lệ của thao tác.

Khi một yêu cầu cập nhật gửi đến với phiên bản cũ hơn so với phiên bản hiện tại đang lưu trữ, ElasticSearch sẽ từ chối thao tác đó. Phản hồi trả về sẽ là mã trạng thái HTTP 409 kèm theo ngoại lệ version_conflict_engine_exception. Điều này đảm bảo dữ liệu mới nhất không bị thay thế bởi dữ liệu lỗi thời.

Chiến lược Sử dụng Phiên bản Ngoại vi (External Versioning)

Trong các kịch bản đồng bộ hóa dữ liệu từ nguồn bên ngoài (ví dụ: cơ sở dữ liệu quan hệ như MySQL), việc quản lý phiên bản nội bộ của ElasticSearch có thể không phù hợp. Hệ thống hỗ trợ chế độ version_type=external để delegating quyền kiểm soát phiên bản cho hệ thống bên ngoài.

Khi kích hoạt chế độ này, ElasticSearch sẽ so sánh版本号 được gửi kèm trong yêu cầu với版本号 đang lưu trữ. Thao tác chỉ thành công nếu版本号 gửi đến lớn hơn版本号 hiện có. Điều này cho phép sử dụng các giá trị như timestamp (miligiây) hoặc bộ đếm tăng dần từ database nguồn làm chuẩn xác thực.

Ví dụ dưới đây minh họa việc cập nhật document với版本号 ngoại vi là một giá trị timestamp lớn:

PUT store_inventory/_doc/101?version=1678899000123&version_type=external
{
   "qty": 150,
   "price": 29.99,
   "sku_code": "ITEM-A001"
}

Nếu một yêu cầu khác gửi đến sau đó với timestamp nhỏ hơn hoặc bằng 1678899000123, ElasticSearch sẽ ném ra lỗi xung đột phiên bản. Cơ chế này đảm bảo tính nhất quán dữ liệu khi đồng bộ hóa từ nhiều nguồn khác nhau.

Kiểm soát Chính xác bằng Seq No và Primary Term

Đối với các thao tác cập nhật nội bộ trong ElasticSearch, việc sử dụng _version đôi khi không đủ mạnh mẽ do cơ chế gộp phiên bản (version merging). Thay vào đó, hệ thống cung cấp cơ chế kiểm soát chặt chẽ hơn thông qua cặp tham số _seq_no và _primary_term.

_seq_no (sequence number) là số thứ tự tăng dần mỗi khi document được thay đổi trên shard chính. _primary_term là số lần shard chính được khởi tạo lại. Để thực hiện cập nhật an toàn, ứng dụng cần lấy trước hai giá trị này, sau đó truyền chúng vào yêu cầu cập nhật thông qua tham số if_seq_no và if_primary_term.

Quy trình thực hiện như sau:

1. Truy vấn document để lấy thông tin phiên bản hiện tại:

GET store_inventory/_doc/101

{
  "_index" : "store_inventory",
  "_id" : "101",
  "_version" : 5,
  "_seq_no" : 42,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "qty" : 150,
    "price" : 29.99,
    "sku_code" : "ITEM-A001"
  }
}

2. Thực hiện cập nhật với điều kiện kiểm tra phiên bản:

PUT store_inventory/_doc/101?if_seq_no=42&if_primary_term=1
{
   "qty": 145,
   "price": 29.99,
   "sku_code": "ITEM-A001"
}

Nếu trong khoảng thời gian giữa bước 1 và bước 2, document bị thay đổi bởi một tiến trình khác, giá trị _seq_no sẽ tăng lên. Khi đó, điều kiện if_seq_no=42 không còn khớp, và ElasticSearch sẽ trả về lỗi xung đột, ngăn chặn việc ghi đè dữ liệu.

Xử lý Xung đột trong Thao tác Bulk

Khi thực hiện các thao tác cập nhật hoặc xóa hàng loạt thông qua API _update_by_query hoặc _delete_by_query, xung đột phiên bản có thể xảy ra frequently do số lượng document lớn. Mặc định,如果遇到 xung đột, quá trình sẽ dừng lại và báo lỗi.

Để tiếp tục xử lý các document còn lại mà không bị gián đoạn bởi các xung đột riêng lẻ, có thể sử dụng tham số conflicts=proceed. Tham số này instructs ElasticSearch bỏ qua các lỗi phiên bản và tiếp tục thực thi trên các document khác. Kết quả trả về sẽ bao gồm thống kê số lượng xung đột đã bỏ qua trong trường version_conflicts.

Ví dụ cập nhật hàng loạt bỏ qua xung đột:

POST store_inventory/_update_by_query?conflicts=proceed
{
  "query": {
    "term": {
      "sku_code": {
        "value": "ITEM-A001"
      }
    }
  },
  "script": {
    "source": "ctx._source['qty'] = ctx._source['qty'] - 5;"
  }
}

Phản hồi từ hệ thống sẽ cung cấp chi tiết về số lượng document đã cập nhật thành công và số lượng xung đột đã được bỏ qua, cho phép người quản trị đánh giá mức độ ảnh hưởng của các thao tác đồng thời mà không làm dừng toàn bộ quy trình xử lý.

Thẻ: Elasticsearch optimistic-locking version-control data-consistency bulk-api

Đăng vào ngày 21 tháng 10 lúc 12:52