Pro tip: cứ build thôi, đừng chưa gì đã lo scale up khi bạn chưa có user
Sau 6 tháng trời xây dựng hẳn một hệ thống “xịn xò” cho dự án đầu tiên – nào Redis để cache, Kafka cho event handling, replica database các kiểu, load balancers tự động, đủ thứ như chuẩn bị sẵn cho hàng triệu người dùng.
Kết quả? Được… 12 người dùng.
6 tháng tập trung lo hạ tầng mà chẳng có sản phẩm nào ra mắt. Mất 6 tháng trước khi nhận ra rằng thực sự chẳng ai cần cái mình làm! Thật ra đa phần chúng ta đều hay xây dựng cho một quy mô sẽ chẳng bao giờ đến, giải quyết vấn đề mình chưa có, tối ưu hóa cho lượng truy cập mà không tồn tại.
Cái bẫy “Nhỡ đâu viral”
Quyết định kỹ thuật nào nghe cũng bắt đầu bằng “nhỡ đâu cần mở rộng?”
- Nhỡ đâu lên trang nhất Hacker News?
- Nhỡ đâu có 100.000 người dùng đồng thời?
- Nhỡ đâu database chịu không nổi?
Thế là mình làm như mọi lập trình viên hợp lý – chuẩn bị từ trước. Thêm Redis “vì cache phải có”, dựng Kafka “vì tương lai phải hướng sự kiện”, triển khai nhiều vùng “vì người dùng toàn cầu phải nhanh”, thêm Elasticsearch “tìm kiếm phải nhanh”.
Mà chỉ số thực tế thì:
- Người dùng thật mỗi ngày: 3 người (bạn, đồng sáng lập, mẹ bạn)
- Database query mỗi giây: 0.1
- CPU server: 2%
- Tỷ lệ hit cache: 0% (vì chẳng có gì để cache)
Những công ty lớn không cần “sâu siêu”
Để mình chia sẻ vài con số nghe hơi đau một tí:
- WhatsApp có 450 triệu người dùng chỉ với 32 kỹ sư. Không Kafka, không Redis cluster, chỉ Erlang và FreeBSD.
- Basecamp chạy monolith, bao năm doanh thu khủng, server chỉ có vài cái. Không vùng này vùng kia.
- Stack Overflow phục vụ 10 triệu khách mỗi ngày chỉ với 9 web server. Họ còn không dùng CDN nhiều năm!
- SQLite vận hành 35% toàn bộ website. Không phải Postgres, không MySQL, là một database file bé tẹo nhét vừa đĩa mềm.
Họ lớn đấy, nhưng vẫn dùng những công nghệ cực đơn giản mà thiên hạ hay chê “cũ kỹ, không mở rộng được”.
Cái giá thực sự của việc “chuẩn bị cho quy mô”
Nếu bạn xây vì chưa có người dùng, bạn phải trả ba loại giá:
- Tiền: Bạn sẽ chi quá nhiều cho hạ tầng không cần thiết. Coi như bạn chịu được, nhưng chưa phải vấn đề chính.
- Thời gian: Mỗi thứ thêm vào lại tăng độ phức tạp. Đăng ký người dùng đơn giản thành chuỗi quy trình:
- Kiểm tra Redis cache
- Ghi vào database chính
- Replicate sang database phụ
- Gửi sự kiện sang Kafka
- Xử lý ở dịch vụ riêng
- Update search index bên Elasticsearch
- Invalidate cache liên quan
- Sync sang vùng backup
Lẽ ra chỉ cần 1 dòng SQL INSERT thì giờ lại thành bài toán hệ phân tán!
- Cơ hội: Đây mới là thứ đau nhất. Trong khi bạn cắm đầu dựng zone thứ ba trên AWS, đối thủ ra mắt 10 tính năng mới. Bạn debug Kafka bị mất tin nhắn, họ đi gặp khách hàng. Bạn tối ưu Elasticsearch query chạy có hai lần/ngày, họ dùng Postgres full-text search rồi xong!
Khi nào mới “cần mở rộng”?
Một bài test nhanh nè:
- Server response time liên tục trên 500ms
- Database query thực sự bị chậm (có đo đàng hoàng)
- Bạn phải trả hơn 100$/tháng cho một server bị quá tải
- Người dùng thực sự kêu ca hiệu năng kém
Còn lại – “có thể mai sẽ chậm”, “biết đâu viral”, “lời khuyên chuẩn hóa”, “Netflix cũng làm vậy” – đừng thêm phức tạp vào vội!
Kiến trúc thực sự dễ mở rộng
Muốn dễ mở rộng nhất? Dùng kiến trúc đơn giản nhất!
- Một server (Rails, Django, Node gì cũng được)
- Một database (Postgres là đủ)
- Một luồng triển khai (git push là xong)
Vậy là bạn dễ dàng phục vụ cả 10.000 người dùng đầu, thậm chí 100.000 nếu không làm gì quá đặc biệt.
Khi thực sự chạm giới hạn:
- Đo cái thực sự chậm
- Chỉ tối ưu đúng điểm đấy
- Lặp lại khi cần
Thậm chí thêm Redis để cache một chỗ nào đó, thêm replica cho báo cáo khi query bị chậm… nhưng tất cả chỉ khi có vấn đề thực sự.
Thực tế xây thế nào?
Mình xây UserJot thì đi ngược lại hết “chuẩn kỹ sư”: Không Redis, không queue, không database phụ, không CDN toàn cầu, không vùng này vùng kia. Chỉ đúng những gì tối giản nhất:
- TypeScript + Postgres
- Mọi thứ sau Cloudflare
- Một repo, một lần triển khai
Đã đáp ứng tốt:
- Đăng nhập người dùng
- Thanh toán qua Stripe
- Gửi email
- Upload file
- Cập nhật real-time (Postgres LISTEN/NOTIFY)
- Background job (sử dụng Postgres như queue)
- Tìm kiếm full-text và vector (toàn bộ bằng Postgres, không Elasticsearch)
Không Redis, không Kafka, không Elasticsearch. Khi thứ gì đó chậm, đo và tối ưu. Không thêm dịch vụ chỉ vì “có thể cần sau này”.
Sự thật “khó nghe” về quy mô của bạn
Đa số chúng ta sẽ chẳng bao giờ vượt qua giới hạn một server. Ngay cả doanh nghiệp thành công cũng chạy hạ tầng đơn giản đến ngạc nhiên.
Nếu bạn xây SaaS, tầm 1.000 khách trả tiền là đã ok rồi. Server hiện giờ phục vụ khỏe 10.000+ khách.
Bạn tối ưu cho cái vấn đề mà có được nó đã là hạnh phúc!
Làm thế nào để không bị ám ảnh “quy mô”?
Công thức mình học được sau bao lần vấp ngã:
Tuần 1-2: Prototype
- Database: SQLite (đúng vậy, không đùa)
- Framework bạn quen nhất
- Deploy lên nền tảng đơn giản (Railway, Render, gì miễn phí càng tốt)
- Không Redis, không queue
100 người dùng đầu tiên:
- Chuyển sang Postgres nếu cần
- Thêm monitoring sơ sơ (chỉ cần uptime)
- Tập trung sản phẩm hợp người dùng
- Vẫn không Redis, không queue
1.000 người dùng đầu tiên:
- Thêm error tracking
- Có thể thêm Redis đúng chỗ bottleneck (phải đo trước!)
- Nghĩ đến backup
- Vẫn một vùng server là đủ
10.000 người dùng đầu tiên:
- Lúc này mới cần nghĩ đến kiến trúc
- Có doanh thu, trả được cho hạ tầng
- Có pattern sử dụng thực tế để tối ưu
- Có thể cần cache layer
Lời khuyên “bạn cần nghe”
Bạn chưa cần Redis!
Bạn chưa cần Kafka!
Bạn chưa cần Elasticsearch!
Bạn chưa cần database phụ!
Bạn chưa cần multi-region!
Bạn chưa cần CDN khi có 50 khách!
Bạn chưa cần scale ngang!
Bạn chưa cần chia database!
Thứ bạn cần: xây được cái mà người ta thực sự muốn dùng.
Tất cả sự phức tạp bạn thêm vào chẳng phải phòng xa vấn đề tương lai – nó chắc chắn gây ra đủ thứ vấn đề hiện tại.
Một thử thách nhỏ cho bạn
Dự án tới, thử làm theo này nhé:
- Dùng stack “cũ kỹ” nhất bạn biết
- Deploy tất cả lên một server
- Dùng một database cho tất cả
- Chỉ thêm gì đó khi thực sự đụng giới hạn
Bạn sẽ ra mắt nhanh hơn, tiết kiệm tiền và chắc gì đã tới giới hạn!
Càng đơn giản càng dễ mở rộng. Kiến trúc “siêu ổn định” nghe cực cool thực ra lại làm mọi thứ khó mở rộng hơn vì quá nhiều phần phải đồng bộ.
Và nếu bạn cần một công cụ phản hồi để nói chuyện với những người dùng thực sự thay vì lo các vấn đề “quy mô”, mình đang xây UserJot – đơn giản, tối giản, làm đúng chức năng nó cần.
Dừng xây cho quy mô. Hãy xây cho người dùng. Quy mô – để nó tự đến, nếu bạn may mắn!