Deploy nhiều microservice không downtime
Best practice không phải Jenkins deploy đồng loạt mọi service. Mỗi service phải deploy độc lập trong một khoảng compatibility, còn thay đổi schema/API/event được chia thành nhiều release nhỏ có thể cùng tồn tại.
1. Rolling update chỉ là lớp compute
v1 pods: 4 -> 3 -> 2 -> 1 -> 0
v2 pods: 0 -> 1 -> 2 -> 3 -> 4
Trong rollout luôn có lúc v1 và v2 cùng nhận traffic.Kubernetes Deployment tạo ReplicaSet mới, thêm pod v2 rồi giảm pod v1 theo maxSurge/maxUnavailable. Readiness loại pod chưa sẵn sàng; preStop, termination grace và load-balancer drain bảo vệ in-flight request. Nhưng rolling update không giải quyết database schema, API/event compatibility hay workflow đang chạy dở.
2. Quy tắc nền tảng: N và N-1 tương thích
Version mới của producer/consumer/database schema phải làm việc được với version đang chạy và thường cả version trước đó trong rollout/rollback window:
- New service đọc được dữ liệu do old service viết.
- Old service không fail khi new service đã mở rộng schema/data.
- New producer không bắt buộc consumer mới phải deploy cùng lúc.
- New consumer vẫn xử lý event/API response cũ.
- Rollback application không bị schema/data mới phá.
Nếu deployment bắt buộc tất cả service đổi cùng lúc mới hoạt động, hệ thống đang có distributed-monolith coupling.
3. Jenkins/pipeline thường deploy thế nào?
service repository change
-> build/test/contract/security
-> publish immutable image digest
-> update manifest for that service
-> deploy dev -> integration -> staging
-> canary production -> automated SLO gate -> full rollout
Shared contract/library change
-> publish backward-compatible version
-> consumers upgrade independently
-> remove old contract only after usage evidence = 0Mỗi service có pipeline/artifact/deployment riêng. Jenkins không cần “deploy hết”; nó chỉ deploy affected service. Monorepo dùng dependency graph/change detection nhưng shared change phải fan-out test đúng. Một business feature xuyên nhiều service được release bằng compatible deployments + feature flag, không bằng một transaction deploy toàn hệ thống.
4. Database migration: Expand → Migrate → Contract
Không deploy code chỉ chạy được sau destructive migration trong cùng một bước. Chia thành nhiều release:
Release A - EXPAND
add nullable column/new table/index concurrently
old code continues working
Release B - DUAL COMPATIBILITY
deploy code that can read old and new
optionally dual-write with idempotency/observability
Migration job - MIGRATE
backfill in bounded batches, checkpoint, throttle, retry
Release C - SWITCH
switch reads to new field behind flag
verify metrics/data reconciliation
Release D - CONTRACT
stop old writes, remove old code
later drop old column/constraint after rollback windowContract thường cách expand nhiều ngày/release, không nằm cùng pipeline run.
5. Ví dụ rename column an toàn
Sai:
alter table orders rename column total to total_amount;
// v1 pods vẫn SELECT total -> fail trong rolling updateAn toàn hơn:
-- Release A
alter table orders add column total_amount numeric(19,2);
-- Backfill batches
update orders set total_amount = total
where id > :last_id and id <= :next_id and total_amount is null;
-- Release B/C: code reads COALESCE(total_amount, total), writes compatible values
-- Verify no null/mismatch, then add constraint safely
-- Release D later: remove total only after all old versions are goneDual-write có race/partial-write risk; tốt hơn nếu database trigger hoặc một authoritative write path phù hợp, nhưng trigger cũng cần lifecycle/observability. Luôn reconciliation trước contract.
6. Migration job chạy ở đâu?
| Cách | Đánh giá |
|---|---|
| Mỗi pod tự chạy Flyway lúc startup | Đơn giản cho migration nhỏ/compatible, nhưng nhiều pod cạnh tranh lock; migration lâu làm readiness/startup khó đoán. |
| Singleton Kubernetes Job/pipeline stage | Ownership/evidence rõ; phải idempotent và app versions compatible trước/sau job. |
| Operator/controller | Phù hợp platform trưởng thành; thêm complexity. |
Best practice thường tách migration thành job một lần với lock, timeout, logs và failure policy. Tuy nhiên “migration trước hay code trước” không có câu trả lời chung: expand migration chạy trước code; contract migration chỉ chạy sau khi code cũ biến mất.
7. Migration lớn không chạy như một transaction khổng lồ
- Backfill theo primary-key range/batch, checkpoint và resume.
- Throttle theo DB CPU/I/O/replication lag/lock wait.
- Tránh table rewrite/long exclusive lock; dùng online/concurrent index theo database.
- Đặt lock timeout/statement timeout và abort an toàn.
- Không giữ deploy pipeline chờ backfill hàng giờ; migration có workflow/monitor riêng.
- Schema change và data migration có audit, dry run, estimate và rollback/forward-fix plan.
8. API compatibility giữa service
// Producer mới thêm field optional
{
"orderId": "...",
"status": "CONFIRMED",
"reservationExpiresAt": "..." // consumer cũ phải ignore được
}- Additive fields trước; không rename/remove/change meaning trực tiếp.
- Consumer không reject unknown fields nếu contract cho phép.
- New required request field cần default/server derivation hoặc endpoint/version mới.
- Contract tests kiểm tra provider mới với consumer contracts đang production.
- Deprecation có inventory consumer, telemetry và sunset process.
Gateway versioning không tự giải quyết service-to-service compatibility; semantic change vẫn cần migration path.
9. Event compatibility
OrderConfirmed v1 -> consumers A(v1), B(v1)
OrderConfirmed v2 -> producer deploy trước? chỉ khi old consumers đọc được
Ưu tiên additive schema, default và tolerant reader. Nếu breaking, publish event type/version mới song song; migrate consumers; đo không còn consumer/traffic cũ rồi ngừng v1. Event lưu lâu/replay khiến compatibility window dài hơn HTTP. Không serialize JPA entity trực tiếp.
10. Feature nhiều service được release thế nào?
- Deploy database expand/contract additions.
- Deploy downstream consumers/providers có backward-compatible support nhưng feature tắt.
- Deploy upstream callers/producers vẫn dùng old behavior mặc định.
- Bật feature cho internal tenant/canary percentage.
- Quan sát end-to-end business SLI và reconciliation.
- Tăng rollout; giữ kill switch.
- Sau stability/rollback window mới xóa old path/schema/event.
Deployment order thường “downstream capability trước, upstream usage sau”. Feature flag tách deploy khỏi release, nhưng flag cần owner, expiry và test cả on/off/mixed version.
11. Ví dụ Order gọi Inventory API mới
Phase 1: Inventory v2 deploy, vẫn hỗ trợ /decrement cũ,
thêm /reservations mới.
Phase 2: Order v2 deploy với flag inventory-reservation=false.
Phase 3: bật flag 1% -> 10% -> 100%; monitor reservation leak/latency.
Phase 4: Order v1 và old path không còn traffic.
Phase 5: deprecate/remove /decrement trong Inventory release sau.Không cần Jenkins deploy hai service cùng một lúc. Nếu Order v2 rollback, Inventory v2 vẫn hỗ trợ API cũ.
12. Rollback không đơn giản là image cũ
| Thay đổi | Rollback strategy |
|---|---|
| Code-only compatible | Rollback image/digest. |
| Additive schema | Rollback code, giữ schema thừa. |
| New data format đã write | Old code phải đọc được; nếu không, forward fix/data conversion. |
| Destructive schema | Khó/không thể rollback nhanh; restore gây data loss và downtime. |
| External side effect/event | Không rollback bằng image; cần compensation/reconciliation. |
Vì vậy ưu tiên roll-forward khi migration/data side effect đã xảy ra. Rollback plan phải được thiết kế trước deploy và diễn tập.
13. Kubernetes rollout settings
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0
minReadySeconds: 10
progressDeadlineSeconds: 600- Readiness chỉ true khi pod nhận traffic an toàn; startup probe cho initialization lâu.
preStop+terminationGracePeriodSecondsđủ drain HTTP/message.- PodDisruptionBudget bảo vệ voluntary disruption, không bảo đảm capacity mọi failure.
- Capacity phải chứa surge; HPA và rollout có thể tương tác.
- Canary/blue-green qua Argo Rollouts/Flagger/service mesh hoặc pipeline routing tùy platform.
14. Pipeline orchestration mẫu
stages {
stage('Build & verify') { /* tests, contracts, scan */ }
stage('Publish image') { /* immutable digest */ }
stage('Expand migration') { /* approved singleton job */ }
stage('Deploy canary') { /* only this service */ }
stage('Analyze') { /* SLO/business/schema metrics */ }
stage('Promote') { /* progressive traffic */ }
}
// Backfill and contract are separate tracked workflows/releases.Jenkins có thể trigger downstream pipeline khi thật sự cần capability ordering, nhưng tránh một “mega pipeline” deploy mọi service. Release manifest có thể ghi tập version đã verified cùng nhau mà vẫn cho phép deploy độc lập.
15. Khi nào cần coordinated release?
Đôi khi compliance, protocol switch hoặc security incident yêu cầu coordination. Vẫn dùng phases:
- Pre-deploy compatibility/shim.
- Quiesce hoặc maintenance window nếu invariant không thể giữ online.
- Fencing/traffic gate để không có mixed writes nguy hiểm.
- Explicit go/no-go, backup/restore evidence và rollback cutoff.
Zero downtime không phải giáo điều. Nếu online migration rủi ro hơn một maintenance window được kiểm soát, chọn downtime có kế hoạch và truyền thông rõ.
16. Observability và deployment gates
- Technical: availability, error rate, p95/p99, saturation, restarts, readiness.
- Compatibility: unknown field/deserialization/404/409, event DLQ, contract mismatch.
- Database: lock wait, migration progress, replication lag, dead tuples, query plan regression.
- Business: order completion, payment success, reservation leak, stuck Saga.
- Deployment marker/version trên logs, metrics và traces; compare canary với stable.
17. Failure cases cần drill
| Failure | Expected response |
|---|---|
| Migration job fail giữa batch | Resume checkpoint; schema vẫn compatible; app không downtime. |
| Canary error tăng | Stop traffic/promote; rollback code, giữ additive schema. |
| Old consumer nhận event mới | Tolerant schema hoặc producer flag off; DLQ alert không phải discovery đầu tiên. |
| New code write format old code không đọc | Gate rollout/rollback; dual-read/data conversion hoặc forward fix. |
| Pod killed khi processing | Drain/visibility timeout/redelivery + idempotent consumer. |
| Contract migration chạy quá sớm | Incident: stop rollout, forward restore compatibility; không drop destructive tự động. |
18. Bài thực hành
- Thêm column bắt buộc vào Order bằng expand/backfill/constraint/contract qua bốn releases.
- Chạy v1 và v2 pods đồng thời; test cả hai đọc/write cùng schema.
- Thêm Inventory reservation API trong khi giữ endpoint cũ; bật bằng feature flag canary.
- Publish event v2 additive; chạy consumer v1/v2 và replay event lịch sử.
- Inject migration failure ở batch 3; resume không duplicate/mất dữ liệu.
- Rollback v2 sau khi đã write data mới; chứng minh v1 vẫn đọc được hoặc ghi rõ forward-fix.
- Canary gate theo error/latency và business stuck-order metric.
- Kill pod giữa message; chứng minh redelivery không tạo double effect.
19. Checklist phỏng vấn
- Rolling update luôn có mixed versions.
- N/N-1 compatibility cho DB/API/event.
- Expand–migrate–contract chia nhiều release.
- Migration singleton, idempotent, bounded và observable.
- Mỗi service build/deploy độc lập; feature xuyên service dùng flag/capability ordering.
- Downstream support deploy trước upstream usage.
- Rollback code khác rollback data/side effect.
- Contract removal dựa usage evidence, không dựa “chắc không ai dùng”.
- Canary gate có business metrics.
- Biết khi nào maintenance window an toàn hơn zero downtime.