📖 English Edition (Bản tiếng Anh)


Điều kiện tiên quyết: Đọc qua Phần 3 — Kiến Trúc Composable Commerce: Vượt Qua Nợ Kỹ Thuật để hiểu bản đồ phân rã các miền nghiệp vụ.

Bản Thiết Kế Zero-Downtime: Chuyển Đổi Magento Sang Microservices Bằng Strangler Fig

Tóm tắt cốt lõi: Quy trình di trú không gián đoạn (Zero-Downtime) từ khối nguyên khối Magento sang hệ thống Go Microservices được thực thi qua 3 giai đoạn của Mẫu Kiến Trúc Strangler Fig: Giai đoạn 1 (Đón Đầu Lưu Lượng) triển khai Envoy Gateway ở cổng vào để điều phối đường dẫn và gắn tiêu đề ngữ cảnh W3C traceparent; Giai đoạn 2 (Chạy Song Song & Đối Chiếu Shadow) nhân bản 100% lưu lượng sản xuất sang các dịch vụ Go mới để kiểm thử ngầm, kết hợp đồng bộ dữ liệu hai chiều liên tục qua Debezium 3.0+ CDC; và Giai đoạn 3 (Chuyển Đổi Dần & Khai Tử) điều hướng lưu lượng người dùng từng phần (1% -> 10% -> 100%), duy trì Magento ở trạng thái dự phòng nóng (Hot Standby) trong 30 ngày trước khi tắt vĩnh viễn.

Nỗi sợ hãi lớn nhất của các doanh nghiệp bán lẻ là nguy cơ gián đoạn bán hàng khi thay đổi nền tảng. Phương pháp chuyển đổi truyền thống theo kiểu “Big Bang” — tức phát triển kín trong nhiều tháng rồi chuyển toàn bộ tên miền DNS trong một đêm cuối tuần — có tỷ lệ thất bại được ghi nhận lên tới hơn 60% trong ngành thương mại điện tử.

Mẫu kiến trúc Strangler Fig loại bỏ hoàn toàn rủi ro này bằng cách thay thế từng phần nhỏ trong khi hệ thống vẫn đang liên tục phục vụ hàng nghìn đơn hàng mỗi ngày.


1. Lộ Trình Tiến Hóa 3 Giai Đoạn Của Strangler Fig

flowchart TD
    subgraph Phase1 ["Giai Đoạn 1: Đón Đầu Cổng Vào (Tháng 1-2)"]
        User1["Yêu Cầu Của Khách"] --> Envoy1["Envoy Gateway Reverse Proxy"]
        Envoy1 -->|"100% Lưu Lượng"| Magento1["Khối Magento 2.4.9 Monolith (PHP)"]
        Envoy1 -.->|"Thăm Dò Thử Nghiệm"| GoEmpty["Khung Dự Án Go Microservices"]
    end

    subgraph Phase2 ["Giai Đoạn 2: Chạy Shadow & Đồng Bộ CDC (Tháng 3-8)"]
        User2["Yêu Cầu Của Khách"] --> Envoy2["Bộ Điều Phối Lưu Lượng Envoy"]
        Envoy2 -->|"Xử Lý Thực Tế (Khách Thấy)"| Magento2["Magento Monolith"]
        Envoy2 -->|"Nhân Bản Ngầm (Khách Không Ảnh Hưởng)"| GoServices["Cụm Go Microservices"]
        Magento2 --> CDC["Debezium 3.0+ CDC"]
        CDC --> Kafka["Luồng Sự Kiện Redpanda / Kafka"]
        Kafka --> GoServices
        GoServices -.->|"Bộ So Khớp Kết Quả"| AuditReport["Báo Cáo Đối Chiếu Dữ Liệu (Đạt 100%)"]
    end

    subgraph Phase3 ["Giai Đoạn 3: Chuyển Vùng & Tắt Khối Monolith (Tháng 9-12)"]
        User3["Yêu Cầu Của Khách"] --> Envoy3["Envoy Edge Gateway"]
        Envoy3 -->|"100% Lưu Lượng Sản Xuất"| GoProd["Cụm Go Microservices (Chính Thức)"]
        GoProd -.->|"Đồng Bộ Ngược (Dự Phòng)"| MagentoPassive["Magento Dự Phòng Nóng (30 Ngày)"]
        MagentoPassive --> Terminate["Tắt Hoàn Toàn Máy Chủ Magento Cũ"]
    end

    Phase1 --> Phase2
    Phase2 --> Phase3

2. Quy Trình Đối Chiếu Dữ Liệu Shadow Traffic

Trước khi chuyển bất kỳ khách hàng thực tế nào sang dịch vụ Go mới, lưu lượng sản xuất được nhân bản phi đồng bộ để so sánh độ chính xác tuyệt đối:

sequenceDiagram
    autonumber
    actor Shopper as "Khách Mua Hàng"
    participant Envoy as "Envoy Reverse Proxy"
    participant Magento as "Magento Monolith (Thực Tế)"
    participant GoSvc as "Go Catalog Service (Chạy Ngầm)"
    participant Diff as "Bộ So Sánh Dữ Liệu & Cảnh Báo"

    Shopper->>Envoy: GET /api/v1/products/SKU-9901
    par Nhánh Xử Lý Chính (Đồng Bộ)
        Envoy->>Magento: Thực Thi Truy Vấn PHP EAV Cũ
        Magento-->>Envoy: Trả Về Dữ Liệu JSON Sản Phẩm (200 OK)
        Envoy-->>Shopper: Trả Kết Quả Cho Khách (< 850ms)
    and Nhánh Chạy Shadow (Không Gây Chặn)
        Envoy->>GoSvc: Nhân Bản Yêu Cầu Y Hệt
        GoSvc-->>Envoy: Phản Hồi Siêu Nhanh Bằng Go (< 25ms)
        Envoy->>Diff: Đẩy 2 Bản JSON Để So Sánh
        Diff->>Diff: Đối Chiếu Giá Bán, Tồn Kho & Thuộc Tính
        Diff-->>Diff: Ghi Nhận Độ Lệch (Mục Tiêu: 0% Khác Biệt)
    end

3. Triển Khai Thực Tế: Reverse Proxy & Shadow Mirroring Bằng Go

Đoạn mã Go dưới đây minh họa tầng trung gian (middleware) chặn bắt các yêu cầu HTTP, chuyển tiếp yêu cầu chính tới Magento cũ và nhân bản một luồng ngầm tới dịch vụ Go mới:

package main

import (
	"bytes"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"
)

type ShadowProxy struct {
	targetMonolith *httputil.ReverseProxy
	shadowURL      *url.URL
	httpClient     *http.Client
}

func NewShadowProxy(monolithAddr, shadowAddr string) (*ShadowProxy, error) {
	mURL, err := url.Parse(monolithAddr)
	if err != nil {
		return nil, err
	}
	sURL, err := url.Parse(shadowAddr)
	if err != nil {
		return nil, err
	}

	return &ShadowProxy{
		targetMonolith: httputil.NewSingleHostReverseProxy(mURL),
		shadowURL:      sURL,
		httpClient:     &http.Client{Timeout: 3 * time.Second},
	}, nil
}

func (sp *ShadowProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Đọc nội dung request một lần để nhân đôi luồng gửi đi
	bodyBytes, _ := io.ReadAll(r.Body)
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

	// Nhánh Shadow phi đồng bộ (Chạy ngầm, không chặn khách)
	go func(reqPath string, method string, payload []byte, headers http.Header) {
		shadowReq, err := http.NewRequest(method, sp.shadowURL.String()+reqPath, bytes.NewBuffer(payload))
		if err != nil {
			return
		}
		shadowReq.Header = headers.Clone()
		shadowReq.Header.Set("X-Shadow-Request", "true")

		t0 := time.Now()
		resp, err := sp.httpClient.Do(shadowReq)
		if err != nil {
			log.Printf("[Lỗi Shadow] Tuyến: %s | Chi tiết: %v", reqPath, err)
			return
		}
		defer resp.Body.Close()
		log.Printf("[Chỉ Số Shadow] Tuyến: %s | Trạng Thái: %d | Độ Trễ: %v", reqPath, resp.StatusCode, time.Since(t0))
	}(r.URL.Path, r.Method, bodyBytes, r.Header)

	// Nhánh chính chuyển tiếp đồng bộ tới Magento Monolith
	sp.targetMonolith.ServeHTTP(w, r)
}

4. Ma Trận So Sánh Các Chiến Lược Chuyển Đổi Nền Tảng

Chiến LượcRủi Ro Vận HànhKhả Năng Khôi Phục (Rollback)Tác Động Tới Khách HàngChi Phí Hạ Tầng
Đập Đi Xây Lại (Big Bang)Cực kỳ cao (>60% thất bại)Rất khó (Mất hàng giờ bảo trì)Nghiêm trọng (Lỗi đặt hàng)Thấp khi code, khổng lồ khi sập
Chạy Song Song 2 Cụm Đầy ĐủTrung bìnhNhanh (Đổi DNS)ThấpRất đắt (Gấp đôi hóa đơn máy chủ)
Strangler Fig (Chuẩn 2027)Rất thấp (< 2% rủi ro)Tức thì (Chỉnh trọng số = 0)Hoàn toàn Zero-DowntimeTối ưu (Tách đến đâu trả tiền đến đó)

❓ Câu Hỏi Thường Gặp (FAQ)

Cơ chế Shadow Traffic giúp đảm bảo dịch vụ Go mới hoạt động chính xác như thế nào?

Shadow Traffic nhân bản trực tiếp các yêu cầu HTTP thực tế của khách hàng tại tầng cổng vào. Trong khi khách hàng vẫn nhận câu trả lời từ Magento cũ một cách bình thường, yêu cầu nhân bản được gửi ngầm tới microservice Go. Một tiến trình so sánh sẽ kiểm tra đối chiếu từng trường dữ liệu JSON (giá bán, tồn kho, mã giảm giá) và phát hiện ngay nếu có sự sai lệch trước khi mở cho người dùng thực.

Làm thế nào để duy trì phiên đăng nhập (Session) của khách hàng xuyên suốt cả PHP và Go?

Một vùng đệm phiên dùng chung được thiết lập trên Redis Cluster. Khi khách hàng đăng nhập ở bất kỳ giao diện nào, hệ thống phát ra một mã xác thực JWT có chữ ký bảo mật HMAC-SHA256. Dịch vụ Go kiểm tra tính hợp lệ của mã này trong bộ nhớ RAM chỉ mất chưa tới 1 mili-giây, trong khi plugin trên Magento đồng bộ cookie phiên PHP tương ứng, giúp khách hàng không bao giờ bị văng tài khoản khi chuyển hướng giữa hai hệ thống.

Tại sao cần duy trì trạng thái 'Dự phòng nóng' (Hot Standby) trong 30 ngày sau khi đã chuyển đổi 100%?

Trong 30 ngày đầu tiên sau khi chuyển toàn bộ lưu lượng sang Go, mọi giao dịch phát sinh ở dịch vụ mới vẫn được một connector đồng bộ ngược trở lại cơ sở dữ liệu MySQL của Magento cũ. Nếu phát sinh bất kỳ sự cố nghiệp vụ biên hiếm gặp nào, đội ngũ vận hành có thể điều hướng lưu lượng quay ngược lại Magento ngay lập tức qua Envoy Gateway trong vòng 5 giây mà không làm thất thoát bất kỳ đơn hàng nào của khách.

🔗 Bước Tiếp Theo: Khám phá chi tiết Phần 5 — Bóc Tách Dữ Liệu Magento 2: Làm Phẳng EAV Bằng SQL & Node.js.