Contents

로그 스트리밍으로 서비스 구성하기

배경

로그도 남기고, 이벤트도 남겨?

서비스를 쭉 구성하다보니 이런 생각을 했습니다.

  1. 어차피 로그는 남긴다.
  2. 필요한 유저 행동에 대해 이벤트르 발행한다.
  3. 그러면 각 서비스가 로그에서 필요한 걸 가져가서 상태 변화를 기록하면 되는 것 아닐까?
  4. 뭣하러 굳이 이벤트를 별도로 발행하지? 어차피 모두 kafka같은 메시지 브로커를 탈텐데?

왜 굳이 2개를 중복으로 메시지 브로커에게 남겨야 하는가가 매우 큰 궁금증이었습니다.
기본적으로 어떤 메시지 브로커를 선택하든 간에, 아니 가장 대표적인 Kafka를 상정하고 얘기해도, 각 컨슈머 그룹에 따라 메시지를 복제해서 전달하고, 컨슈머 그룹 내에 여러 컨슈머가 있을 경우에 적절히 분배해주는 기능이 존재합니다.
MSA를 구성하든, MMA를 구성하든 간에 사실 필요한 로그를 누락 없이 받아서 처리할 수 있을 것입니다.
처리량이 많다고요? 노드를 늘리고, 스펙을 올리죠!

그럼 현실적으로 왜 그러지 않지?

체리픽을 어떻게 할지가 가장 큰 문제가 아닐까 생각합니다.
이 부분 자체가 단순히 받는 쪽에서 실시간으로 흐르고 있는 로그 스트림을 봐가면서 하나하나 가져오기에는 너무 큰 부담이라 생각합니다.
그렇다면 로그를 생성하는 쪽에서도 어떠한 로그인지에 대해 최소 2~3개의 분류를 해주고, 받는 쪽에서 어떤 로그 분류를 받아서 처리할지 골라서 받으면, 부담이 많이 줄어들 수 있을 것입니다.

근데 이러면 이벤트 발행하는 것과 다르지 않냐구요?
사실 이 포스트 자체가 로그와 이벤트를 둘 다 남기는 것이 불만이었고, 둘을 하나로 줄이는 과정에 있다고 보시면 해당 의문은 그렇게 중요한 것이 아니라고 느끼실 겁니다.
단지 이벤트가 사라지고 로그만이 남았다고 생각하시면 편해요.

가정

뭘 만들까?

제가 해당 도메인에 있으니 라이브 스트리밍 서비스를 만든다고 가정해보겠습니다.
기본적으로 스트리밍을 할 수 있는 환경을 만들어야 할 것입니다.

  1. RTMP(S) 서버: RTMP를 받는 서버입니다.
  2. Transcoder: 송출 처리된 비디오를 여러 화질로 변환합니다.
  3. Packetizer & Uploader: ts나 mp4 형식으로 비디오나 오디오를 박싱합니다.
  4. HLS 서버: 박싱된 미디어 데이터나 메타데이터를 사용자에게 서빙합니다.
  5. LiveInfo: 라이브 스트리밍에 대한 정보를 관리합니다.
  6. Live API 서버: 라이브 스트리밍에 대한 정보를 서빙합니다.

구현하는 게 아니니 좀 넉넉히 가정했습니다.

여기에 메시지 브로커로는 apache kafka를 가정하겠습니다.
제가 카프카에 대한 지식이 깊지 않아서 실수할 수 있으니, 만약 잘못된 내용이 있다면 제 이메일로 알려주시면 첨삭하도록 하겠습니다.

구상

토픽을 구성해볼까?

카프카로 흐르는 모든 것은 로그다.

개인적으로는 카프카 클러스터를 구성한다면, 해당 카프카 클러스터는 오로지 로그만을 전달하기 위한 클러스터로 구성할 것입니다.
하지만 많은 조직에서 비싼 카프카 클러스터를 오로지 로그 시핑을 위한 용도로만 쓰도록 설계할 것같진 않습니다.
예를 들어, 로컬에서 생성형 AI를 서비스에 활용할 경우에 카프카를 통해 요청과 응답을 주고 받을 수 있을 것입니다.

하지만, 이 글에서는 제가 편한 방식과 이상을 반영해서 로그만을 전달한다고 가정하겠습니다.
그러므로 일단 * 토픽에 ElasticSearch Sink Connector를 붙이겠습니다.
필요하다면 Transforms를 이용하여 인덱스 이름을 직접 수정하도록 합니다.
저도 일단 지르고 보는 거에요

그래서 각 서비스는?

필요한 이벤트 로그(서비스 운영 상 정상적인 상황의 정보 발생에 따른 로그)는 대표적으로 이런 것들이 있을 것같습니다.

  1. RTMP 서버: 방송 개설 및 종료 여부, 인증 성공 및 실패 여부
  2. Transcoder: 변환되는 해상도 및 화질 정보
  3. Live API 서버: Publish Key 변경 여부, 방송 제목 변경 여부, 방송 옵션 변경 여부

이제 어떻게 해야 커플링을 최소화하며 로그를 남길 수 있을까요?
미리 작성했던 대로 2~3개 정도의 분류를 적용하여 토픽을 설정해야할 것입니다.
현재 나와 있는 스펙을 보면 대분류는 media 하나로 가능할 것같습니다.

그 다음 중분류에서 2가지 분류로, 소분류에선 더 잘게 나눌 수 있어 보입니다.

  1. live_stream: 실제 라이브 과정의 것임을 의미합니다.
    1. status: 방송 시작, 중단과 같은 상태 변경에 쓰입니다.
    2. metadata: 해당 방송의 메타데이터가 변경됨을 남깁니다.
  2. broad_info: 방송에 이미 설정되어 있는 것임을 의미합니다.
    1. publish_key: 퍼블리시키에 대한 변경이 발생됨을 남깁니다.
    2. title: 방송 제목에 대한 변경이 발생됨을 남깁니다.
    3. tags: 방송 태그가 변경됨을 남깁니다.
    4. options: 기타 방송을 위한 옵션이 변경됨을 남깁니다.

그러면 현재 제안 상으로 다음 토픽들이 나오게 됩니다.

  1. media.live_stream.status
  2. media.live_stream.metadata
  3. media.broad_info.publish_key
  4. media.broad_info.title
  5. media.broad_info.tags
  6. media.broad_info.options

토픽 좀 긁어볼까?

이제 이걸 어떻게 활용할 수 있을까요?
대략적으로 생각나는 건 이정도입니다.

  1. media.broad_info.publish_key: API를 통해 변경된 퍼블리시키를 RTMP 서버의 인증 부분에서 사용
  2. media.broad_info.title: API를 통해 변경된 방송 제목을 LiveInfo가 받아서 변경 (쓰기 작업)
  3. media.broad_info.tags: API를 통해 변경된 방송 태그를 LiveInfo가 받아서 변경 (쓰기 작업)
  4. media.broad_info.options: API를 통해 변경된 방송 옵션을 LiveInfo가 받아서 변경 (쓰기 작업)
  5. media.live_stream.status: RTMP 서버에서 publish 성공 시 개설, 커넥션 종료 시 중단을 발행하여 LiveInfo에서 방송 상태 변경 (쓰기 작업)
  6. media.live_stream.metadata: Transcoder에서 오리지널 비디오 및 오디오에 대한 정보 및 트랜스코딩 되는 타겟들을 발행하여 LiveInfo와 HLS 서버가 사용할 수 있는 HLS 옵션으로 기록 (쓰기 작업)

그리고 이 데이터들은

  1. 송출자가 송출 시 인증 과정에 사용
  2. 시청자가 방송 정보 조회 및 방송 시청 시 데이터로 사용

조금 더 나아가서

사실 만약 엘라스틱 서치나 밀리서치를 구성한다면, kafka를 통해 검색 엔진에 추가하고 사용할 수 있을 것입니다.
물론 직접적으로 넣기보단 관련 서버가 받아서 검색엔진에 대한 작업을 하는 방향으로 입니다.
예를 들어,

  1. 방송 제목이 변경되었다면 기존의 것을 삭제하고 새로운 것으로 대체하는 동작
  2. 방송이 개설되었다면, 제목을 조회 및 추가하여 검색 가능하게 설정
  3. 방송이 중단되었다면, 제목을 삭제하여 검색 불가능하게 설정

이에 대해선 tagsmetadata에도 동일합니다.
특정 태그에 대한 방송을 검색한다거나, 어떤 해상도를 지원하는 방송을 검색하는 등이 가능해지는 거죠.

끝으로

한번쯤 구성해보고 싶은 구조입니다.
당연한 이야기지만 트랜잭션이 필요한 구간은 쓰기가 끝난 후에, CDC를 통해 메시지 브로커에 publish하고 온라인 분석에 활용할 수 있도록 하는 구조가 일반적으로 보입니다.
또한 이 구조 자체가 로그를 생산하고 소비하는 주체가 되는 곳에서 확실하게 합의가 되어야 하는 부분이라 시작할 때 체계를 잘 잡아야 할만해 보입니다.