Menu
ESC

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

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

Đang tải...

Bài 16 — Deployment Strategies: Blue-Green, Canary, Rolling

Operations Management for Tech Bài 16/60

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

Hãy tưởng tượng bạn là người vận hành hệ thống của một sàn thương mại điện tử. 9 giờ tối thứ Sáu, sếp bảo: "Version mới đã test xong, deploy lên production đi." Bạn gõ lệnh, hệ thống tự động thay toàn bộ code cũ bằng code mới, và... 30 giây sau, trang thanh toán trả về lỗi 500 cho tất cả người dùng. Doanh thu tụt về 0 ngay giữa giờ cao điểm. Đến lúc bạn rollback được thì đã mất 15 phút và hàng nghìn đơn hàng.

Câu chuyện này không hiếm. Vấn đề không nằm ở chỗ code có bug — bug là chuyện luôn xảy ra. Vấn đề nằm ở cách bạn đưa code mới ra production. Nếu bạn thay 100% hệ thống cùng một lúc, thì khi có sự cố, 100% người dùng bị ảnh hưởng, và bạn không có đường lui nhanh.

Đây chính là lý do các chiến lược triển khai (deployment strategies) ra đời. Bài này sẽ đi sâu vào ba chiến lược phổ biến nhất mà bất kỳ kỹ sư vận hành nào cũng phải nắm vững: Blue-Green, Canary, và Rolling. Hiểu rõ ba chiến lược này giúp bạn trả lời được câu hỏi cốt lõi của nghề Ops: làm sao đưa thay đổi ra production mà giảm thiểu rủi ro, giới hạn "bán kính vụ nổ" (blast radius), và có thể quay lui trong vài giây thay vì vài chục phút.

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

Trước khi đi vào từng chiến lược, hãy nắm một nguyên tắc chung: mọi chiến lược triển khai hiện đại đều cố gắng tách rời hai thứ: việc cài đặt code mới lên máy chủ, và việc cho phép người dùng thật đi vào code mới đó. Khi bạn kiểm soát được luồng traffic đi vào phiên bản nào, bạn kiểm soát được rủi ro.

Blue-Green Deployment

Ý tưởng: bạn duy trì hai môi trường production giống hệt nhau — gọi là Blue và Green.

  • Blue là môi trường đang chạy, đang phục vụ 100% người dùng (phiên bản hiện tại).
  • Green là môi trường đứng yên, nơi bạn cài đặt và kiểm thử phiên bản mới.
Khi Green đã sẵn sàng và test xong, bạn chuyển toàn bộ traffic từ Blue sang Green bằng cách đổi cấu hình ở load balancer hoặc DNS. Chỉ trong vài giây, Green trở thành production, còn Blue trở thành môi trường dự phòng.

Ưu điểm:

  • Rollback cực nhanh: nếu Green có vấn đề, bạn chỉ cần chuyển traffic ngược về Blue. Blue vẫn còn nguyên đó, chưa bị đụng tới.
  • Không downtime: việc chuyển traffic diễn ra tức thời.
  • Test trên môi trường thật: Green là bản sao production, nên bạn có thể chạy smoke test trước khi mở cửa.
Nhược điểm:
  • Tốn gấp đôi tài nguyên: bạn phải nuôi hai môi trường đầy đủ cùng lúc, ít nhất là trong lúc chuyển đổi. Với hệ thống lớn, chi phí này không nhỏ.
  • Chuyển 100% traffic một lần: nếu Green có lỗi mà smoke test không bắt được, thì toàn bộ người dùng vẫn dính lỗi ngay khoảnh khắc chuyển. Bạn rollback nhanh nhưng vẫn có một cửa sổ ảnh hưởng toàn bộ.
  • Vấn đề database: cả Blue và Green thường dùng chung một database. Nếu phiên bản mới thay đổi schema, việc rollback trở nên phức tạp.

Canary Deployment

Tên gọi này bắt nguồn từ "canary in the coal mine" — thợ mỏ ngày xưa mang chim hoàng yến (canary) xuống hầm; nếu có khí độc, chim chết trước, báo hiệu cho người rút lui. Trong triển khai, "canary" là một nhóm nhỏ người dùng được đưa vào phiên bản mới trước để "thử nghiệm rủi ro".

Ý tưởng: thay vì chuyển 100% traffic, bạn chuyển từng phần nhỏ tăng dần. Ví dụ:

  • Cho 1% traffic vào phiên bản mới, quan sát 10-15 phút.
  • Nếu ổn (error rate, latency bình thường), tăng lên 5%, rồi 25%, rồi 50%.
  • Cuối cùng 100%.
Điểm mấu chốt của Canary là quan sát bằng số liệu. Ở mỗi mức, bạn theo dõi các chỉ số như tỉ lệ lỗi HTTP 5xx, độ trễ p95/p99, tỉ lệ đơn hàng thành công. Nếu chỉ số xấu đi, bạn dừng lại và rollback ngay khi chỉ mới có 1% người dùng bị ảnh hưởng.

Ưu điểm:

  • Giới hạn bán kính vụ nổ: chỉ 1% người dùng gặp rủi ro ở giai đoạn đầu, không phải 100%.
  • Ra quyết định dựa trên dữ liệu thật: bạn thấy hành vi phiên bản mới với traffic production thật, chứ không phải môi trường test.
  • Tiết kiệm tài nguyên hơn Blue-Green: bạn không cần nhân đôi toàn bộ hệ thống.
Nhược điểm:
  • Phức tạp hơn: cần hệ thống routing theo tỉ lệ phần trăm, cần observability tốt để đọc số liệu.
  • Chậm hơn: quá trình rollout có thể kéo dài hàng giờ.
  • Cần đủ traffic: nếu hệ thống bạn chỉ có vài request mỗi phút, thì 1% traffic không đủ để thống kê ra vấn đề.

Rolling Deployment

Ý tưởng: bạn có một cụm nhiều máy chủ (hoặc nhiều pod trong Kubernetes) đang chạy phiên bản cũ. Thay vì thay tất cả cùng lúc, bạn thay lần lượt từng nhóm nhỏ.

Ví dụ có 10 pod chạy version cũ. Rolling update sẽ: tắt 2 pod cũ, dựng 2 pod mới, chờ chúng healthy, rồi tiếp tục thay 2 pod tiếp theo, cho đến khi cả 10 pod đều là version mới. Trong suốt quá trình, hệ thống luôn có đủ pod phục vụ, nên không downtime.

Ưu điểm:

  • Không cần nhân đôi tài nguyên: bạn tận dụng chính cụm máy hiện có, chỉ cần dư một chút để thay lần lượt.
  • Đơn giản, mặc định sẵn: Kubernetes dùng Rolling Update làm chiến lược mặc định. Bạn gần như không cần cấu hình gì thêm.
Nhược điểm:
  • Rollback chậm hơn: để quay lui, bạn phải làm ngược lại quá trình rolling, thay từng pod về version cũ — mất thời gian.
  • Giai đoạn "trộn lẫn": trong lúc rolling, hệ thống chạy đồng thời cả version cũ và mới. Nếu hai version không tương thích (ví dụ API thay đổi), sẽ phát sinh lỗi khó lường.
  • Khó kiểm soát blast radius chính xác như Canary, vì việc phân phối traffic theo pod chứ không theo tỉ lệ phần trăm có chủ đích.

Bảng so sánh nhanh

Tiêu chíBlue-GreenCanaryRolling
Tốc độ rollbackRất nhanh (đổi traffic)Nhanh (dừng ở % nhỏ)Chậm (rolling ngược)
Chi phí tài nguyênCao (gấp đôi)Trung bìnhThấp
Blast radius ban đầu100% khi chuyểnRất nhỏ (1-5%)Từng phần
Độ phức tạpTrung bìnhCaoThấp
Cần observability tốtNên cóBắt buộcNên có

Tình huống thực tế

Ví dụ 1: Sàn TMĐT Việt Nam dùng Blue-Green cho ngày sale lớn

Một sàn thương mại điện tử tại TP.HCM (tạm gọi là "ShopViet") chuẩn bị cho đợt sale 11/11. Họ cần deploy phiên bản mới của service giỏ hàng, nhưng tuyệt đối không được để xảy ra downtime giữa giờ cao điểm.

Đội Ops chọn Blue-Green. Họ dựng môi trường Green với version mới, chạy một bộ smoke test tự động gồm 200 kịch bản (thêm hàng vào giỏ, áp mã giảm giá, thanh toán thử). Test xong lúc 2 giờ sáng — giờ traffic thấp — họ chuyển load balancer từ Blue sang Green trong đúng 3 giây.

Kết quả: 20 phút sau, dashboard báo tỉ lệ lỗi ở API áp mã giảm giá tăng từ 0.1% lên 4%. Vì Blue vẫn còn nguyên, họ chuyển traffic ngược về Blue chỉ trong 5 giây. Người dùng gần như không cảm nhận được sự cố.

Bài học: Blue-Green tỏa sáng khi bạn cần khả năng rollback tức thời và có ngân sách nuôi hai môi trường. Nhưng nó cũng cho thấy điểm yếu: smoke test 200 kịch bản vẫn không bắt được lỗi 4% kia, vì lỗi chỉ xuất hiện với dữ liệu người dùng thật. Đây chính là chỗ Canary sẽ làm tốt hơn.

Ví dụ 2: Grab và Canary cho tính năng tính giá cước

Một công ty gọi xe khu vực Đông Nam Á (bối cảnh tương tự Grab) cần triển khai thuật toán tính giá cước mới. Đây là thứ cực nhạy cảm: sai một chút là tính sai tiền hàng triệu chuyến xe, ảnh hưởng cả tài xế lẫn khách.

Họ chọn Canary. Bắt đầu bằng cách cho 1% chuyến xe ở một khu vực nhỏ (ví dụ quận 7, TP.HCM) đi qua thuật toán mới. Họ theo dõi ba chỉ số: giá cước trung bình có lệch bất thường không, tỉ lệ khách hủy chuyến sau khi xem giá, và số khiếu nại về giá.

Sau 30 phút, chỉ số ổn định, họ tăng lên 5%, rồi 20%. Đến mức 20%, họ phát hiện tỉ lệ hủy chuyến ở khu vực có mưa tăng vọt — hóa ra thuật toán mới nhân hệ số thời tiết quá cao. Họ dừng rollout ngay, và chỉ 20% (không phải 100%) người dùng bị ảnh hưởng trong thời gian ngắn.

Bài học: Canary cho phép bạn phát hiện lỗi mà môi trường test không bao giờ tái hiện được — như tương tác giữa thuật toán giá và thời tiết thật. Điều kiện tiên quyết là bạn phải có observability đủ tốt và đủ traffic để số liệu có ý nghĩa thống kê. Với một công ty gọi xe hàng triệu chuyến/ngày, 1% vẫn là hàng chục nghìn chuyến — quá đủ để đọc tín hiệu.

Ví dụ 3: Startup fintech dùng Rolling trên Kubernetes

Một startup fintech ở Hà Nội chạy backend trên Kubernetes với 12 pod cho service xác thực OTP. Họ deploy nhiều lần mỗi ngày, mỗi lần thay đổi nhỏ. Nuôi hai môi trường Blue-Green quá tốn kém cho quy mô của họ, và họ chưa có hệ thống routing đủ tinh vi cho Canary.

Họ dùng Rolling Update mặc định của Kubernetes, cấu hình maxUnavailable: 1maxSurge: 2 — nghĩa là tại mỗi thời điểm chỉ tối đa 1 pod cũ bị tắt, và được phép dựng thêm tối đa 2 pod. Mỗi pod mới phải qua readinessProbe (kiểm tra pod sẵn sàng nhận traffic) rồi mới nhận request.

Một lần, họ deploy version quên set biến môi trường kết nối Redis. Pod mới đầu tiên fail readinessProbe, không bao giờ được đưa vào phục vụ, và Kubernetes tự động dừng rollout. 11 pod cũ vẫn chạy bình thường, người dùng không hề bị ảnh hưởng.

Bài học: Rolling Update đơn giản, rẻ, và khi cấu hình health check đúng cách, nó tự bảo vệ bạn khỏi những lỗi cấu hình cơ bản. Nhưng nếu version mới chạy được nhưng có bug logic, Rolling không có cơ chế đọc số liệu để dừng như Canary — đó là giới hạn cần biết.

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

Đây là quy trình chọn và thực thi một chiến lược triển khai an toàn:

Bước 1 — Đánh giá rủi ro của thay đổi. Thay đổi càng nhạy cảm (thanh toán, xác thực, tính tiền) thì càng nên nghiêng về Canary. Thay đổi nhỏ, ít rủi ro thì Rolling là đủ.

Bước 2 — Kiểm tra điều kiện tiên quyết.

  • Có đủ traffic để Canary có ý nghĩa thống kê không?
  • Có ngân sách nuôi hai môi trường cho Blue-Green không?
  • Observability đã đủ tốt chưa (bạn cần đo được error rate, latency, và chỉ số nghiệp vụ)?
Bước 3 — Đảm bảo tương thích ngược (backward compatibility). Vì mọi chiến lược đều có giai đoạn version cũ và mới chạy song song, code mới phải làm việc được với dữ liệu và schema cũ. Với thay đổi database, hãy tách thành nhiều bước: thêm cột mới trước, deploy code, rồi mới xóa cột cũ ở lần deploy sau (expand-contract pattern).

Bước 4 — Định nghĩa tiêu chí thành công và thất bại rõ ràng trước khi deploy. Ví dụ: "error rate < 0.5% và p99 latency < 300ms trong 15 phút thì tăng bước tiếp theo; ngược lại rollback tự động."

Bước 5 — Chuẩn bị đường lui. Trước khi deploy, hãy chắc chắn bạn biết chính xác lệnh/nút bấm để rollback, và đã thử nó ít nhất một lần.

Bước 6 — Thực thi và quan sát. Đừng deploy rồi bỏ đi. Ngồi nhìn dashboard trong khoảng thời gian quan trọng nhất — thường là 15-30 phút đầu.

Bước 7 — Ghi lại kết quả. Deploy thành công hay thất bại đều là dữ liệu quý để cải tiến quy trình.

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

  • Quên vấn đề database schema. Đây là lỗi giết chết Blue-Green nhiều nhất. Bạn rollback code dễ dàng, nhưng nếu migration đã đổi schema theo cách không tương thích ngược, code cũ không chạy được với schema mới. Luôn dùng expand-contract: migration phải tương thích với cả hai version.
  • Canary mà không nhìn số liệu. Canary chỉ có giá trị khi bạn thực sự đọc metrics ở mỗi bước. Cho 1% traffic rồi 5 phút sau nhảy thẳng 100% mà không quan sát thì bạn chỉ đang làm "Rolling đội lốt Canary".
  • Chọn Canary khi traffic quá thấp. Nếu hệ thống bạn có 10 request/phút, thì 1% là 0.1 request/phút — không bao giờ đủ để phát hiện lỗi. Lúc này Blue-Green với smoke test kỹ càng lại phù hợp hơn.
  • Không cấu hình health check đúng. Rolling Update dựa hoàn toàn vào readiness/liveness probe. Nếu probe của bạn chỉ kiểm tra "port có mở không" thay vì "app thực sự phục vụ được không", thì pod hỏng vẫn bị đưa vào phục vụ.
  • Mẹo tự động hóa rollback. Đừng chờ con người phát hiện lỗi. Cấu hình để hệ thống tự rollback khi error rate vượt ngưỡng. Các công cụ như Argo Rollouts, Flagger, hoặc Spinnaker hỗ trợ analysis tự động cho Canary.
  • Mẹo kết hợp chiến lược. Trong thực tế, nhiều đội kết hợp: dùng Blue-Green cho hạ tầng nhưng cho traffic vào Green theo kiểu Canary tăng dần. Đừng nghĩ ba chiến lược là loại trừ nhau.

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

  • Phân tích tình huống: Công ty bạn có một service báo cáo nội bộ, chỉ khoảng 50 nhân viên dùng, traffic rất thấp, chạy trên 3 máy chủ. Bạn nên chọn chiến lược nào và vì sao? (Gợi ý: cân nhắc yếu tố traffic thấp và số máy chủ ít.)
  • Thiết kế tiêu chí Canary: Với service thanh toán, hãy liệt kê 3 chỉ số cụ thể bạn sẽ theo dõi ở mỗi bước Canary, kèm ngưỡng số cụ thể để quyết định "tiếp tục" hay "rollback".
  • Bẫy database: Bạn cần đổi tên một cột trong database từ phone thành phone_number. Hãy viết ra chuỗi các bước deploy (theo expand-contract) để việc này an toàn với Rolling Update, đảm bảo cả version cũ và mới đều chạy được trong giai đoạn chuyển tiếp.
  • Tính chi phí: Hệ thống production của bạn cần 20 máy chủ. Nếu dùng Blue-Green, bạn cần bao nhiêu máy trong lúc chuyển đổi? Chi phí này có xứng đáng với lợi ích rollback tức thời cho ứng dụng của bạn không?

Tóm tắt

  • Mọi chiến lược triển khai đều nhằm một mục tiêu: giảm rủi ro khi đưa code ra production bằng cách kiểm soát traffic đi vào phiên bản mới.
  • Blue-Green: hai môi trường song song, chuyển 100% traffic một lần. Rollback tức thời nhưng tốn gấp đôi tài nguyên và blast radius ban đầu là 100%.
  • Canary: tăng traffic dần từ 1% lên 100%, quan sát số liệu ở mỗi bước. Giới hạn blast radius tốt nhất, nhưng phức tạp và cần observability cùng đủ traffic.
  • Rolling: thay lần lượt từng nhóm máy chủ. Đơn giản, rẻ, mặc định trong Kubernetes, nhưng rollback chậm và có giai đoạn trộn lẫn version.
  • Việc chọn chiến lược phụ thuộc vào: mức độ rủi ro của thay đổi, lượng traffic, ngân sách, và độ trưởng thành của hệ thống observability.
  • Dù chọn chiến lược nào, hai nguyên tắc bất biến là: đảm bảo tương thích ngược (đặc biệt với database) và luôn chuẩn bị sẵn đường lui đã được kiểm chứng.