GN⁺: 650만 체크로 확장하는 One Million Checkboxes 기술
(eieio.games)650,000,000 체크박스 체크하기: 예상치 못한 인기 대처하기
2024년 6월 26일, One Million Checkboxes (OMCB) 웹사이트를 출시함
- 100만 개의 글로벌 체크박스를 가진 사이트로, 체크박스를 체크하면 모든 사용자에게 즉시 반영됨
- 출시 후 30분 만에 수천 명의 사용자가 수백만 개의 체크박스를 체크함
- Hacker News, /r/InternetIsBeautiful, Mastodon, Twitter 등에서 유입됨
- Washington Post와 New York Times에도 소개됨
- 첫날 5천만 개 이상의 체크박스가 체크됨
- 2주 후 사이트를 종료하기 전까지 6억 5천만 개 이상의 체크박스가 체크됨
원래 아키텍처
- 체크박스 상태는 100만 비트(125KB)로 저장됨
- 클라이언트는 비트셋을 사용하여 체크박스를 렌더링하고 서버에 체크 상태를 알림
- 서버는 Redis를 사용하여 비트를 업데이트하고 모든 클라이언트에 브로드캐스트함
- nginx를 통해 정적 콘텐츠를 제공하고, Flask 서버를 통해 비트셋 상태와 웹소켓 연결을 처리함
- Redis는 상태 저장 및 메시지 큐 역할을 함
확장 원칙
- 비용 제한: 서버리스로 확장하여 파산하지 않도록 비용을 수학적으로 계산함
- 단기적 해결책 수용: 사이트의 인기가 일시적일 것으로 가정하고, 빠른 해결책을 선택함
- 간단하고 자체 호스팅된 기술 사용: 직접 서버를 운영하고 디버깅할 수 있는 기술만 추가함
- 재미 추구: 돈보다는 재미를 우선시함
- 글로벌 유지: 모든 사용자가 즉시 변화를 볼 수 있도록 글로벌 상태를 유지함
첫날: 폭발적인 인기
- 30분 만에 서버 부하가 급증함
- 추가 서버를 스핀업하여 부하를 분산시킴
- Redis 연결 문제 해결을 위해 배치 업데이트를 도입함
- Digital Ocean의 관리형 Redis 인스턴스를 업그레이드함
밤새 계획이 없었음
- ITP 캠프에서 얼굴 인식 Pacman 게임을 전시하기 위해 계획을 세움
- iPad를 가져가서 서버를 스핀업함
- 서버 네이밍 규칙을 발전시키며 8개의 워커 VM을 운영함
- 플라스크 프로세스 수를 줄이고 업데이트 배치 크기를 늘려 부하를 줄임
대역폭 문제
- Digital Ocean의 대역폭 가격을 고려하지 않음
- 상태 스냅샷 빈도를 줄이고, 업데이트 크기를 줄임
-
tc
유틸리티를 사용하여 초당 전송 데이터 양을 제한함
둘째 날: 계속 성장함
- 입력 유효성 검사를 제대로 하지 않아 사이트가 다운됨
- Redis 복제본을 추가하여 부하를 분산시킴
- 플라스크 프로세스가 계속 충돌하여 자동 재시작 스크립트를 작성함
오래된 업데이트 문제
- 클라이언트가 오래된 업데이트를 적용하여 상태가 잘못 표시되는 문제 발생
- 타임스탬프를 추가하여 업데이트 순서를 보장함
Go로 재작성
- 성능 엔지니어 친구와 함께 백엔드를 Go로 재작성함
- 성능이 크게 향상됨
- DDOS 공격을 CloudFlare를 통해 방어함
사이트 종료
- 체크박스가 빠르게 체크 해제되지 않으면 동결되도록 변경함
- Redis를 사용하여 동결 상태를 관리함
- 2주 후 사이트를 종료함
배운 점
- 두 번째로 '실제' 백엔드를 가진 서버를 공개 인터넷에 배포한 경험
- 단기적인 해결책을 선택한 것이 좋은 선택이었음
- Redis와 nginx의 강력함을 다시 확인함
- 사람들이 익명으로 상호작용하는 사이트에 대한 갈망을 확인함
GN⁺의 정리
- 이 글은 웹사이트의 예상치 못한 인기로 인해 발생한 기술적 문제와 해결 과정을 다룸
- Redis와 nginx를 사용한 간단한 아키텍처로도 대규모 트래픽을 처리할 수 있음을 보여줌
- 단기적인 해결책을 통해 빠르게 문제를 해결하고 사이트를 안정화하는 방법을 설명함
- Go로의 재작성과 CloudFlare를 통한 DDOS 방어 등 다양한 기술적 도전을 다룸
- 비슷한 기능을 가진 프로젝트로는 Reddit의 /r/Place와 같은 대규모 협업 프로젝트가 있음
Hacker News 의견
-
많은 교훈과 역사적 지식을 배울 수 있었음
- 모든 종류의 중단과 실패 지점을 다루었지만, 저장 공간 문제는 언급되지 않음
- Redis가 Lua를 사용할 수 있다는 것을 몰랐으며, 이를 대체 상태로 사용하는 것에 관심이 생김
- 클라우드 서비스의 대역폭 문제는 청구 초과를 피할 수 있는 하드 리미트가 없다는 점에서 가장 큰 불만 중 하나임
-
훌륭한 글이었음! 웹사이트도 축하하지만, 글 자체가 가장 자랑스러워해야 할 부분임
-
두 날 만에 사이트를 구축한 것은 좋은 선택이었음
- 초기 경력 엔지니어들이 배워야 할 중요한 교훈임
- 스케일링 문제는 실제로 문제가 될 때까지는 문제가 아님
- 그 시점에서 좋은 문제이며, 생각보다 해결하기 어렵지 않음
-
최근 관련된 프로젝트:
- "One Million Checkboxes" - 링크 - 2024년 6월 (305개의 댓글)
-
재미있는 프로젝트임
- 6년 전 안드로이드에서 Pixmap이라는 협업 픽셀 편집 앱을 출시했음
- 큐를 사용하여 각 이벤트를 PNG 이미지에 적용하고, 클라이언트는 연결 시 초기 PNG를 로드함
- 각 픽셀 드로우 이벤트는 클라이언트에 작은 객체로 전송됨
- 초기 로드 시 이미지 압축을 활용하고, 변경 세트는 매우 작음
- 각 이벤트가 로그에 저장되므로 이미지를 "되감기"할 수 있음
- 데모 링크
-
훌륭한 글이었음 - 비용이 얼마나 들었는지 궁금함
-
사람들은 제한된 익명 상호작용을 갈망한다는 믿음이 확인되었음
-
백엔드 초보자로서 이 프로젝트에 대한 간단한 대체 아키텍처가 있는지 궁금함
- 백만 개의 상태를 호스팅하고 클라이언트와 동기화하는 더 쉬운 방법이 있기를 바람
- 글의 일부 솔루션이 이해하기 어려웠음
- 작성자에게 찬사를 보냄 - 프로젝트가 훌륭함
-
멋짐!
- 다음 글은 체크박스의 통계 분석이 될 것인지 궁금함
- 내가 선택한 체크박스가 거의 즉시 해제되어 슬펐던 기억이 있음
-
게임이 아직도 라이브인지 궁금함
- One Million Checkboxes에 접속했을 때 아무 것도 체크되지 않았고, JS 콘솔에 다음과 같은 메시지만 보였음
- {"total":0,"totalGold":0,"totalRed":0,"totalGreen":0,"totalPurple":0,"totalOrange":0,"recentlyChecked":false}