Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Production canary & shadow traffic

Mở đầu — vì sao bài này quan trọng

Suốt cả khóa học này, chúng ta đã cùng nhau dựng lên một "phòng thí nghiệm" hiệu năng khá hoàn chỉnh: từ JMeter, k6, cho tới dashboard Grafana, kịch bản soak, spike, flash sale. Nhưng có một sự thật phũ phàng mà mọi Performance Engineer giàu kinh nghiệm đều phải thừa nhận: môi trường staging không bao giờ giống production 100%.

Staging của bạn có thể chạy trên 2 pod thay vì 20 pod. Database staging có 100.000 dòng, còn production có 80 triệu dòng. Cache trên staging trống rỗng, còn trên production đã "ấm" (warm) sau nhiều ngày. Traffic staging là bot k6 gọi cùng một endpoint, còn traffic thật là 30.000 người dùng với đủ loại hành vi kỳ quặc mà không kịch bản nào mô phỏng nổi. Kết quả: một bản build "pass hết mọi test hiệu năng trên staging" vẫn có thể sập production ngay giờ cao điểm.

Vậy làm sao để kiểm chứng hiệu năng trên chính production mà không biến người dùng thật thành chuột bạch? Đó chính là nội dung của bài này: hai kỹ thuật cốt lõi để test an toàn trên production — Canary deployment (triển khai từng phần, quan sát trước khi mở rộng) và Shadow traffic (nhân đôi traffic thật để "bắn thử" phiên bản mới mà không ảnh hưởng người dùng). Đây là những kỹ thuật ở tầng cao nhất của nghề, nơi performance engineering giao thoa với release engineering và observability.

Khái niệm cốt lõi

Tại sao phải test trên production?

Nghe có vẻ liều lĩnh, nhưng đây là xu hướng trưởng thành của ngành. Cụm từ "testing in production" (TIP) không phải là làm ẩu — mà là chấp nhận rằng có những rủi ro chỉ bộc lộ dưới điều kiện production thật: data thật, phần cứng thật, cấu hình mạng thật, traffic thật với đủ loại pattern. Thay vì cố mô phỏng hoàn hảo (bất khả thi và tốn kém), ta triển khai theo cách giới hạn được bán kính thiệt hại (blast radius)quan sát được (observable), để nếu có sự cố thì chỉ một phần nhỏ người dùng bị ảnh hưởng và ta phát hiện tức thì.

Canary deployment là gì?

Từ "canary" (chim hoàng yến) bắt nguồn từ thời thợ mỏ mang chim vào hầm — nếu chim ngất do khí độc, thợ mỏ biết phải rút lui trước khi nguy hiểm đến mình. Trong software, canary là phiên bản mới được triển khai cho một tỷ lệ nhỏ traffic thật (ví dụ 1%, 5%, 10%), trong khi phần lớn traffic vẫn đi vào phiên bản cũ ổn định (gọi là "baseline" hoặc "stable").

Quy trình canary điển hình:

  • Deploy version mới song song với version cũ (cả hai cùng chạy).
  • Định tuyến (route) một phần nhỏ traffic — ví dụ 5% — vào canary.
  • So sánh metrics hiệu năng giữa canary và baseline: latency p95/p99, error rate, throughput, CPU/memory.
  • Nếu canary "khỏe" ngang hoặc tốt hơn baseline → tăng dần tỷ lệ (5% → 25% → 50% → 100%).
  • Nếu canary "ốm" (latency tăng vọt, error rate cao) → rollback tức thì, chỉ 5% người dùng bị ảnh hưởng trong thời gian ngắn.
Điểm mấu chốt với dân performance là bước 3: canary analysis. Ta không chỉ hỏi "canary có sập không?" mà hỏi "canary có chậm hơn baseline không?". Đây là nơi kiến thức metrics (Bài 6) và đọc kết quả (Bài 24, 38) phát huy tác dụng ngay trên production.

Shadow traffic (traffic mirroring) là gì?

Nếu canary vẫn cho người dùng thật "nếm thử" version mới (dù chỉ 5%), thì shadow traffic hoàn toàn không. Kỹ thuật này sao chép (mirror) traffic thật đang đi vào version cũ, rồi gửi bản sao đó song song sang version mới — nhưng response của version mới bị vứt bỏ, không bao giờ trả về cho người dùng.

flowchart LR
    U[Người dùng thật] --> LB[Load Balancer / Proxy]
    LB -->|response thật| U
    LB --> P[Production v1<br/>xử lý & trả kết quả]
    LB -.->|bản sao traffic| S[Shadow v2<br/>xử lý & vứt response]
    P --> M1[(Metrics baseline)]
    S --> M2[(Metrics shadow)]

Nhờ vậy, version mới nhận chính xác pattern traffic production thật — đúng endpoint, đúng payload, đúng tần suất, đúng giờ cao điểm — mà nếu nó chậm hay lỗi thì không một người dùng nào bị ảnh hưởng. Đây là cách kiểm chứng hiệu năng gần với thực tế nhất mà bạn có thể có, tốt hơn mọi kịch bản k6/JMeter tự viết.

Các công cụ hỗ trợ mirroring: Envoy (request_mirror_policies), Istio (VirtualService với mirror + mirrorPercentage), NGINX (mirror directive), hoặc AWS ALB/GoReplay.

Canary vs Shadow — khác biệt cốt lõi

Tiêu chíCanaryShadow
Người dùng thật thấy response version mới?Có (một phần)Không bao giờ
Rủi ro với người dùngThấp (giới hạn %)Gần như không
Kiểm chứng đúng traffic thật?Đúng nhưng chỉ một phầnĐúng 100%
Rủi ro side-effect (ghi DB, gửi email...)Có thậtNguy hiểm nếu không xử lý
Dùng khi nàoRelease chính thức từng bướcKiểm chứng hiệu năng trước release
Cảnh báo lớn nhất của shadow: side-effect. Nếu request thật là "đặt hàng" và shadow version cũng ghi vào DB, gửi email xác nhận, trừ tồn kho... thì bạn vừa tạo đơn hàng ma. Ta sẽ xử lý điều này ở phần hướng dẫn.

Tình huống thực tế

Ví dụ 1 — Sàn TMĐT "ShopViet" và cú canary cứu một đêm 12.12

ShopViet (giả định, quy mô ~40.000 đơn/ngày, cao điểm 12.12 lên 300.000 đơn) chuẩn bị lên phiên bản mới của service checkout với thư viện thanh toán được nâng cấp. Trên staging, k6 test cho kết quả p95 = 180ms, pass hết threshold. Team tự tin release.

May thay, họ dùng canary. Đêm trước 12.12, họ route 5% traffic checkout vào version mới. Sau 15 phút, Grafana cho thấy: baseline p99 = 240ms, còn canary p99 = 1.9s — chậm gấp gần 8 lần. Error rate canary cũng nhích lên 0.8% so với 0.05% của baseline. Điều tra nhanh phát hiện thư viện thanh toán mới mở một connection pool mới cho mỗi request thay vì tái sử dụng, gây cạn kết nối tới payment gateway dưới tải cao — thứ mà staging (traffic thấp) không bao giờ chạm tới.

Team rollback trong 2 phút. Chỉ 5% người dùng bị chậm trong 15 phút, không ai mất đơn. Nếu deploy thẳng 100% vào đúng đêm 12.12, đó đã là một thảm họa doanh thu.

Bài học: Canary phát hiện lỗi hiệu năng chỉ lộ ra dưới tải và data production. Đừng bao giờ deploy thẳng service tiền bạc vào giờ cao điểm.

Ví dụ 2 — Fintech "PayNhanh" dùng shadow traffic để rewrite service rủi ro

PayNhanh (giả định) muốn viết lại service risk-scoring (chấm điểm rủi ro giao dịch) từ Python monolith sang Go microservice. Vấn đề: service này cực nhạy cảm, không ai dám cho người dùng thật chạm vào version mới chưa được kiểm chứng, kể cả 1%.

Giải pháp: shadow traffic. Họ cấu hình Istio mirror 100% traffic sang service Go mới, nhưng vứt bỏ response. Suốt 2 tuần, service Go nhận đúng pattern giao dịch thật — cả những case kỳ lạ như giao dịch 3 giờ sáng, số tiền lẻ, user mới toanh. Kết quả thu được: version Go có p50 nhanh hơn 40% nhưng p99 lại cao hơn do garbage collection pause dưới burst traffic — một vấn đề chưa từng thấy trong load test nhân tạo. Họ tinh chỉnh GC tuning, chạy shadow thêm 1 tuần cho tới khi p99 ổn định, rồi mới bắt đầu canary thật.

Bài học: Shadow cho phép "chạy thử" version mới với traffic thật 100% mà zero rủi ro cho người dùng — hoàn hảo cho những rewrite nhạy cảm. Nhưng nó chỉ đo được read path; write side-effect phải bị chặn (risk-scoring chỉ đọc, không ghi, nên an toàn).

Ví dụ 3 — Startup giao đồ ăn và cái bẫy side-effect của shadow

Một startup giao đồ ăn khu vực Đông Nam Á muốn shadow-test version mới của service order. Họ bật NGINX mirror mà quên rằng service order gọi tiếp sang service gửi SMS xác nhận và trừ tồn kho nhà hàng. Kết quả: trong 20 phút shadow, hàng nghìn SMS "Đơn hàng của bạn đã được xác nhận" được gửi cho khách không hề đặt, và tồn kho một số món bị trừ sai lệch.

Họ phải xin lỗi khách và chạy job đối soát tồn kho suốt đêm.

Bài học: Shadow traffic không tự động an toàn. Mọi write/side-effect (DB, message queue, email/SMS, gọi bên thứ ba) phải được cô lập — dùng shadow database, feature flag is_shadow để short-circuit các tác vụ ghi, hoặc mock các downstream. Luôn hỏi: "Nếu tôi nhân đôi request này, cái gì trong thế giới thực sẽ thay đổi?"

Hướng dẫn từng bước

Dưới đây là quy trình thiết lập canary có kiểm soát hiệu năng, và cách bổ sung shadow.

Bước 1 — Chuẩn bị observability trước tiên. Không có metrics thì canary và shadow đều vô nghĩa. Đảm bảo cả version cũ lẫn mới đều emit metrics gắn label phân biệt (version=v1 / version=v2) cho: latency p50/p95/p99, error rate, throughput (RPS), CPU, memory. Chuẩn bị sẵn Grafana dashboard so sánh baseline vs canary cạnh nhau (tận dụng kiến thức Bài 22, 55).

Bước 2 — Triển khai canary với tỷ lệ nhỏ. Với Kubernetes + Istio, cấu hình VirtualService định tuyến theo trọng số:

http:
  - route:
      - destination: { host: checkout, subset: v1 }
        weight: 95
      - destination: { host: checkout, subset: v2 }
        weight: 5

Bắt đầu với 1–5%. Đừng vội. Để canary "ngâm" ít nhất 15–30 phút qua các pattern traffic khác nhau.

Bước 3 — Chạy canary analysis tự động. Đây là phần chuyên môn performance quan trọng nhất. Thay vì mắt người nhìn dashboard, dùng công cụ như Argo Rollouts hoặc Flagger để so sánh metrics canary vs baseline theo ngưỡng định trước. Ví dụ khai báo với Flagger:

metrics:
  - name: request-duration-p99
    thresholdRange: { max: 500 }   # p99 canary không được vượt 500ms
  - name: error-rate
    thresholdRange: { max: 1 }     # error rate không quá 1%

Nếu canary vi phạm ngưỡng qua nhiều lần đo liên tiếp → tự động rollback. Nếu đạt → tự động tăng weight.

Bước 4 — Tăng dần theo bậc thang. 5% → 25% → 50% → 100%, mỗi bậc "ngâm" và phân tích lại. Đây gọi là progressive delivery. Mỗi bậc là một cơ hội bắt lỗi hiệu năng dưới tải cao hơn.

Bước 5 — Thêm shadow traffic (khi cần kiểm chứng sâu hơn). Trước cả khi cho canary chạm người dùng, bạn có thể mirror traffic:

Istio VirtualService

http: - route: - destination: { host: checkout, subset: v1 } mirror: host: checkout subset: v2 mirrorPercentage: value: 10.0

Bước 6 — Cô lập side-effect cho shadow. Trong code version shadow, kiểm tra header phân biệt (ví dụ Istio thêm hostname có hậu tố -shadow) và short-circuit mọi tác vụ ghi:

if (isShadowRequest(req)) {
    // đọc, tính toán, đo hiệu năng — nhưng KHÔNG:
    // ghi DB thật, gửi email/SMS, gọi payment, publish message
}

Bước 7 — Thu thập, so sánh, quyết định. Đối chiếu metrics shadow/canary vs baseline. Chỉ khi version mới không chậm hơn baseline một cách có ý nghĩa thống kê, mới promote lên 100%. Ghi lại kết quả để phục vụ regression tracking (Bài 49).

Lỗi thường gặp & mẹo

  • Quên side-effect khi shadow (như ví dụ 3): sai lầm nguy hiểm nhất. Luôn vẽ sơ đồ downstream trước khi bật mirror. Nếu service có write, hãy dùng shadow database riêng hoặc chặn write bằng flag.
  • Canary quá ít traffic để có ý nghĩa thống kê. Route 1% cho một service chỉ có 50 RPS nghĩa là canary nhận 0.5 request/giây — không đủ dữ liệu để so p99. Với service tải thấp, tăng % hoặc kéo dài thời gian ngâm.
  • So sánh sai cơ sở (apples-to-oranges). Canary mới khởi động có cache lạnh (cold cache), JIT chưa ấm, connection pool chưa đầy — nên vài phút đầu luôn chậm hơn. Đừng vội rollback; cho thời gian warm-up, hoặc loại bỏ cửa sổ warm-up khỏi phân tích.
  • Chỉ nhìn giá trị trung bình (average). Average che giấu đuôi (tail). Một canary có avg 100ms nhưng p99 = 3s vẫn là thảm họa với người dùng ở đuôi. Luôn so p95/p99, không so mean.
  • Canary không đại diện (không có sticky routing đúng). Nếu bạn route theo user mà canary lại chỉ nhận toàn user tỉnh lẻ mạng chậm, kết quả méo mó. Đảm bảo canary nhận mẫu traffic ngẫu nhiên, đại diện.
  • Rollback không đủ nhanh. Toàn bộ giá trị của canary nằm ở khả năng rollback tức thì. Tự động hóa nó. Rollback thủ công lúc 2 giờ sáng là công thức cho thảm họa.
  • Mẹo — "dark launch" bằng feature flag. Kết hợp shadow/canary với feature flag để bật tính năng mới cho nội bộ nhân viên trước, rồi mới tới người dùng — thêm một lớp an toàn.
  • Mẹo — shadow để so sánh tính đúng đắn (correctness), không chỉ hiệu năng. Bạn có thể so response của shadow vs baseline (diff) để phát hiện version mới trả kết quả sai, ngoài việc đo tốc độ.

Bài tập thực hành

  • Thiết kế canary plan. Chọn một service bạn quen (thật hoặc giả định). Viết ra: các bậc tăng traffic (%), thời gian ngâm mỗi bậc, và 3 ngưỡng metric (p99 latency, error rate, và một metric tài nguyên như CPU) làm điều kiện auto-rollback. Giải thích vì sao chọn các con số đó.
  • Vẽ sơ đồ side-effect. Với service đó, liệt kê mọi tác vụ ghi/side-effect (DB, queue, email, gọi bên thứ ba). Đánh dấu cái nào phải bị chặn nếu chạy shadow, và mô tả cách chặn (flag, mock, shadow DB).
  • Phân tích canary giả lập. Cho dữ liệu: baseline p99 = 300ms err 0.1%, canary p99 = 310ms err 0.1% (nhưng 3 phút đầu canary p99 = 900ms). Bạn quyết định promote hay rollback? Giải thích vai trò của warm-up window trong quyết định.
  • (Nâng cao) Nếu có môi trường thử nghiệm, dựng Istio hoặc NGINX mirror 10% traffic từ một app demo sang một instance thứ hai, và xác nhận trên dashboard rằng instance shadow nhận traffic nhưng người dùng không thấy response của nó.

Tóm tắt

  • Staging không bao giờ thay thế được production; những lỗi hiệu năng nguy hiểm nhất chỉ lộ ra dưới data thật, phần cứng thật, traffic thật.
  • Canary deployment: cho một tỷ lệ nhỏ traffic thật nếm thử version mới, so sánh metrics canary vs baseline (đặc biệt p95/p99 và error rate), tăng dần nếu khỏe, rollback tức thì nếu ốm — giới hạn blast radius.
  • Shadow traffic (mirroring): nhân đôi traffic thật sang version mới nhưng vứt bỏ response, cho kiểm chứng hiệu năng với traffic thật 100% mà zero rủi ro người dùng — miễn là cô lập được mọi side-effect ghi.
  • Điều kiện tiên quyết cho cả hai: observability tốt (metrics gắn label version, dashboard so sánh cạnh nhau) và rollback tự động, tức thì.
  • Cạm bẫy lớn nhất của shadow là side-effect (đơn ma, SMS ma, tồn kho sai); cạm bẫy lớn nhất của canary là so sánh sai cơ sở (cold cache) và chỉ nhìn average thay vì tail.
  • Đây là kỹ thuật ở đỉnh của nghề Performance Engineer: nơi performance testing hòa vào release engineering và observability để đảm bảo mỗi lần lên production đều an toàn, có kiểm soát, và học được điều gì đó từ chính người dùng thật.
Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi