안녕하세요. 리디 R-Bus(RIDI Event Bus) 팀 엔지니어 정석교입니다. 리디에서 Kafka를 어떻게 활용하고 있는지에 대해서 소개 드리려 합니다.
Kafka의 정식 명칭은 Apache Kafka로, 실시간으로 이벤트 스트림을 게시 및 구독, 저장, 처리할 수 있는 분산 데이터 스트리밍 플랫폼입니다. 전통적인 메시징 시스템에 대한 대안으로 LinkedIn에서 개발됐고, 현재는 여러 테크 기업들에서 활용되고 있습니다.
2020년부터 리디 역시 내부 API를 활용하던 마이크로 서비스들 간의 통합을 점차 Kafka 기반으로 옮겨가고 있습니다. 자, 그럼 리디에서 Kafka를 어떻게 활용하고 있는지 알아볼까요?
실시간 랭킹
리디 서비스에는 ‘실시간 랭킹’ 섹션이 있습니다.
이 데이터는 사용자들이 콘텐츠를 감상할 때 호출되는 감상 데이터 API를 통해서 만들어집니다.
과거에는 이 API를 담당하는 (마이크로) 서비스에서 실시간 랭킹을 담당하는 서비스의 실시간 랭킹 API를 호출하는 방식을 사용하였습니다. 하지만 이러한 방식에는 응답속도나 장애 전파 등 여러 아쉬운 점이 있었습니다.
이제는 Kafka를 활용하여 콘텐츠 감상에 대한 이벤트를 수집하여 스트리밍하는 토픽을 통해 해결하고 있습니다.
감상 데이터 서비스는 이 토픽에 콘텐츠 감상 메시지를 게시하고, 실시간 랭킹 서비스는 해당 토픽을 구독하는 방식을 사용합니다.
이를 통해서 도서 감상 서비스는 응답속도 향상과 더불어 실시간 랭킹 서비스에 대한 의존성을 없애, 더 높은 안정성을 확보할 수 있었습니다. 실시간 랭킹 서비스 입장에서는 과거 API 호출 시 개별 처리되던 데이터를 여러 개 묶어서 처리할 수 있게 되어 더욱 높은 효율성을 확보했습니다.
또한 콘텐츠 감상에 대한 토픽을 확보하게 되어 실시간 랭킹 서비스 외의 다른 서비스에서도 기존 시스템에 영향을 주지 않고 감상 이벤트를 활용할 수 있는 확장성을 확보하였습니다.
이미 눈치채신 분도 계시겠지만, 이렇게 Kafka를 이벤트 버스로 활용하기 시작하면서 지금 제가 근무하고 있는 R-Bus (RIDI Event Bus) 팀이 출범하게 되었습니다. 그리고 감상 이벤트 외에도 고객의 행동 로그, 내부 콘텐츠 상태변화 등 다양한 이벤트를 Kafka 를 통해 처리하고 있습니다.
애널리틱스
리디에서는 다양한 사업적 요구를 분석하기 위해서 여러 종류의 분석 플랫폼들을 활용하고 있는데, 리디 서비스와 이러한 플랫폼들 간의 데이터 통로로도 Kafka를 활용하고 있습니다.
예를 들어 앱 푸시 클릭에 대한 기록, 구매 기록 등의 정보가 Kafka를 통해 여러 플랫폼으로 전달되고, 이를 통해 분석된 정보는 실시간으로 CRM 등에 활용되고 있습니다.
이 외에도 페이지뷰, 매출과 같은 KPI 성 매트릭들도 Kafka를 통해 수집해서 시계열 데이터베이스(TSDB)인 InfluxDB로 저장해 콘텐츠 부서에서 실시간 대시보드로 KPI를 트래킹하고 대응할 수 있도록 하고 있습니다.
작업 큐
또 Kafka를 비동기 작업 큐(job queue)로도 활용하고 있습니다. 리디에서는 다양한 혜택과 신간 알림 등의 정보를 알림이라는 내부 서비스와 앱 푸시, 메일을 사용해 고객에게 전달하고 있습니다. 알림은 매일 수천만 건, 앱 푸시와 메일도 수십만에서 수백만 건 발송이 이뤄지고 있습니다.
기존 REST API를 사용하는 방식은 순간적으로 부하가 늘어나는 이런 형태의 작업을 처리하기에 적합하지 않았습니다. Kafka를 활용한 작업 큐를 도입하여 작업들을 병렬로 처리하면서, 고객들에게 유용한 정보를 빠르게 전달할 수 있게 되었습니다.
다양한 이벤트 활용
Kafka로 모으는 리디의 다양한 이벤트들은 실시간 부정행위 감지에도 적용됩니다. 회원 가입 이벤트를 활용해 부정한 방법으로 생성된 계정을 감지하고, 댓글 이벤트를 활용해 특정 작품에 반복으로 악의적인 댓글을 다는 행위 등을 감지하고 있습니다.
지금까지 소개 드린 내용은 리디 고객의 입장에서는 변화를 느끼기 힘든 사례인데요. 이번에는 고객 관점에서도 충분히 변화를 느낄 수 있는 사례를 소개해 드리겠습니다.
리디에서는 다양한 종류의 이벤트를 진행하는데, 그중에서도 특정 조건의 콘텐츠를 열람하거나 콘텐츠에 댓글을 남기면 포인트를 주는 이벤트가 인기입니다. 예전에는 이벤트 기간이 끝난 후 배치 작업을 통해 일괄 지급했지만, 지금은 Kafka를 활용해 감상 및 댓글에 대한 토픽을 구성하여 실시간으로 지급하고 있습니다.
예제 코드
그러면 실제 코드를 통해 처음 소개해 드렸던 실시간 랭킹을 좀 더 자세히 살펴보도록 하겠습니다.
먼저 메시지 게시와 구독에 사용될 함수를 선언해 줍니다. 참고로 리디에서는 Kafka 메시지 포맷으로 CloudEvents를 사용하고 있으며, 컨슈머는 주로 Node.js 기반으로 KafkaJS를 사용하고 있습니다.
interface Message {
bookId: string;
userIdx: number;
}
export const subscribeReadingBooks =
createSubscribe<Message>('reading-books');
export const publishReadingBooks = (data: Message) => {
const event = new CloudEvent({ data });
return producer.send({
messages: [
{
headers: {
'content-type': 'application/cloudevents+json; charset=UTF-8',
},
value: event.toString(),
},
],
topic: 'reading-books',
});
};
그리고 발행과 구독을 해 줍니다.
// 감상 데이터 서비스에서 메시지 게시
publishReadingBooks({
bookId,
userIdx: req.user.idx,
});
// 실시간 랭킹 서비스에서 토픽 구독
subscribeReadingBooks({
eachBatch: async ({ messages }) => {
// 실시간 랭킹을 계산하기 위한 작업
}),
});
마치며
현재 리디에서는 최대 초당 수만 개가량의 메시지가 Kafka를 통해서 처리되고 있습니다. 이 수는 앞으로 더욱 늘어날 것으로 기대하고 있습니다.
부지런함을 경계하는 20년차 개발자, 엔지니어 정석교님 인터뷰 바로가기
고객과 발맞춰 새로운 콘텐츠 경험을 선보이는
리디와 함께할 당신을 기다립니다.