Làm sao để thiết kế hệ thống phục vụ hàng triệu người dùng?

Trước đây blog Code Dạo toàn viết về code, hôm nay mình đổi phong cách, viết lên tầm thiết kế hệ thống cho nó máu!

Kì này, chúng ta tìm sẽ thử thiết kế một hệ thống lớn, phục vụ hàng triệu người dùng. Đây là một câu hỏi khá là khó và không có câu trả lời chính xác (Tương tự những câu: vì sao phụ nữ buồn, làm sao để con gái sướng).

Nhân hôm trước, mình có làm bài phỏng vấn tại công ty nọ, có một câu hỏi yêu cầu thiết kế một ứng dụng chat sao cho có thể scale cho hàng triệu người dùng. Trước giờ mình không có kinh nghiệm với cái này, qua quá trình tự tìm hiểu cũng đủ biết sơ sơ để chém gió.

Vì vậy mình chia sẻ cho các bạn, Mọi người cùng đọc và góp ý nhé.

Tại sao thiết kế hệ thống hàng triệu người dùng lại khó?

Thiết kế một hệ thống cho 1, 2 người dùng, chạy trên máy local vô cùng đơn giản. Tuy nhiên, một bài toán dễ đến mấy, khi scope lên đến tầm hàng triệu người dùng cũng sẽ trở thành một bài toán lớn và khó hơn rất nhiều lần.

Tại sao vậy? Lấy ví dụ nhé, một con server cùi có thể chịu được 100 request mỗi giây. Khi lượng request lên đến 10000 thì có thể nâng cấp server xịn hơn. Nhưng khi lượng request lên đến 1-2 triệu thì không thể nâng cấp server được nữa, mà phải thiết kế sao cho nhiều server chạy cùng lúc.

Hoặc đơn thuần như việc sắp xếp dữ liệu, với 1000 entry thì chạy trong nháy mắt, nhưng với chục triệu, trăm triệu entry thì có thể chạy đến hàng tiếng, lúc này ta phải lựa chọn thuật giải tối ưu. Vấn đề này liên quan tới scalability (khả năng mở rộng của hệ thống).

Mặt khác, không phải developer nào cũng có cơ hội để giải quyết bài toán scalability. Với các ứng dụng nhỏ,những dự án outsource, ít người đôi khi chỉ cần dùng một số giải pháp đơn giản là đã giải quyết được.

Ở các công ty lớn như Facebook, Uber, Google, đây là bài toán bắt buốc phải giải. Ở Việt Nam chắc sẽ có một số công ty lớn như Zalo, LoziTiki, Thế Giới Di Động mới cần giải quyết vấn đề scalability này.

Những sản phẩm với lượng người dùng khủng như Tiki, Zalo,… mới cần giải bài toán về scalability

Ba yếu tố quan trọng của một hệ thống

Khi thiết kế một hệ thống phục vụ hàng triệu người dùng, ta cần để ý 3 yếu tố quan trọng nhất: Performance, Availability, và Scalability:
  • Performance:  Tốc độ phản hồi của hệ thống, được đo bằng đơn vị thời gian, có thể là giây hoặc mili giây. Hệ thống hoạt động càng nhanh thì người dùng làm được nhiều việc hơn, đem lại lợi nhuận cao hơn. Hệ thống mà quá chậm thì sẽ không có ai sử dụng.
  • Availability: Chỉ khả năng hoạt động của hệ thống vào mọi thời điểm, được đo bằng uptime. Ví dụ như trong 100 ngày, hệ thống hoạt động 99 ngày còn 1 ngày die thì uptime là 99/100 = 99%.
    • Uptime của các hệ thống lớn như Facebook, Google, Uber phải luôn >99%, vì chỉ cần ngưng hoạt động vài phút là các công ty sẽ thiệt hại từ vài nghìn cho tới vài triệu đô.
    • Hôm trước phỏng vấn ở Agoda, anh Director chia sẻ 1 giây Agoda kiếm được 1000 đô. Bum bum bum 3s là 3000 đô. Do đó hệ thống mà sập cỡ 5-10 phút là thiệt hại sẽ… hơi bị bự.
  • Scalability: Khả năng mở rộng của hệ thống. Liệu khi có đông user hơn thì hệ thống có thể mở rộng (scale) được không? Việc scale có thể thực hiện dễ dàng, nhanh chóng hay không? Chi phí scale như thế nào?
    • Ví dụ lượng người dùng tăng gấp 10, ta chỉ cần tăng gấp 2 hoặc gấp 5 lượng server là phục vụ được, hệ thống có scalability cao. Tuy nhiên, nếu ta phải tăng gấp 100, gấp 200 lượng server, hoặc không thể thêm server để phục vụ chừng đó người dùng, hệ thống có scalability thấp.
Rất khó để đảm bảo 3 yếu tố này! May thay, đây là bài toàn đã được hàng chục công ty lớn giải, do đó chúng ta có một số phương pháp, thiết kế sẵn có để giải quyết vấn đề này!
Các hệ thống của Google, Linkedin, Facebook phải phục vụ hàng trăm triệu người dùng

Các thiết kế thường dùng cho hệ thống lớn

1. Đảm bảo perfomance

  • Cân bằng tải với Load Balancer: Load Balancer là một thiết bị (phần cứng hoặc phần mềm) cho phép cân bằng tải đến nhiều server.
    • Giả sử ta có 1 server có thể phục vụ 1000 người. Để phục vụ 10000 người, ta có thể chạy 10 server. Người dùng sẽ không trực tiếp truy cập tới server, mà chỉ truy cập tới load balancer. LB sẽ điều tiết, cân bằng lượng tải trên 10 server này.
Load balancer để cân bằng tải
  • Phân tán dữ liệu với Content Delivery Network (CDN): CDN là một mạng lưới các server được phân bố trên nhiều khu vực.
    • Giả sử server thiend*a để ở Mĩ, mỗi khi bạn truy cập đến thiend*a, bạn sẽ phải kết nối tới server bên Mĩ, khá là chậm. Với CDN, dữ liệu sẽ được để ở Mĩ, Việt Nam, Lào, Cam.
    • Khi bạn kết nối đến thiend*a, bạn sẽ kết nối tới server gần nhất (Việt Nam), tốc độ sẽ nhanh hơn nhiều. CDN thường chỉ chứa các dữ liệu tĩnh, ít thay đổi như media (video, ảnh, nhạc), file (CSS, JS)
Cách thức hoạt động của CDN
  • Caching: Cache là một kĩ thuật để tăng tốc độ đọc dữ liệu, bằng cách lưu dữ liệu sẵn vào cache server để tăng tốc độ đọc ở những lần sau.
    • Ví dụ mỗi lần gọi API hoặc Database mất 10s, ta chỉ gọi lần đầu và lưu kết quả vào cache. Ở những lần sau, đọc kết quả từ cache chỉ mất 0.5s thôi. Trong series Nhận diện Idol, mình có sử dụng Redis làm Cache Server.

2. Đảm bảo Availability

  • Master/Slave: Thay vì chỉ chạy 1 server, ta chạy 2 hoặc nhiều hơn. 1 server chính gọi là master, các server còn lại là slave. Khi master có vấn đề (sập nguồn hay crash), một slave sẽ được chỉ định để lên thay thế master.
  • Replication: Thường được kết hợp chung với Load Balancer. Code của ứng dụng sẽ được deploy lên nhiều server. Khi có 1 server die, load balancer sẽ chuyển request sang server khác, đảm bảo request vẫn được thực hiện.
Kiến trúc Mát Tơ/Sờ Leo

3. Đảm bảo scalability

  • Vertical Scaling: Tăng sức mạnh phần cứng cho server bằng cách… lắm thêm RAM, lắm thêm chip, thay ổ cứng bằng ổ SSD.
    • Cách này khá nhanh và dễ thực hiện (Nếu dùng AWS hoặc Azure chỉ việc đổi config là xong, 30 giây). Nhược điểm của cách làm này là: phần cứng luôn có một giới hạn, phần cứng càng mạnh thì giá càng… trên trời nên chỉ có thể mở rộng đến một giới hạn nhất định
  • Horizontal Scaling: Thay vì tăng sức mạnh cho 1 server, ta thêm nhiều server vào hệ thống và chạy cùng lúc.
    • Cách này làm cho thiết kế phức tạp hơn, nhưng bù lại ta có thể dùng phần cứng rẻ tiền lắp thêm vào, khả năng mở rộng hầu như không giới hạn (Google File System sử dụng hướng này, data center hàng nghìn con server linux loại rẻ).
Vertical và Horizontal Scaling
  • Với application server (server chứa code): Cần đảm bảo code ở server là stateless (không lưu trạng thái). Ta chỉ cần chạy vài chục đến vài trăm server (server farm), các server này đều ẩn sau load balancer. Load balancer sẽ điều tiết tải lên các server này. Nếu lượng người dùng tăng, chỉ việc thêm server là xong.
  • Với database server: Với database thì mọi chuyện phức tạp hơn nhiều, ta không thể chạy database ở nhiều máy vì dữ liệu có thể sẽ bị bất đồng bộ.
    • Cho các ứng dụng thuần read/ít write (blog, trang tin tức,…) ta có thể dùng thiết kế master/slave : 1 server master để read/write, nhiều server slave chỉ để đọc. Khi người dùng cần đọc thông tin từ database, ta có thể đọc từ master hoặc một trong các slave. Khi cần ghi dữ liệu vào database, ta ghi vào master, sau đó đồng bộ dần qua các slave.
    • Cho các ứng dụng có lượng read/write nhiều như nhau (Agoda, Facebook), ta có thể áp dụng cách sharding. Chia database thành các mẫu shard nhỏ (theo IP, theo địa điểm vật lý của người dùng,…). Các database NoSQL (MongoDB, Cassandra) đều hỗ trợ sharding kiểu này.

Kết

Những kĩ thuật mình nhắc đến trong bài chỉ mang tính chất “cưỡi ngựa xem hoa” (Vậy mà đã gần 2k chữ). Nói thì có vẻ đơn giản, nhưng nếu đi sâu vào một trong các kĩ thuật (load balancer, master/slave, sharding) cũng sẽ mất vài nghìn chữ. Do vậy, mình chỉ liệt kê sơ để bạn đọc có hướng để tìm hiểu thêm.

Mặc dù có thể cả đời bạn không cần dùng đến nhưng kĩ năng này (suốt ngày làm web tin tức, web bán hàng, dự án nội bộ công ty), hãy thử tìm hiểu sâu về chúng nhé! Chúng sẽ tăng cường khả năng tư duy và tầm nhìn hệ thống của bạn lên rất nhiều đấy!

Nếu có hứng thú, các bạn cứ để comment lại, mình sẽ viết nguyên 1 series về vấn đề này sau nhé!

Dưới đây là một số link để tham khảo thêm, bạn nào có tài liệu hay thì cứ share trong mục comment nhé:

 

P/S: Để theo dõi bài viết trên Tôi Đi Code Dạo, nhớ Subscribe Chat Bot của tụi mình nha. Bot của Code Dạo sẽ gửi bạn những bài viết cực kì hay ho về kĩ năng mềm và cứng, kinh nghiệm trong ngành vào thứ 4 hàng tuần nhé!

Đăng ký bài viết

49 thoughts on “Làm sao để thiết kế hệ thống phục vụ hàng triệu người dùng?”

  1. Hi code dạo, bạn có thể viết 1 ebook về vấn đề này được không. Để mọi người nắm rõ hơn.

    Like

  2. Góp ý vài thuật ngữ giang hồ cho scale:
    Vertical Scaling hay còn gọi là Scale up
    Horizontal scaling gọi là Scale out

    Ngoài ra còn có scale down & scale in (nhưng chắc ít ai xài, thường chỉ apply cho những system có cơ chế auto scale)

    Like

  3. 1 giây Agoda kiếm được 1000 đô, vị chi 1 ngày 86400 x 1000 đô = 86 triệu đô. Con số này có ảo quá ko ad. Em thì không tin lắm làm sao mà kiếm được nhiều tiền thế?

    Like

  4. Ở VN rất ít website hứng được >1 triệu request cùng lúc. Vì dù có mở rộng bề ngang (thêm nhiều server) thì chi phí vẫn đắt đỏ. Giả sử scale lên 20 con ở aws thì tiền cũng lên mấy chục ngàn mĩ kim. Thế mà bọn Tây chúng nó tiêu tiền nhìn chóng cả mặt :3

    Like

    1. Thật ra là do requirement nữa bạn. Ko phải hệ thống nào cũng lớn đến mức đấy ;). Mấy app nho nhỏ thì host server cùi, to hơn thì 2,3 con server là đủ xử ròo 😉

      Like

  5. Cảm ơn Hoàng ! Bài viết của bạn rất hữu ích…Vote bạn là Series về chủ đề này.

    Like

  6. Mong anh viết sâu hơn về vấn đề này,có cả những ví dụ trong code thì càng dễ hiểu

    Like

  7. Chủ đề rất hay, cảm ơn bạn đã chia sẻ, cố gắng viết tiếp phần tiếp theo cho anh em đọc nha

    Like

  8. Cách đây hơn 10 năm, Võ Lâm Truyền Kỳ đã chịu được hàng triệu lượt truy cập. Mình rất tò mò cách họ làm?

    Like

    1. VLTK mua source của Tàu Khựa. Gì chứ về thiết kế hệ thống thì VN phải xách dép qua Tàu học dài dài. Dân nó đông nên mấy app, web vừa ra mắt đã có lượng user từ vài trăm nghìn đến vài triệu, scale ko khéo là vỡ mật ngay :3

      Like

  9. Bài viết rất hay, giúp tôi có 1 cái nhìn tổng quan. Nếu Hoàng ra sách thì mình sẽ mua về đọc để có thêm kiến thức.

    Like

  10. Cám ơn anh. Bài viết hay. Có vài bạn muốn ví dụ cụ thể thì chỉ có thể tự học, theo kinh nghiệm của mình thì khi bạn join vào một project lớn bạn mới thấy được những thứ thú vị. Tuy nhiên mình có refer cho ai muốn tìm hiểu đó là Spring Framework, Spring Boot, Spring Cloud Ribbon (load balancer), Cache, Gateway server, Eureka Server…

    Like

  11. Bữa giờ e tò mò : không biết thằng facebook nó lưu tin nhắn trong database như thế nào ta. 1 người có thể nhắn 100-1000 tin nhắn. Khi cả mấy trăm triệu người thì facebook nó query message để hiển thị tin nhắn như thế nào cho nhanh a hè. Vì trước giờ e chỉ thấy tin nhắn thì lưu trong 1 bảng thôi

    Like

  12. Cảm ơn bài viết của bạn, có lẽ đây là bài viết để người code hiểu rõ hơn về hướng đi cho những dự án lớn, rất hay !

    Like

  13. có khi nào con Load Balancer chết không nhỉ hay nó chịu 1 lượng request quá lớn nên không forward lại cho các server khác kịp. Nếu vậy thì có solution nào không nhỉ ?

    Like

  14. So we cannot use memory cache like Guava cache (Java)..for scalability because it is kind of stateful

    Like

      1. vậy để application có thể stateless, data nên ở scope request, còn data với application hay session scope thì minh save ở cache server đúng ko bạn

        Like

  15. Bài rất hay, rất thực tế.
    Bạn thân mình đã và đang sử dụng 2 kỹ thuật là Load Banlancer và (CDN – CloudFront) của AWS. Thấy rất là hữu ích và dễ sử dụng.

    Like

  16. Bài viết từ lâu rồi nhưng đọc thấy hay và tỷ mỉ quá. Rất mang tính ứng dụng thực tế cao. Cảm ơn ad rất nhiều vì đã chia sẻ những kiến thức rất thực tế.

    Like

Leave a comment