"WebSocket 트래픽을 절반으로 줄인 비밀" text img
실시간 최적화의 혁신 전략
디스코드의 기술 페이지를 읽으며 디스코드가 어떻게 WebSocket 트래픽을 거의 절반으로 줄였는지 알아보았습니다. 디스코드가 사용한 스마트한 기법들과 우리가 개발자로서 배울 수 있는 교훈들을 알아봅시다.
📌 문제점
디스코드의 사용자 수가 증가함에 따라 WebSocket 대역폭 사용량도 급증했으며, 이는 특히 모바일 기기나 느린 네트워크를 사용하는 사용자들에게 영향을 미쳤습니다.
주요 병목 지점:
- 높은 대역폭 사용: JSON 데이터 형식이 불필요한 오버헤드 추가
- 중복 데이터 전송: 작은 변경 사항에도 전체 데이터 스냅샷 전송
- 제한된 모바일 성능: 느린 네트워크 환경에서 지연 및 높은 데이터 비용 발생
이러한 문제를 해결하기 위해 디스코드의 엔지니어들은 고품질 사용자 경험을 유지하면서 WebSocket 트래픽을 최적화하는 데 집중했습니다.
🚀 디스코드의 접근 방식
디스코드는 다음과 같은 4가지 전략으로 비효율성을 해결했습니다:
- 이진 데이터 형식으로 전환
- 메시지 압축 구현
- 데이터 동기화 최적화
- 델타 업데이트 활용
각 전략을 자세히 살펴보겠습니다.
1️⃣ 이진 데이터 형식으로 전환
- 문제점: JSON은 사람이 읽기 쉽지만 메시지 크기가 큼
- 해결책: 오버헤드를 줄이기 위해 MessagePack 도입
✅ 왜 MessagePack인가?
Format of MessagePack
- JSON 대비 작은 메시지 크기
- 기존 기술 스택에 손쉬운 통합
- 직렬화/역직렬화 시 성능 저하 최소화
🔧 구현 방법
- 서버: msgpack-lite로 메시지 인코딩
- 클라이언트: MessagePack 호환 라이브러리로 디코딩
📊 결과
- 메시지 크기 35% 감소
- 직렬화/역직렬화 효율성 향상, 지연 시간 거의 없음
2️⃣ 메시지 압축 구현
- 문제점: 반복적인 데이터로 인해 여전히 큰 메시지 존재
- 해결책: per-message Deflate 압축 적용
https://github.com/faye/permessage-deflate-node
GitHub - faye/permessage-deflate-node: Per-message DEFLATE compression extension for WebSocket connections
Per-message DEFLATE compression extension for WebSocket connections - faye/permessage-deflate-node
github.com
✅ 왜 per-message Deflate인가?
- 개별 WebSocket 메시지 압축 가능
- 대부분의 브라우저와 라이브러리에서 지원
📊 결과
- 대역폭 사용량 추가로 25% 감소
- 약간의 CPU 사용 증가, 그러나 대역폭 절감 효과가 더 큼
3️⃣ 데이터 동기화 최적화
- 문제점: 변경되지 않은 데이터까지 전송하여 낭비 발생
- 해결책: 선택적 동기화 전략 적용
- 클라이언트가 로컬 캐시 유지
- 서버는 변경된 데이터만 전송
✍️ 예시
{
"id": "ef23r24grewg",
"name": "Siyeon",
"status": "waiting",
"lastActive": "2024-2-12T05:04:10Z"
}
{
"id": "ef23r24grewg",
"status": "ongoing"
}
📊 결과
- 메시지 빈도 및 크기 감소
- 불필요한 데이터 전송 없이 최신 상태 유지
4️⃣ 델타 업데이트 활용
- 문제점: 선택적 업데이트로도 큰 데이터 구조 존재 (예: 목록)
- 해결책: 델타 업데이트로 이전 상태 대비 변경 사항만 전송
✍️ 예시 (JSON Patch)
- 원본: { "tasks": ["todo", "in-progress", "done"] }
- 업데이트: { "tasks": ["todo", "review", "done", "archived"] }
- 델타:
[
{ "op": "replace", "path": "/tasks/1", "value": "review" },
{ "op": "add", "path": "/tasks/3", "value": "archived" }
]
📊 결과
- 데이터 전송 최소화
- 빠른 클라이언트 업데이트 지원
⚠️ 도전 과제 및 해결 방법
- 복잡성 증가
- 문제: 코드 복잡성 증가
- 해결: 직렬화/역직렬화 로직을 모듈화하여 관리, 철저한 테스트 수행
- 구형 클라이언트 호환성
- 문제: 일부 클라이언트는 새로운 기능 미지원
- 해결: WebSocket 핸드셰이크에서 버전 협상 도입
- 이진 데이터 디버깅 어려움
- 문제: 사람이 읽기 어려움
- 해결: 내부 디버깅 도구 개발, 개발 단계에서는 JSON 사용
🌟 최적화 결과
- WebSocket 트래픽 50% 감소
- 모바일 사용자 경험 개선: 더 빠른 업데이트, 낮은 데이터 사용량
- 비용 절감: 대역폭 비용 및 서버 부하 감소
💡 실시간 애플리케이션을 위한 교훈
- 효율적인 데이터 형식 사용: MessagePack, Protobuf 활용
- 압축의 중요성: 높은 트래픽 환경에서 큰 효과
- 선택적 업데이트: 불필요한 데이터 전송 방지
- 하위 호환성 고려: 모든 프로토콜 변경 시 필수
- 트래픽 분석과 테스트: 병목 지점 식별로 효율성 향상
📢 결론
디스코드의 최적화 사례는 실시간 시스템 개발에 있어 강력한 인사이트를 제공합니다.
"작은 최적화가 모여, 큰 변화를 만듭니다."
여러분이 비슷한 문제에 직면해 있다면, 디스코드의 접근 방식을 참고해 보세요. 작은 개선들이 쌓여 여러분의 애플리케이션을 더 빠르고 효율적으로 성장시킬 수 있습니다.
끝까지 읽어주셔서 감사합니다!