API
RAM
N+1
State and Scale
cron • file • memory

Stateless và stateful khi scale nhiều instance

Giải thích stateless và stateful cho backend, kèm lỗi hay gặp khi scale như schedule chạy trùng, lưu file local và giữ state trong memory.

10 phút đọc16/06/2026

Rất nhiều project chạy ổn khi chỉ có 1 instance.

Nhưng đến lúc cần scale thêm instance để chịu tải, rất nhiều bug bắt đầu lộ ra:

  • cron chạy trùng
  • cache nằm trong biến memory bị lệch giữa các máy
  • upload file xong máy khác không thấy
  • user hit qua instance khác thì session mất

Gốc của những lỗi này thường nằm ở chỗ code chưa được thiết kế rõ theo hướng stateless hay đang vô tình giữ quá nhiều state trong từng instance.

Kết luận nhanh

Nếu cần nhớ ngắn gọn:

  1. stateless giúp scale ngang dễ hơn vì mỗi instance có thể xử lý request gần như độc lập
  2. stateful không sai, nhưng nếu không kiểm soát tốt thì khi tăng instance rất dễ phát sinh bug khó đoán
  3. những thứ dễ gây lỗi nhất khi scale là schedule, file local, session local và data giữ trong variable memory
  4. nếu muốn scale thêm instance an toàn, phải đẩy state quan trọng ra ngoài app process

Stateless là gì?

Hiểu thực dụng:

  • một request đi vào instance A hay instance B thì kết quả vẫn phải nhất quán
  • app không phụ thuộc vào dữ liệu tạm đang nằm riêng trong RAM của một instance cụ thể

Ví dụ gần với stateless:

  • request API đọc dữ liệu từ database
  • auth dựa vào token hoặc session store chung
  • file nằm ở object storage hoặc shared storage
  • cache nằm ở Redis

Ý chính là:

  • instance chỉ xử lý logic
  • state quan trọng không nằm cứng trong chính process đó

Stateful là gì?

Stateful nghĩa là app hoặc flow đang phụ thuộc vào trạng thái giữ bên trong một instance cụ thể.

Ví dụ:

  • session user nằm trong memory của process
  • app giữ một map dữ liệu runtime trong biến global
  • file upload được ghi vào local disk của đúng instance đó
  • cron job trong từng instance tự quyết định trạng thái xử lý

Những thứ này vẫn có thể chạy ổn khi chỉ có 1 máy.
Nhưng khi thêm instance thứ 2, thứ 3 thì bắt đầu rắc rối.

Vì sao hiểu stateless/stateful lại quan trọng khi scale?

Vì scale ngang gần như luôn giả định:

  • nhiều instance có thể thay nhau xử lý request
  • request nào cũng có thể rơi vào bất kỳ instance nào
  • instance có thể bị kill, restart, replace bất cứ lúc nào

Nếu code đang ngầm giả định:

  • “máy này giữ dữ liệu đó”
  • “cron này chỉ chạy một lần”
  • “biến này luôn còn trong RAM”

thì khi scale lên, bug sẽ xuất hiện rất nhanh.

Lỗi 1: giữ data trong variable memory

Đây là lỗi rất phổ biến.

Ví dụ:

const onlineUsers = new Map<string, string>();

Nếu bạn lưu state kiểu này trong app:

  • instance A có onlineUsers riêng
  • instance B có onlineUsers riêng

Khi scale lên 2-3 instance:

  • data giữa các instance không đồng bộ
  • logic kiểm tra trạng thái user có thể sai
  • request trước vào máy A, request sau vào máy B thì context biến mất

Nếu dữ liệu đó quan trọng cho business, nó không nên chỉ sống trong RAM của một process.

Nên thay bằng:

  • Redis
  • database
  • message queue
  • distributed cache

tùy bài toán.

Lỗi 2: session hoặc auth state nằm local trong app

Nếu session chỉ nằm trong memory local:

  • user login qua instance A
  • request tiếp theo đi vào instance B
  • session không còn

Kết quả là:

  • login chập chờn
  • auth lúc được lúc mất
  • scale lên xong tưởng load balancer lỗi

Nếu muốn scale nhiều instance ổn định, session nên nằm ở:

  • Redis
  • database
  • hoặc dùng token stateless phù hợp

Lỗi 3: schedule chạy trùng khi tăng instance

Đây là pain point production rất hay gặp.

Ví dụ mỗi instance đều chạy:

  • cron gửi email
  • cron đồng bộ dữ liệu
  • cron cleanup
  • cron charge billing

Khi còn 1 instance:

  • mọi thứ có vẻ ổn

Khi tăng lên 3 instance:

  • cron chạy 3 lần
  • email gửi trùng
  • job cleanup đá nhau
  • billing hoặc sync có thể bị chạy nhiều lần

Đây là ví dụ kinh điển của stateful behavior bị giấu trong app.

Nếu app có schedule quan trọng, cần nghĩ theo một trong các hướng:

  1. chỉ một worker chuyên chạy schedule
  2. dùng distributed lock
  3. dùng queue / job system
  4. để scheduler ngoài app chính điều phối

Nói ngắn gọn:

  • đừng để mọi instance web cùng tự chạy schedule quan trọng nếu không có cơ chế coordination

Lỗi 4: lưu file ngay trong source hoặc local disk của instance

Đây là lỗi rất hay gặp ở app upload file hoặc export file.

Ví dụ:

  • user upload avatar
  • app ghi vào ./uploads

Khi có 1 instance:

  • nhìn có vẻ ổn

Khi scale lên nhiều instance:

  • upload vào máy A
  • request đọc file lại rơi vào máy B
  • file không thấy

Nếu còn deploy lại container hoặc replace EC2:

  • file local còn có thể mất luôn

Đây là lý do file người dùng upload không nên giữ trong:

  • source code folder
  • local disk tạm của container
  • local path chỉ gắn với một instance

Nên dùng:

  • S3
  • shared storage
  • object storage tương đương

Lỗi 5: giữ progress hoặc trạng thái xử lý trong app instance

Ví dụ:

  • job đang chạy tới bước nào
  • ai đang xử lý item nào
  • batch nào đang pending

Nếu chỉ giữ những state đó trong memory:

  • restart là mất
  • scale thêm instance là lệch
  • failover rất khó

Những state dạng workflow nên được lưu ở nơi bền hơn:

  • database
  • Redis
  • queue backend

Stateless có phải lúc nào cũng tốt hơn không?

Không phải mọi thứ đều phải “stateless tuyệt đối”.

Thực tế:

  • hệ thống nào cũng có state

Vấn đề không phải là xoá hết state.
Vấn đề là:

  • state đang nằm ở đâu
  • có bền không
  • có chia sẻ được giữa nhiều instance không
  • có survive restart không

Nói cách khác:

  • business vẫn có state
  • nhưng app instance không nên là nơi giữ state quan trọng một cách âm thầm

Cách áp dụng để scale thêm instance an toàn hơn

Nếu bạn muốn codebase đỡ phát sinh bug khi scale, có thể đi theo checklist này:

1. Giả định request có thể rơi vào bất kỳ instance nào

Khi viết code, luôn nghĩ:

  • request sau chưa chắc vào lại cùng máy

Chỉ mindset này thôi đã giúp bạn tránh rất nhiều lỗi local-state.

2. Đẩy state quan trọng ra ngoài app process

Ví dụ:

  • session -> Redis / DB
  • file -> S3 hoặc object storage
  • cache shared -> Redis
  • workflow state -> DB / queue backend

3. Tách web instance và worker / scheduler nếu cần

Đây là cách rất thực dụng.

Đừng bắt mọi instance web vừa:

  • serve request
  • vừa chạy cron
  • vừa xử lý queue

Nếu system đã lớn, nên tách vai trò rõ hơn:

  • web instances
  • worker instances
  • scheduler riêng nếu cần

4. Dùng idempotent design cho job quan trọng

Kể cả có lock hoặc queue, vẫn nên thiết kế job quan trọng theo hướng:

  • chạy lại không phá data
  • cùng một request không gây duplicate nguy hiểm

Điều này cực quan trọng khi scale và khi xử lý retry.

5. Xem local disk là tạm thời

Trong môi trường scale ngang hoặc container:

  • local disk gần như nên được xem là chỗ tạm

Đừng dùng nó làm nơi giữ dữ liệu business lâu dài nếu không có lý do rất rõ.

Một cách tự kiểm tra code có dễ scale không

Trước khi tăng số instance, tự hỏi:

  1. nếu request tiếp theo sang máy khác thì có lỗi không?
  2. nếu instance restart thì có mất state quan trọng không?
  3. nếu scale từ 1 lên 3 instance thì schedule có chạy trùng không?
  4. nếu file upload nằm local thì máy khác có đọc được không?
  5. nếu một biến memory bị reset thì business có vỡ không?

Nếu câu trả lời là “có” ở nhiều chỗ, hệ thống chưa sẵn sàng để scale ngang an toàn.

Khi nào stateful vẫn chấp nhận được?

Stateful không phải lúc nào cũng xấu.

Một số thứ vẫn có thể giữ local nếu:

  • chỉ là cache phụ
  • mất cũng không sao
  • không ảnh hưởng business correctness

Ví dụ:

  • in-memory cache nhỏ để tối ưu read
  • map tạm cho metric không quan trọng

Nhưng phải rất rõ ràng:

  • đó là optimization
  • không phải source of truth

Kết luận

Hiểu statelessstateful không chỉ là kiến thức kiến trúc cho đẹp, mà là thứ giúp bạn tránh rất nhiều bug đau đầu khi hệ thống cần scale thêm instance.

Những chỗ dễ gây lỗi nhất thường là:

  • schedule chạy trùng
  • file lưu local
  • session local
  • data giữ trong variable memory

Muốn scale thêm instance an toàn hơn về sau, nguyên tắc rất quan trọng là:

  • state quan trọng không nên nằm cứng trong app instance

App instance càng stateless bao nhiêu, việc scale ngang càng dễ và ít bất ngờ bấy nhiêu.