0

Amazon Aurora MySQL Bài 39: Xây dựng chiến lược Zero-Downtime Schema Migration trên bảng hàng trăm triệu dòng

Trong quá trình phát triển sản phẩm, việc thay đổi cấu trúc cơ sở dữ liệu (Schema Migration) là điều không thể tránh khỏi. Tuy nhiên, khi một bảng trong Aurora MySQL đã phình to lên tới hàng chục hoặc hàng trăm triệu bản ghi (như bảng orders, transactions, hay audit_logs), một câu lệnh đơn giản như ALTER TABLE có thể trở thành cơn ác mộng: nó khóa toàn bộ bảng (Table Lock), làm tê liệt mọi thao tác INSERT, UPDATE của người dùng, và dễ dàng dẫn đến sập hệ thống do tràn tài nguyên.

Bài viết này sẽ mổ xẻ các chiến lược thực hiện Zero-Downtime Schema Migration chuyên sâu cho các bảng dữ liệu khổng lồ trên Aurora MySQL.

1. Nỗi đau của lệnh ALTER TABLE truyền thống

Khi bạn chạy lệnh thay đổi schema kinh điển trên một bảng lớn:

SQL

ALTER TABLE orders ADD COLUMN shipping_provider VARCHAR(50) NOT NULL DEFAULT 'GHN';

  • Điều gì xảy ra bên dưới?

    1. MySQL tạo ra một bản sao tạm thời của bảng (Temporary Table) mang cấu trúc mới.

    2. Nó tiến hành copy toàn bộ hàng trăm triệu dòng dữ liệu từ bảng cũ sang bảng tạm.

    3. Trong suốt thời gian sao chép (có thể kéo dài từ vài phút đến vài tiếng), bảng gốc bị khóa chặt (Exclusive Lock), mọi câu lệnh ghi dữ liệu của ứng dụng backend đều bị treo cứng (Waiting for table metadata lock).

    4. Sau khi hoàn tất, nó đổi tên bảng và xóa bảng cũ.

  • Hậu quả: Gây ra hiện tượng gián đoạn dịch vụ diện rộng (Downtime), làm nghẽn hàng đợi kết nối và có thể kích hoạt cơ chế Timeout của ứng dụng.

2. Các giải pháp An toàn (In-Place Alter Table với Online DDL)

May mắn thay, các phiên bản Aurora MySQL hiện đại (tương thích MySQL 8.0) hỗ trợ cơ chế Online DDL cho phép thay đổi schema mà không khóa bảng ghi.

a. Tận dụng thuật toán ALGORITHM=INPLACE và LOCK=NONE

Khi thực hiện thay đổi schema, hãy tường minh chỉ định thuật toán để kiểm soát hành vi của Aurora:

SQL

ALTER TABLE orders 
ADD COLUMN shipping_provider VARCHAR(50) NULL,
ALGORITHM = INPLACE,
LOCK = NONE;

  • ALGORITHM=INPLACE: Aurora thực hiện thay đổi cấu trúc trực tiếp ngay trên các tệp dữ liệu hiện có mà không cần tạo bảng sao chép cồng kềnh.

  • LOCK=NONE: Cho phép các câu lệnh SELECT, INSERT, UPDATE, DELETE của ứng dụng tiếp tục hoạt động bình thường không bị gián đoạn trong suốt quá trình thay đổi schema.

  • Lưu ý: Không phải mọi thao tác ALTER TABLE đều hỗ trợ LOCK=NONE. Việc thêm cột mới (nếu không có giá trị mặc định phức tạp) hoặc thêm/xóa Index thường hỗ trợ rất tốt. Tuy nhiên, việc đổi kiểu dữ liệu của một cột lớn (CHANGE COLUMN) thường bắt buộc phải tạo bảng tạm và khóa bảng.

3. Chiến lược nâng cao cho các thay đổi phức tạp: Shadow Table Pattern

Đối với các thay đổi cấu trúc quá nặng nề (ví dụ: đổi kiểu dữ liệu của cột khóa chính, tách bảng lớn, hoặc thêm các ràng buộc phức tạp mà Online DDL không hỗ trợ LOCK=NONE), ta sử dụng mô hình Shadow Table (Bảng bóng) kết hợp trigger hoặc CDC:

  1. Tạo Shadow Table: Tạo một bảng mới (orders_new) có cấu trúc mong muốn giống hệt bảng gốc (orders).

  2. Đồng bộ dữ liệu: Sử dụng các công cụ như gh-ost hoặc pt-online-schema-change (hoặc AWS DMS / Custom Script):

    • Sao chép toàn bộ dữ liệu lịch sử từ bảng cũ sang bảng mới theo từng batch nhỏ.

    • Tạo các Triggers (INSERT, UPDATE, DELETE) trên bảng cũ để tự động đồng bộ mọi thay đổi phát sinh theo thời gian thực sang bảng mới.

  3. Atomic Rename (Đổi tên nguyên tử): Khi dữ liệu hai bên đã khớp hoàn toàn, thực hiện một lệnh RENAME TABLE diễn ra trong vòng vài mili-giây để hoán đổi tên bảng:

    SQL

    RENAME TABLE orders TO orders_old, orders_new TO orders;
    
    
  4. Dọn dẹp: Xóa bảng cũ (orders_old) sau khi đã xác nhận hệ thống hoạt động ổn định.

4. Góc nhìn vận hành cho Backend Engineer

  • Tránh thêm cột có giá trị DEFAULT phức tạp trên bảng lớn: Việc chạy ALTER TABLE ADD COLUMN col VARCHAR(10) NOT NULL DEFAULT 'abc' trên MySQL cũ có thể bắt buộc phải viết lại toàn bộ các dòng dữ liệu để gán giá trị mặc định. Ở MySQL 8.0 / Aurora v3, tính năng Instant ADD COLUMN đã được tối ưu giúp việc thêm cột mới diễn ra gần như tức thì mà không cần quét lại bảng. Hãy luôn kiểm tra tính năng này trước khi thực thi.

  • Lên lịch thực hiện vào khung giờ thấp điểm: Dù Online DDL hỗ trợ LOCK=NONE, nó vẫn tiêu tốn một lượng tài nguyên CPU và I/O nhất định của Aurora Storage Volume. Hãy luôn thực hiện các thay đổi schema lớn vào khung giờ ít người dùng nhất (ví dụ nửa đêm hoặc rạng sáng) kết hợp theo dõi sát các chỉ số trên CloudWatch.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí