작년에, 저는 거래 플랫폼을 위한 실시간 모니터링 대시보드 구축 프로젝트를 주도했습니다. 요구사항: 사용자 화면에 100밀리초 미만의 지연 시간으로 초당 100만 이벤트로 업데이트되는 시장 데이터를 시각화.
이것은 우리가 데이터 시각화에 대해 알고 있다고 생각했던 모든 것을 깨뜨렸습니다.
실시간의 현실
아무도 말해주지 않는 사실: "실시간"은 보통 실시간이 아닙니다. 그리고 그것은 종종 괜찮습니다.
"실시간"으로 표시된 대부분의 대시보드는 실제로 5-30초마다 새로고침됩니다. 대부분의 사용 사례에서는 이것이 완벽히 적절합니다. 하지만 실제로 1초 미만 업데이트가 필요할 때는 규칙이 완전히 바뀝니다.
"실시간"의 세 가지 계층
계층 1: 준실시간 (5-60초 새로고침)
사용 사례: 비즈니스 대시보드, 마케팅 분석, 영업 지표
아키텍처: API 엔드포인트 폴링, 배치 집계
복잡성: 중간
이것이 대부분의 사람들이 필요한 것입니다. 데이터 팀이 매분 데이터를 집계하고, 대시보드가 업데이트를 폴링합니다. 간단하고 효과적입니다.
계층 2: 실시간 (1-5초 새로고침)
사용 사례: 운영 모니터링, 라이브 이벤트 추적, 고객 지원 대기열
아키텍처: WebSockets, 서버 전송 이벤트, 스트리밍 쿼리
복잡성: 높음
폴링에서 푸시로의 전환은 모든 것을 바꿉니다. 이제 지속적인 연결 유지, 재연결 로직 처리, 클라이언트/서버 간 상태 관리가 필요합니다.
계층 3: 1초 미만 (1초 미만)
사용 사례: 거래 플랫폼, 라이브 게임 통계, 산업 모니터링
아키텍처: 스트리밍 파이프라인, 특수 데이터베이스, 최적화된 렌더링
복잡성: 매우 높음
이것이 우리가 8개월 동안 머물렀던 곳입니다. 모든 최적화가 중요합니다. 모든 밀리초가 중요합니다.
실시간 시각화가 어려운 이유
문제 1: 데이터 볼륨
초당 100만 이벤트에서, 각 이벤트를 렌더링할 수 없습니다. 그것은 매초 백만 개의 포인트입니다. 브라우저가 폭발할 것입니다.
해결책: 사전 집계. 원시 이벤트를 프론트엔드로 보내지 마세요. 소스에서 집계하세요 — 시간 버킷당 평균, 개수, 백분위수. 우리는 백만 개의 원시 이벤트 대신 초당 10개의 집계 업데이트를 전송했습니다.
문제 2: 렌더링 성능
초당 10개의 업데이트라도, 전체 차트를 다시 렌더링하면 성능이 죽습니다. React의 조정, SVG 조작, 캔버스 다시 그리기 — 모두 합산됩니다.
해결책: 증분 업데이트. 차트를 다시 구축하지 말고 추가하세요. 우리는 가장 높은 빈도의 차트에 WebGL 기반 렌더링을 사용했는데, 이는 60fps 업데이트를 부드럽게 처리할 수 있습니다.
문제 3: 인간의 지각
직관에 반하는 발견입니다: 약 200밀리초보다 빠른 업데이트는 흐릿해집니다. 사용자는 초당 10프레임 이상으로 정보를 처리할 수 없습니다. 그들은 그저 깜빡임을 볼 뿐입니다.
해결책: 시각적 부드러움. 데이터가 10Hz로 업데이트될 때조차도, 우리는 200밀리초에 걸쳐 전환을 애니메이션화했습니다. 차트는 혼란스럽지 않으면서 "라이브" 느낌을 주었습니다.
문제 4: 네트워크 변동성
WebSocket 연결이 끊어집니다. 패킷이 지연됩니다. 모바일 사용자가 네트워크를 전환합니다.
해결책: 강력한 재연결, 메시지 큐잉, 우아한 성능 저하. 연결이 끊어지면 마지막으로 알려진 상태를 "재연결 중" 표시와 함께 보여주세요 — 빈 화면을 보여주지 마세요.
효과를 발휘한 아키텍처
다음은 우리의 초당 백만 이벤트 요구사항을 처리한 스택입니다:
데이터 계층
- 이벤트 수집을 위한 Apache Kafka
- 실시간 집계를 위한 Apache Flink
- 최신 상태 캐싱을 위한 Redis
- 히스토리 쿼리를 위한 TimescaleDB
API 계층
- WebSocket 서버용 Go (동시 연결 효율적 처리)
- 내부 서비스 통신용 gRPC
- 메시지 일괄 처리 (모든 이벤트가 아닌 100밀리초마다 업데이트 전송)
프론트엔드
- UI 구조용 React
- 고빈도 차트용 WebGL (regl 통해)
- 중간 빈도 차트용 경량 캔버스
- 낮은 빈도, 상호작용이 많은 차트용 SVG (D3 통해)
핵심 결정 사항
- 가능한 한 빨리 집계: 프론트엔드는 원시 이벤트가 아닌 표시 준비가 된 데이터를 수신해야 합니다.
- 업데이트 빈도 분리: 모든 요소가 10fps를 필요로 하지 않습니다. 정적 컨텍스트는 30초마다 업데이트할 수 있습니다.
- 사용자 제어 상세 수준: 사용자가 "개요" (느린 업데이트, 더 많은 데이터)와 "세부" (빠른 업데이트, 집중된 보기) 사이에서 선택할 수 있게 하세요.
성능 최적화
서버에서
- 시간 버킷 사전 계산: 클라이언트가 "지난 5분"을 계산하지 않게 하기
- 델타 인코딩: 전체 상태가 아닌 변경된 부분만 전송
- 압축: WebSocket 메시지 gzip 압축 (놀랍도록 효과적)
- 연결 풀링: 구독 간 연결 재사용
클라이언트에서
- 객체 풀링: 가비지 컬렉션 대신 차트 요소 재사용
- RequestAnimationFrame 일괄 처리: 브라우저 렌더링 주기와 업데이트 동기화
- 캔버스 레이어링: 정적 요소는 하나의 캔버스, 동적 요소는 다른 캔버스
- Web Workers: 메인 스레드 외부에서 들어오는 데이터 파싱
효과가 없었던 것
- 고빈도 업데이트용 SVG (DOM 조작이 너무 느림)
- 실시간 상태용 Redux (빈번한 업데이트에 지나치게 오버헤드)
- 5fps 이상을 위한 기성 차트 라이브러리 (이 사용 사례에 최적화되지 않음)
실시간에서 얻은 UX 교훈
교훈 1: 사용자에게 제어권 주기
모든 사람이 라이브 업데이트를 원하는 것은 아닙니다. 일부 사용자는 산만하게 느낍니다. 우리는 다음을 추가했습니다:
- 일시정지 버튼: 현재 보기 "고정"
- 업데이트 빈도 선택기: 1초, 5초, 30초
- 히스토리 모드: "5분 전에 일어난 일 보여주세요"
교훈 2: 상태를 명확히 하기
사용자는 다음을 알아야 합니다:
- 이것이 라이브인가 역사적인가?
- 마지막 업데이트는 언제였나?
- 연결 상태가 건강한가?
우리는 각 업데이트마다 맥박을 뛰는 지속적인 "하트비트" 표시기를 추가했습니다. 놀랍게도 안심시켜 줍니다.
교훈 3: 지루한 상태 처리하기
대부분의 시간에는 흥미로운 일이 일어나지 않습니다. 차트는 그저... 비슷한 값으로 업데이트됩니다.
여기서 주석이 도움이 됩니다: "14:32에 급증 감지됨"은 의미 있는 변화에 주의를 끕니다. 이것 없이는 사용자들은 잡음을 응시하게 됩니다.
교훈 4: 모바일은 다르다
더 작은 화면, 더 나쁜 연결, 배터리 제약. 모바일용:
- 자동으로 업데이트 빈도 줄이기
- 시각화 단순화
- 적극적인 재연결 로직 추가
실시간이 가치 없을 때
이 시스템을 구축한 후, 저는 실시간 요구사항에 대해 더 회의적입니다. 물어보세요:
- 더 빠른 업데이트가 사용자 행동을 바꿀 것인가?
- 사용자들이 실제로 그렇게 빠른 정보에 따라 행동할 수 있는가?
- 엔지니어링 비용이 정당화되는가?
대부분의 대시보드에 대한 답은 아니오입니다. 15초 새로고침도 괜찮습니다. 초가 실제로 중요한 경우에 실시간을 사용하세요.
도구와 리소스
계층 1-2 (준실시간 및 실시간)용:
ChartGen과 같은 현대적 도구는 API를 효과적으로 폴링하는 차트를 생성할 수 있습니다. WebSocket 엔드포인트와 결합하면 맞춤형 인프라 없이도 견고한 실시간 대시보드를 구축할 수 있습니다.
계층 3 (1초 미만)용:
특수 도구가 필요합니다: 캔버스와 D3, 맞춤형 WebGL 렌더링, 또는 uPlot이나 증분 업데이트 모드의 Apache ECharts와 같은 목적에 맞게 구축된 라이브러리.
스트리밍 인프라용:
- Apache Kafka + Flink (복잡하지만 강력함)
- AWS Kinesis + Lambda (관리형이지만 제한적)
- Redis Streams + 맞춤형 집계 (더 간단하지만 확장성 낮음)
실시간 시스템 모니터링
우리가 측정한 것:
- 종단 간 지연 시간 (이벤트 타임스탬프에서 화면 픽셀까지)
- 연결 상태 (시간당 재연결 횟수)
- 렌더링 성능 (초당 프레임 수)
- 사용자 참여 (사람들이 실제로 실시간 보기를 보는가?)
놀라운 발견: 많은 사용자가 대시보드를 열고, 2분 동안 보고, 배경 탭에 그대로 두었습니다. "라이브" 데이터는 대부분 보이지 않았습니다.
마지막 생각
실시간 시각화는 엔지니어링 도전이지만, 또한 UX 도전이기도 합니다. 가장 어려운 부분은 데이터를 화면에 빠르게 가져오는 것이 아닙니다 — 그것을 인간이 실제로 이해하고 행동할 수 있는 방식으로 제시하는 것입니다.
실시간을 구축하기 전에 물어보세요: 더 빠른 데이터로 사용자들이 실제로 무엇을 다르게 할 것인가?
답변이 명확하지 않다면, 아마도 실시간이 전혀 필요하지 않을 수 있습니다.


