1 điểm bởi GN⁺ 2024-07-28 | 1 bình luận | Chia sẻ qua WhatsApp

Tích 650.000.000 ô checkbox: ứng phó với mức độ phổ biến ngoài dự kiến

Ngày 26 tháng 6 năm 2024, ra mắt website One Million Checkboxes (OMCB)
  • Một trang web có 1 triệu ô checkbox toàn cục; khi một ô được tích, thay đổi sẽ được phản ánh ngay lập tức cho mọi người dùng
  • Chỉ sau 30 phút kể từ khi ra mắt, hàng nghìn người dùng đã tích hàng triệu ô checkbox
  • Lưu lượng đến từ Hacker News, /r/InternetIsBeautiful, Mastodon, Twitter, v.v.
  • Cũng được giới thiệu trên Washington Post và New York Times
  • Trong ngày đầu tiên, hơn 50 triệu ô checkbox đã được tích
  • Trước khi đóng site sau 2 tuần, đã có hơn 650 triệu lượt tích ô checkbox

Kiến trúc ban đầu

  • Trạng thái checkbox được lưu dưới dạng 1 triệu bit (125KB)
  • Client dùng bitset để render checkbox và báo trạng thái tích lên server
  • Server dùng Redis để cập nhật bit và broadcast tới mọi client
  • Phục vụ nội dung tĩnh qua nginx, còn server Flask xử lý trạng thái bitset và kết nối WebSocket
  • Redis đóng vai trò vừa lưu trạng thái vừa là hàng đợi thông điệp

Nguyên tắc mở rộng

  • Giới hạn chi phí: tính toán chi phí bằng công thức để có thể mở rộng theo kiểu serverless mà không bị phá sản
  • Chấp nhận giải pháp ngắn hạn: giả định độ phổ biến của site chỉ là tạm thời và chọn giải pháp nhanh
  • Dùng công nghệ đơn giản, tự host: chỉ bổ sung những công nghệ có thể tự vận hành và debug trực tiếp
  • Ưu tiên niềm vui: đặt sự thú vị lên trên tiền bạc
  • Duy trì tính toàn cục: giữ trạng thái toàn cục để mọi người dùng có thể thấy thay đổi ngay lập tức

Ngày đầu tiên: bùng nổ mức độ phổ biến

  • Tải server tăng vọt chỉ sau 30 phút
  • Spin up thêm server để phân tán tải
  • Áp dụng cập nhật theo lô để giải quyết vấn đề kết nối Redis
  • Nâng cấp instance Redis managed của Digital Ocean

Không có kế hoạch cho cả đêm

  • Lập kế hoạch để trưng bày trò chơi Pacman nhận diện khuôn mặt tại trại ITP
  • Mang theo iPad để spin up server
  • Vừa phát triển quy tắc đặt tên server vừa vận hành 8 worker VM
  • Giảm số tiến trình Flask và tăng kích thước batch cập nhật để giảm tải

Vấn đề băng thông

  • Ban đầu không tính đến giá băng thông của Digital Ocean
  • Giảm tần suất chụp snapshot trạng thái và giảm kích thước cập nhật
  • Dùng tiện ích tc để giới hạn lượng dữ liệu truyền mỗi giây

Ngày thứ hai: tiếp tục tăng trưởng

  • Site bị sập do không kiểm tra hợp lệ đầu vào đúng cách
  • Thêm bản sao Redis để phân tán tải
  • Các tiến trình Flask tiếp tục crash nên đã viết script tự khởi động lại

Vấn đề cập nhật cũ

  • Phát sinh vấn đề client áp dụng các cập nhật cũ khiến trạng thái hiển thị bị sai
  • Thêm timestamp để bảo đảm thứ tự cập nhật

Viết lại bằng Go

  • Cùng một người bạn là kỹ sư hiệu năng viết lại backend bằng Go
  • Hiệu năng được cải thiện đáng kể
  • Chống đỡ tấn công DDOS thông qua CloudFlare

Đóng site

  • Thay đổi để các checkbox sẽ bị đóng băng nếu không được bỏ tích đủ nhanh
  • Dùng Redis để quản lý trạng thái đóng băng
  • Đóng site sau 2 tuần

Điều rút ra

  • Đây là lần thứ hai triển khai một server có backend “thực sự” lên Internet công cộng
  • Việc chọn các giải pháp ngắn hạn là một quyết định đúng đắn
  • Một lần nữa khẳng định sức mạnh của Redis và nginx
  • Xác nhận rằng mọi người rất khao khát những website nơi họ có thể tương tác ẩn danh

Tóm tắt của GN⁺

  • Bài viết này nói về các vấn đề kỹ thuật phát sinh do website bất ngờ trở nên cực kỳ phổ biến và quá trình giải quyết chúng
  • Cho thấy ngay cả với một kiến trúc đơn giản dùng Redis và nginx vẫn có thể xử lý lưu lượng rất lớn
  • Giải thích cách nhanh chóng xử lý sự cố và ổn định site bằng các giải pháp ngắn hạn
  • Đề cập đến nhiều thách thức kỹ thuật như viết lại bằng Go và phòng thủ DDOS qua CloudFlare
  • Một dự án có chức năng tương tự là các dự án cộng tác quy mô lớn như /r/Place của Reddit

1 bình luận

 
GN⁺ 2024-07-28
Ý kiến trên Hacker News
  • Có thể học được nhiều bài học và kiến thức lịch sử

    • Đã xử lý đủ mọi kiểu gián đoạn và điểm thất bại, nhưng không thấy nhắc đến vấn đề dung lượng lưu trữ
    • Trước đây không biết Redis có thể dùng Lua, và điều đó khiến tôi hứng thú với việc dùng nó như trạng thái thay thế
    • Vấn đề băng thông của dịch vụ đám mây là một trong những điều gây khó chịu nhất, vì không có giới hạn cứng để tránh vượt mức tính phí
  • Bài viết rất tuyệt! Chúc mừng cả website nữa, nhưng bản thân bài viết mới là phần đáng tự hào nhất

  • Việc xây dựng trang chỉ trong hai ngày là một lựa chọn đúng đắn

    • Đây là bài học quan trọng mà các kỹ sư ở giai đoạn đầu sự nghiệp nên học
    • Vấn đề mở rộng quy mô không phải là vấn đề cho đến khi nó thực sự trở thành vấn đề
    • Đến lúc đó thì đó là một vấn đề tốt, và không khó giải quyết như người ta nghĩ
  • Dự án liên quan gần đây:

    • "One Million Checkboxes" - liên kết - tháng 6 năm 2024 (305 bình luận)
  • Dự án thú vị

    • 6 năm trước tôi đã phát hành một ứng dụng chỉnh sửa pixel cộng tác tên là Pixmap trên Android
    • Tôi dùng hàng đợi để áp dụng từng sự kiện vào ảnh PNG, và client sẽ tải PNG ban đầu khi kết nối
    • Mỗi sự kiện vẽ pixel được gửi tới client dưới dạng một đối tượng nhỏ
    • Lần tải ban đầu tận dụng nén ảnh, còn tập thay đổi thì rất nhỏ
    • Vì mỗi sự kiện được lưu trong log, có thể "tua ngược" hình ảnh
    • Liên kết demo
  • Bài viết rất hay - tôi tò mò không biết chi phí là bao nhiêu

  • Điều này củng cố niềm tin rằng con người khao khát những tương tác ẩn danh có giới hạn

  • Với tư cách là người mới học backend, tôi tự hỏi liệu có một kiến trúc thay thế đơn giản hơn cho dự án này không

    • Hy vọng có một cách dễ hơn để lưu trữ một triệu trạng thái và đồng bộ với client
    • Một số giải pháp trong bài hơi khó hiểu với tôi
    • Gửi lời khen tới tác giả - dự án rất tuyệt
  • Hay đấy!

    • Tò mò không biết bài tiếp theo có phải sẽ là phân tích thống kê về các checkbox không
    • Tôi nhớ mình đã buồn khi checkbox mình chọn gần như bị bỏ chọn ngay lập tức
  • Tôi tự hỏi liệu trò này còn đang chạy hay không

    • Khi truy cập One Million Checkboxes, không có ô nào được chọn và trong JS console chỉ hiện thông báo sau
    • {"total":0,"totalGold":0,"totalRed":0,"totalGreen":0,"totalPurple":0,"totalOrange":0,"recentlyChecked":false}