“Hãy đập đi viết lại toàn bộ bằng Microservices.”

Câu nói này thường là điềm báo cho những dự án kỹ thuật thất bại trị giá hàng triệu đô la. Khi một ứng dụng di sản (legacy) như một hệ thống thương mại điện tử Magento khổng lồ đang gánh vác toàn bộ doanh thu tài chính của một công ty, việc thực hiện một cú chuyển đổi kiểu “Big Bang” (cắt cái rụp sang hệ thống mới) thực tế là một hành động tự sát.

Thay vì đốt trụi ngôi nhà cũ trước khi ngôi nhà mới được xây xong, chúng tôi đã áp dụng một cách tỉ mỉ Strangler Fig Pattern 3 Giai đoạn (Mô hình Cây đa bóp cổ). Chúng tôi để cho hệ sinh thái microservice phân tán mới từ từ quấn quanh cục monolith Magento cũ, chặn bắt traffic của nó từng mảnh một cho đến khi cái server cũ chỉ còn là một cái vỏ rỗng tuếch.

Dưới đây là cuốn sổ tay chiến thuật chính xác mà chúng tôi đã sử dụng để migrate an toàn 10 domain thương mại cốt lõi (Catalog, Order, Customer, Payment, Fulfillment, v.v.) từ Magento sang một stack hiện đại, đạt được 99.9% uptime và khả năng rollback trong chưa tới 5 phút.

3 Chướng ngại vật Không hề Đơn giản trong việc Di chuyển

Trước khi viết dù chỉ một dòng logic định tuyến API, chúng tôi phải giải quyết 3 sự không tương thích nền tảng cốt lõi giữa Magento và các microservices hiện đại:

  1. Cơn ác mộng Schema EAV: Magento không lưu sản phẩm trong một bảng phẳng (flat table); nó sử dụng mô hình Entity-Attribute-Value (EAV), rải rác dữ liệu qua các bảng *_varchar, *_int, và *_decimal. Các lệnh SELECT * ngây thơ là bất khả thi. Chúng tôi phải xây dựng các pipeline ETL nặng nề để “làm phẳng” catalog thành các cấu trúc kiểu document.
  2. Sự va chạm giữa Integer và UUID: Magento cũ dựa vào các giá trị entity_id dạng số nguyên tăng dần (sequential integer). Các hệ thống phân tán hiện đại dựa vào UUID. Trước bất kỳ đợt migrate nào, ngoài việc map dữ liệu, chúng tôi phải thiết lập một bảng tham chiếu chéo magento_id_map nghiêm ngặt để dịch các khóa chính (primary keys) một cách an toàn giữa Monolith và Mesh (Lưới dịch vụ).
  3. CDC Đích thực vs. Polling: Dữ liệu thay đổi từng giây trong thương mại điện tử. Việc cập nhật theo lô (batch updates) qua cron jobs sẽ gây ra các race conditions khổng lồ trong quá trình ghi song song (dual-writes). Chúng tôi đã triển khai True Change Data Capture (CDC) sử dụng Debezium (để đồng bộ binlogs của MySQL) và Dapr Pub/Sub để đồng bộ hóa hướng sự kiện theo thời gian thực.

Một khi tầng dữ liệu đã được gỡ rối, chúng tôi bắt đầu triển khai đợt rollout 3 giai đoạn.

Giai đoạn 1: Migrate Chỉ đọc (The Smart Gateway)

Cách an toàn nhất để giới thiệu một hệ thống mới là không cho phép nó ghi (write) bất cứ thứ gì.

Trong Tuần 1, chúng tôi deploy các Microservices mới cùng với các database vận hành rỗng tuếch, giấu chúng hoàn toàn phía sau một API Gateway mới.

Gateway này đóng vai trò là một người điều phối giao thông:

  • Luồng Đọc (GET): Trỏ về các Microservices mới (ví dụ: tải danh sách sản phẩm).
  • Luồng Ghi (POST/PUT): Trỏ cứng (Hard-routed) ngược lại về server Magento cũ.

Làm sao các Microservices rỗng này có được dữ liệu catalog? Chúng tôi khởi tạo hệ thống theo dõi MySQL binlog thời gian thực thông qua Debezium. Nếu Magento cập nhật một cái giá, Debezium sẽ tóm lấy sự kiện binlog đó và stream nó về Catalog Service mới. Quá trình này hình thành nên một cây cầu 1 chiều: Magento vẫn là nguồn chân lý duy nhất không thể tranh cãi, và các Microservices của chúng tôi hoạt động như những bản sao chép chỉ đọc (read replicas) có tốc độ chớp nhoáng. Nếu có bất kỳ thứ gì hỏng hóc, một cái công tắc (feature flag) sẽ lật toàn bộ traffic Đọc về lại Magento trong chưa tới 10 giây.

Giai đoạn 2: Migrate Đọc-Ghi & Đồng bộ Kép

Giai đoạn 1 chứng minh rằng các hệ thống mới có thể đọc. Giai đoạn 2 chứng minh chúng có thể quản lý trạng thái (state). Chúng tôi bắt đầu migrate các Write-APIs (API ghi) một cách từ từ, bắt đầu với các domain có rủi ro thấp hơn như Customer, rồi đến Catalog, và cuối cùng là Order.

Một khi Write APIs chạm vào Microservices, Magento sẽ rơi vào tình trạng mất đồng bộ một cách nguy hiểm. Bởi vì module Fulfillment nguyên khối cũ vẫn nằm bên trong Magento, nó cần phải biết về các đơn hàng mà các Microservices Go đang tạo ra.

Chúng tôi giải quyết việc này bằng Đồng bộ 2 chiều với Dapr Pub/Sub:

  1. Khi một microservice (ví dụ: Order Service) xử lý thành công một giao dịch, nó sử dụng pattern Transactional Outbox để publish một sự kiện order.created vào Lưới sự kiện Dapr (Event Mesh).
  2. Một Legacy Sync Worker chuyên trách sẽ chộp lấy sự kiện này và ghi nó ngược trở lại vào database của Magento, phiên dịch payload hiện đại của chúng tôi trở lại thành các định dạng schema EAV phức tạp của Magento.
  3. Chúng tôi map các timestamps (dấu thời gian) đến tận phần nghìn giây (millisecond). Trong trường hợp xảy ra va chạm, bản ghi mới nhất sẽ ghi đè lên bản cũ.

Giai đoạn 3: Cắt cầu Hoàn toàn & The Hot Standby

Đến Tuần 8, toàn bộ traffic nặng về Ghi đã trỏ trực tiếp vào service mesh mới. Traffic API của Magento đã tụt xuống mức 0 tròn trĩnh.

Chúng tôi có xóa Magento ngay lập tức không? Hoàn toàn không.

Magento bị giáng chức một cách âm thầm xuống làm một Hot Standby (Dự phòng Nóng). Trong trọn vẹn 1 tháng, chúng tôi thực sự đã đảo ngược lại luồng dữ liệu của Giai đoạn 1. Chúng tôi đồng bộ dữ liệu từ microservices ngược trở lại vào Magento. Nếu một lỗi chí mạng cấp độ thảm họa bị phát hiện trong hệ sinh thái mới, chúng tôi vẫn nắm giữ tấm lưới an toàn tối thượng: gạt công tắc API Gateway trở lại Magento với mức độ mất mát dữ liệu bằng 0.

Một khi thời gian cách ly 30 ngày kết thúc êm đẹp, chúng tôi cuối cùng mới terminate các EC2 instances của Magento. Cái cây đa bóp cổ (Strangler Fig) đã nuốt trọn vật chủ.

Kết luận

Các dự án đập đi viết lại không thất bại vì bản thân Microservices là một thứ tồi tệ; chúng thất bại vì các lập trình viên bỏ bê tính nhất quán dữ liệu trong quá trình chuyển đổi.

Bằng cách sử dụng CDC/Debezium cho Giai đoạn 1, đồng bộ 2 chiều bằng Event-Driven Outboxes qua Dapr cho Giai đoạn 2, và duy trì một Hot Standby kéo dài trong Giai đoạn 3, chúng tôi đã đảm bảo được sự an toàn tuyệt đối cho dữ liệu của mình. Việc migrate các hệ thống cũ có thể đại diện cho những rủi ro đáng sợ, nhưng với những ràng buộc kiến trúc đúng đắn, chúng sẽ trở nên nhàm chán, có thể dự đoán trước, và an toàn 100%.

Nếu bạn đang đánh giá năng lực của một vendor trước khi thực hiện migration, bài viết Lập trình viên Magento ở Việt Nam: Hướng dẫn Thuê và Đánh giá Kỹ thuật sẽ phân tích sự khác biệt giữa các xưởng (shops) chỉ biết code extension và các đội ngũ thực sự có khả năng làm chủ kiến trúc, tích hợp, và độ tin cậy trên môi trường production.


🤝 Kết nối với tôi

Bạn đang gặp phải những thách thức tương tự về kiến trúc hệ thống, mở rộng quy mô (scaling) hay dịch chuyển (migration)? Hãy kết nối với tôi trên LinkedIn, theo dõi GitHub của tôi, hoặc gửi một email để trao đổi nhé.