"네이버 축구 생중계 그거.. 폴링 방식 쓰는거같던데요?"
때는 형제의 나라 가나와 붙었던 11월 28일...
후반전 시작하고 얼마 안 돼서 연속 2골이나 넣어버린 조규성 선수를 침흘리면서 보다가 문득 스터디원이 말했던게 생각났다.
제발 딱 한 골만 더!!! 하는 심정으로 네이버 생중계를 띄워놓고 F12를 눌러 크롬 개발자 모드를 켰다.
롱폴링도 아니고 그냥 폴링을 쓴다니, 왜지?
개발자 도구로 네트워크를 살펴보니 진짜로 일정한 시간 간격을 두고 request-response가 전달되고 있었다.
크게 2가지 타입으로 나눌 수 있었다.
잘 보면 이름에 stream
이 들어간 게 있다. chunklist_480.stream.m3u8
의 response를 찍어보면 이렇게 알 수 없는 내용들이 가득 적혀있는데, 아무래도 이게 우리가 보는 생중계 영상인 것 같다. 이유는..
먼저 Response를 한 줄씩 뜯어보면 #EXTINF
라는 문구로 시작하는 줄이 규칙적으로 나오는데, 구글에 extinf
라고 검색하면 이런 위키 백과 페이지가 하나 나온다.
그리고 이 M3U 라는 파일 포맷의 확장판이 Extended M3U이고 확장정보를 담을 때 #EXTINF
를 사용한다고 적혀있다.
다시 M3U를 검색해보면 'http live streaming'을 위해 사용되는 파일 포맷이라는 내용의 글들이 꽤 보인다. 그리고 앞서 찾았던 위키 백과의 외부 링크 하나를 타고 들어가면...
이렇게 #EXTINF
태그의 포맷도 친절히 알려주고 있다. 네이버 스포츠 캡처본을 보면 #EXTINF:2.000000,~~~
라고 되어있는걸 보면 duration은 2초마다 끊은 것 같다.
참고로 480.stream_*
응답은 이렇게 생겼다. 스트리밍 데이터라 개발자 모드에서 제대로 변환을 못 하는 것 같다.
이제 다른 유형의 응답을 보자. 이름부터 좀 다르다. game-polling 이다. 아마 스터디원은 이걸 보고 polling 방식을 사용한다고 말했던 것 같다.
이번 응답은 좀 더 인간 친화적이다. 무려 JSON 형태로 오고 있다!
그래서 포멧팅을 해서 구경하던 중에 이런걸 발견했다.
{
"scorers": {
"home": [
{
"time": 58,
"addedTime": null,
"playerName": "조규성",
"ownGoal": false
},
{
"time": 61,
"addedTime": null,
"playerName": "조규성",
"ownGoal": false
}
],
"away": [
{
"time": 24,
"addedTime": null,
"playerName": "모하메드 살리수",
"ownGoal": false
},
{
"time": 34,
"addedTime": null,
"playerName": "쿠두스",
"ownGoal": false
}
]
}
}
오호.. 골 넣은 사람들 목록이구만? addedTime
과 ownGoal
이 무슨 뜻인지는 모르겠다.
조금 더 내려보자.
{
"textRelayData": {
"homeScore": 2,
"awayScore": 2,
"textRelays": [
{
"no": 1746503169,
"eventType": "Goal",
"flag": "0",
"homeOrAway": "Home",
"time": "61",
"normalTime": "61",
"addedTime": "0",
"homeScore": 2,
"awayScore": 3,
"ptHomeScore": 0,
"ptAwayScore": 0,
"homeScorePlayer": null,
"awayScorePlayer": null,
"half": "2",
"playerId": "1996453",
"playerName": "조규성",
"videoMasterId": "",
"text": "골! 조규성의 헤딩골로 경기는 2 - 2 동점이 됩니다.",
"statusCode": 2,
"statusInfo": "후반 16'",
"eventName": "Goal",
"eventText": "Goal",
"eventClassName": "stat_goal"
}
]
}
}
보아하니 조규성 선수의 동점골이 터졌을 때인 것 같다. 그러고보니 실제 중계 웹사이트에서 스크롤을 조금만 내려보면 텍스트로 중계를 보여주는 부분이 있었다.
자동 업데이트를 켜놓으면 이 텍스트 중계 부분이 웹페이지를 새로고침하지 않아도 저절로 업데이트가 되는걸 발견했다. 그리고 끝까지 보면서 후반부에 가나가 마지막 골을 넣었을 때에도 새로고침 없이 저절로 점수가 업데이트 되었다. game-polling
이라는 이름처럼 주기적으로 요청을 보내고 있다는걸 확인할 수 있었다. 스크린샷은 찍지 못했지만 polling-status
라는 이름의 연결이 있는걸 보면 폴링 혹은 이와 유사한 방식을 썼을 것이라고 추측해볼 수 있다. (물론 네이버 스포츠에서 이름만 polling이고 사실은 웹소켓이나 다른 방식을 썼을 수도 있다.🧐)
서버와 클라이언트가 실시간으로 소통하(는 것처럼 보이)기 위해 고안된 기법이 있다. 간단하게 요약하자면 이렇다.
클라이언트: "내가 5초마다 요청 넣을게. 그 때마다 바로 보내줘."
서버: "그래. 나도 요청 받자마자 바로 응답 주고 연결 닫을게."
클라이언트: "내가 5초마다 요청 넣을게. 근데 보낼거 없으면 좀 더 있다가 보내줘."
서버: "그래. 요청 받고나서 새 데이터가 생기면 보내줄게. 대신 대기시간 지나면 연결 닫을거야."
클라이언트: "우리 오래오래 보자."
서버: "그래. 둘 중 하나가 연결 끊기로 하기 전까지 계속 연결되어 있는거야."
먼저 웹소켓을 사용하지 않은 이유는 명백하다.
동접자가 200만명에 달하는 상황에서 서버가 클라이언트 하나마다 연결을 모두 유지해야 한다면..? 경험이 짧은 나로써도 쉽지 않을 것 같다는 생각이 든다. 또한 웹소켓은 보통 서버 to 클라이언트 및 클라이언트 to 서버, 양방향 소통이 모두 필요할 때 유용한 방식이기도 하다. 월드컵 생중계는 클라이언트에서 서버쪽으로 보낼 데이터가 없다. 굳이 웹소켓을 쓸 필요가 없는 것이다.
그렇다면 폴링과 롱폴링 중 어떤걸 썼을까? 에 대한 구체적인 단서는 찾지 못했다. 응답 시간이 아주 칼같이 일정한 간격으로 찍혔다면 폴링일 가능성이 높을텐데 이것도 정확하지 않다. 네트워크 상황에 따라 달라질 수 있는 요소가 많기 때문이다.
혹시나 단서를 찾은 분이 계신다면 공유해주세요. 🤗
잘 읽었습니다. 감사합니다.
저도 갑자기 궁금해져서 찾아봤는데 제 환경에서는 조금 다르게 보였습니다.
제 환경에서도 폴링은 계속 이뤄지고 있었지만 네이버 스포츠 플러그인이라는 크롬 익스텐션을 설치한 사용자와 그렇지 않은 사용자가 분기되는 것 같습니다.
480p 이하의 화질 동영상 서비스에서는 말씀 주신대로 cdn 서버에서 짧은 동영상을 폴링 받아오는 것으로 추측됩니다.
화질이 720p 이상이 되면 (720, 1080) 네이버 스포츠 플러그인을 거쳐서,
똑같이 짧은 길이의 동영상을 폴링하되 주소가 로컬의 17080번 포트로 변경되었습니다.
480p에서 720p로 화질을 변경하게 되면 cdn서버에 폴링을 종료한다는 메시지를 보낸 다음, localhost로 폴링을 개시한다는 메시지를 보내 그 위치를 바꾸게 됩니다.
이 정보 조각들로 미루어보아 아마 이런 방식으로 동작하지 않을까? 하는 생각을 했습니다.
1) 경기 요약 (골, 옐로/레드 카드 등)은 지속적으로 HTTP 폴링 서버에서 가져온다
2) 게임 동영상 자체는 ffmpeg을 사용하여 짧은 길이의 동영상으로 자른 영상을 폴링한다.
3) 이 때, 고화질의 동영상을 많은 사용자가 폴링할 경우 리소스가 많이 소모되므로 별도의 플러그인을 사용한다.
플러그인의 역할이 무엇인지 정확히 알지는 못하겠는데, 서버 자체의 커넥션 비용을 줄이기 위한 모종의 방법을 사용하지 않을까요? ㅎㅎ
wireshark로 더 찾아보니 특정 위치의 IDC로 종종 TCP 커넥션을 재연결하는 모습도 보입니다. 로컬에서는 또 10080 포트를 사용해서 통신하네요.
월드컵 시즌인만큼 저도 관련된 포스트를 조만간 써보겠습니다!
진짜 축구보면서도 이런 걸 찾으시다니 대단합니다 :) 저희 회사도 비디오,오디오 스트리밍 서비스에 hls를 사용하고 있어요 ㅎㅎ 이미 아실 수도 있지만 참고 되시는 링크하나 남겨요! https://aws.amazon.com/ko/media/tech/video-latency-in-live-streaming/