Skip to content
isdnetworks
Go back

SSE 프록시와 WebSocket 프록시의 차이

(수정됨)

한 서비스의 text/event-stream 연결이 주기적으로 끊긴다는 문제가 있었다. 연결이 안 되는 것이 아니라 되다가 몇 분 뒤에 끊기는 형태였다.

Table of contents

Open Table of contents

배경 — 잘 되는 설정과의 비교

같은 nginx 에 여러 서브도메인이 물려 있는데 다른 것들은 안 끊겼다. 같은 서버와 같은 프록시와 같은 앞단 배포망을 쓰므로 설정만 다른 상태였다.

두 server 블록을 나란히 놓으니 네 항목이 갈렸다. proxy_read_timeout 과 proxy_buffering 과 proxy_cache 와 Connection 헤더였다.

원인 — 다른 프로토콜용 설정

문제가 있는 쪽은 Connection 헤더에 upgrade 를 넣고 있었는데 그것은 WebSocket 핸드셰이크용이다. 이 서비스는 일반 HTTP 연결을 열어 두고 서버가 계속 보내는 방식이라 프로토콜이 달랐다.

스트리밍이니까 WebSocket 설정을 쓰면 되겠거니 하고 복사한 것으로 보인다. 프로토콜이 다르면 필요한 설정도 다르므로 복사가 성립하지 않는다.

조치 — 네 항목이 각각 필요한 이유

proxy_read_timeout 은 nginx 공식 문서대로 기본 60초이고 두 읽기 사이의 간격에 걸리므로 이벤트가 뜸하면 끊긴다. 그래서 길게 잡아야 한다. proxy_buffering 은 프록시가 응답을 모았다가 보내는 것이라 한 줄씩 즉시 나가야 하는 스트리밍에서는 off 로 꺼야 한다.

proxy_cache 는 스트림을 캐싱하면 안 되므로 끄고 Connection 은 유지 연결을 위해 빈 값으로 둔다. 넷이 각각 다른 이유로 필요했다. 버퍼링은 두 가지 방법이 있었는데 nginx 설정에서 끄는 것과 서버가 X-Accel-Buffering: no 를 보내는 것이다. 앞쪽을 골랐다. 이유는 이 서비스가 그 헤더를 넣으려면 배포가 하나 더 필요해서다. 대신 같은 위치의 다른 응답까지 버퍼링이 꺼지는 것을 감수했다.

검증 — 앞단과 얽힌 버퍼링

버퍼링이 왜 결정적이었는지가 이 조사의 핵심이었다. 앞단 CDN 에도 타임아웃이 있고 스트리밍 서버는 주기적으로 : keep-alive 주석 줄을 보내 그것을 리셋한다.

프록시가 버퍼링하면 그 신호가 앞단까지 안 나가고 앞단은 아무것도 못 받은 채 타임아웃에 도달한다. 주기적으로 끊긴 이유가 유지 신호가 버퍼에 묶여 있었기 때문이었다.

주의 — 계층별 타임아웃

이 문제가 어려웠던 이유는 타임아웃이 세 계층에 있다는 점이었다. CDN 과 nginx 와 서버가 각각 값을 갖고 있다.

어느 계층이 끊는지를 알아야 하고 끊기는 주기가 힌트가 되므로 주기를 재는 것이 진단의 시작이다. 이 문제를 푼 방법은 같은 프록시에서 잘 되는 설정과 비교한 것이었는데 누군가 전에 같은 문제를 겪고 고쳐 둔 것으로 보이며 잘 되는 예가 있으면 그것이 문서보다 빠른 답이다.

정리


Share this post on:

Previous Post
비활성화된 버튼을 우회하지 않는다
Next Post
영역마다 다른 이관 진행