GN⁺: 과소평가된 Server-Sent Events (SSE) 기술
(igorstechnoclub.com)서버 전송 이벤트(Server-Sent Events, SSE)는 과소평가됨
- 대부분의 개발자는 WebSockets에 대해 알고 있지만, SSE는 더 간단하고 종종 간과되는 대안임.
- SSE는 서버에서 클라이언트로의 일방향 통신 채널을 HTTP를 통해 설정함.
- WebSockets의 양방향 연결과 달리, SSE는 서버에서 클라이언트로의 업데이트를 위한 열린 HTTP 연결을 유지함.
SSE가 과소평가되는 이유
- WebSocket의 인기: WebSockets의 전이중 통신 기능이 SSE의 간단한 접근 방식을 가림.
- 제한 사항에 대한 인식: 일방향 특성이 제한적으로 보일 수 있지만, 많은 사용 사례에 충분함.
SSE의 주요 강점
-
구현의 간단함
- 표준 HTTP 프로토콜을 활용하여 WebSocket 연결 관리의 복잡성을 제거함.
-
인프라 호환성
- 기존 HTTP 인프라와 원활하게 작동함:
- 로드 밸런서
- 프록시
- 방화벽
- 표준 HTTP 서버
- 기존 HTTP 인프라와 원활하게 작동함:
-
자원 효율성
- WebSockets에 비해 낮은 자원 소비:
- 일방향 특성
- 표준 HTTP 연결 사용
- 지속적인 소켓 유지 관리 불필요
- WebSockets에 비해 낮은 자원 소비:
-
자동 재연결
- 브라우저의 내장 지원:
- 연결 중단 처리
- 자동 재연결 시도
- 탄력적인 실시간 경험
- 브라우저의 내장 지원:
-
명확한 의미론
- 일방향 통신 패턴이 다음을 보장함:
- 명확한 관심사 분리
- 직관적인 데이터 흐름
- 단순화된 애플리케이션 로직
- 일방향 통신 패턴이 다음을 보장함:
실용적인 응용
- 실시간 뉴스 피드 및 소셜 업데이트
- 주식 시세 및 금융 데이터
- 진행 바 및 작업 모니터링
- 서버 로그 스트리밍
- 협업 편집(업데이트용)
- 게임 리더보드
- 위치 추적 시스템
구현 예시
서버 측 (Flask)
-
/stream
경로가 SSE 연결을 처리함. -
generate_random_data()
가 포맷된 이벤트를 지속적으로 생성함. -
text/event-stream
MIME 타입이 SSE 프로토콜을 신호함. -
stream_with_context
가 Flask 애플리케이션 컨텍스트를 유지함.
클라이언트 측 (JavaScript)
-
EventSource
객체가 SSE 연결을 관리함. -
onmessage
핸들러가 수신된 이벤트를 처리함. -
onerror
가 연결 문제를 처리함. - 브라우저가 자동 재연결을 처리함.
제한 사항 및 고려사항
-
일방향 통신
- 서버에서 클라이언트로만 가능
- 클라이언트에서 서버로의 통신은 별도의 HTTP 요청 필요
-
브라우저 지원
- 최신 브라우저에서 잘 지원됨
- 구형 브라우저에서는 폴리필 필요할 수 있음
-
데이터 형식
- 주로 텍스트 기반 데이터 지원
- 바이너리 데이터는 인코딩 필요 (예: Base64)
모범 사례
-
오류 처리
-
eventSource.onerror
로 연결 오류를 처리함.
-
-
연결 관리
- 완료 시 연결을 정리함.
-
재연결 전략
- 최대 재시도 횟수를 설정하고 재연결 로직을 구현함.
실제 예시: ChatGPT의 구현
- 현대 언어 학습 모델(LLM)은 SSE를 사용하여 스트리밍 응답을 제공함.
- 주요 패턴:
-
content-type: text/event-stream
헤더 반환 -
\r\n\r\n
로 구분된 데이터 블록 스트리밍
-
결론
- SSE는 실시간 서버-클라이언트 통신을 위한 우아한 솔루션을 제공함.
- 간단함, 효율성, 기존 인프라와의 통합이 많은 애플리케이션에 적합한 선택임.
- WebSockets는 양방향 통신에 여전히 유용하지만, SSE는 일방향 데이터 스트리밍 시나리오에 더 집중되고 적절한 솔루션을 제공함.
SSE 는 보안장비(웹방화벽이나 지능형 보안) 막히지는 않는데 개행 문자 단위로 스트리밍은 안되는 경우를 자주 만납니다. (온프레미스) 중간에서 응답을 다 받았다가 한 방에 보내주는 식으로요.
Hacker News 의견
-
Mercure는 SSE 기반의 오픈 프로토콜로, WebSockets 기반 솔루션의 대체물로 사용됨. Mercure는 클라이언트와의 지속적인 SSE 연결을 유지하는 독립적인 허브를 중심으로 작동하며, 서버 앱과 클라이언트가 사용할 수 있는 간단한 HTTP API를 제공함. Mercure는 JWT 기반의 인증 메커니즘, 여러 주제에 대한 단일 연결 구독, 이벤트 기록, 네트워크 문제 발생 시 자동 상태 조정 등의 기능을 추가함
-
SSE의 큰 단점은 HTTP/2가 아닌 경우 최대 연결 수 제한이 있다는 점임. 이는 브라우저당 제한이 낮아 여러 탭을 열 때 문제가 될 수 있음
-
Doppler의 CLI에서 SSE를 사용하여 자동 재시작 기능을 구현했음. SSE를 통해 서버에서 이벤트를 수신하고 최신 비밀 정보를 가져와 애플리케이션 프로세스에 주입함. WebSockets 대신 SSE를 선택한 이유는 Golang 애플리케이션에 추가 종속성을 가져오지 않기 위함임. HTTP 타임아웃 문제를 해결하기 위해 간헐적인 "ping" 이벤트를 전송해야 했음
-
SSE의 단방향 특성은 제한적으로 보일 수 있지만 많은 경우에 충분함. SSE의 주요 제한 사항은 텍스트 전용이라는 점과 HTTP/1.1에서의 브라우저 연결 제한임. HTTP/2 이상을 사용하면 연결 제한은 문제가 되지 않음. 성능이 중요한 경우 fetch와 ReadableStream을 사용하여 더 유연하고 오버헤드가 적은 솔루션을 선택할 수 있음
-
SSE의 단순성 때문에 많은 개발자가 적절한 구현을 사용하지 않고 데이터 청크를 정규 표현식으로 파싱하는 경우가 많음. 이는 SSE가 스트림에서 주석을 지원하기 때문에 문제가 될 수 있음
-
Data-star.dev는 SSE를 통해 하이퍼미디어 응답을 스트리밍하는 데 중점을 둔 프론트엔드 라이브러리임. Go와 NATS를 백엔드 기술로 사용하여 개발되었으며, 모든 SSE 구현과 호환됨
-
SSE는 과소평가되지 않음. 실제로 Open AI에서 스트리밍 완료에 사용되고 있음. ReactJS 코드베이스에서 SSE를 구현하는 것은 어려웠으며, 당시 Axios가 이를 지원하지 않아 네이티브 fetch를 사용해야 했음
-
웹 프로젝트에서 SSE를 구현했을 때, 6개 이상의 탭을 열면 웹사이트가 작동을 멈췄음. Firefox는 SSE 연결을 6개의 호스트 최대 연결 제한에 포함시키며, 이로 인해 추가 요청이 차단됨
-
SSE는 잘 작동할 때 과소평가됨. 현재 작업 중인 프로젝트에서 인증 문제와 터널의 keep-alive 문제로 인해 어려움을 겪고 있음. 이는 프로토콜의 문제가 아니며, 해결책을 찾는 것이 어려움