project/wargame

[꿀팁대방출] Kafka Topic 재설계와 EDA 도입을 통한 획기적인 클라우드 비용 개선

downfa11 2025. 7. 12. 10:46

 

네? Kafka 운영비 400$를 제공한다구요? 거기다가 작게 쓰면 1$/month 이하라고요?

 

Kafka의 공동 제작자이자 Confluent의 공동 창립자, CTO인 neha의 인터뷰를 통해서 탄생 비화를 알 수 있었다.

카프카가 대세가 되는걸 느낀 시점에서, 데이터를 어떻게 처리할지만 고민하던 링크드인 내부에서 새로 창업을 결심했다고 한다.

 

다들,, Kafka의 기업용 클라우드를 제공하는 Confluent의 저렴한 요금제에 따르시오

 

Confluent Kafka를 이용해서 저렴한 비용으로 kafka를 이용해보자. 사실 클라우드 벤더사중에서 AWS의 비용은 비싼 편이다.

 

 

베이직 요금제로 진행하면 한달에 1GB도 안쓰는 범부들 입장에서 거의 제로에 가깝게 비용이 나온다.

 

 

아 첫 한달 400$ 제공이 눈앞에 아른거려

난 죽었다깨도 절대 혼자 못쓰는 양인데… confluent도 거의 안쓰고 켜두기만 하면 0달러래서 하는거라고…

 

 

네? Redis Cloud는 메모리 30MB 이내면 무료라고요?

Redis Cloud에서 30MB, Connections 30개짜리 무료로 제공해준다.

특히 Redisson같은 분산 락에는 기본적으로 30개정도 connections을 가져가기 때문에 명시적으로 제어해줘야 무료 30개에 맞출 수 있다.

  • 참고) Lettuce의 유휴 Connection는 defualt 8개다.

그리고 무료 버전에서는 database(0)밖에 지원하지 않는 것도 명심하자.

 

@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    config.useSingleServer()
            .setAddress("redis://" + redisHost + ":" + redisPort)
            .setPassword(password)
            .setConnectionPoolSize(7)
            .setConnectionMinimumIdleSize(4)
            .setDatabase(0);
    return Redisson.create(config);
}

 

꿀팁 대방출이다.. 다들 쓰세요

 

Kafka Topic 설계를 통해 운영 비용을 개선해보자

 

기존 마이크로 서비스: membership, feed, player, match, result, result-query (6개)

  • confluent kafka basic에서 파티션 3개씩 사용해서 기존 방식

각 서비스에 대한 request/response 토픽을 별도로 두는 방식

  • 서비스 수가 늘어날수록 토픽 수가 빠르게 증가
  • 현재 공통 로그 수집 목적의 토픽까지 더해서 총 11개 Topic

이전까지는 일부만 적용되었던 이벤트 중심 아키텍처(EDA)를 확장, 토픽 수도 도메인 이벤트를 중심으로 최소화하도록 설계

 

 

그럼 기존 방식은 왜 response/request 구조를 사용해야 했는가?

  • feed 서비스에서 membership에게서 nickname으로 user_id를 받아오는 요청/반응
  • match 서비스에서 매칭을 위해 player 서비스에게서 각각 데이터를 받아오는 요청/반응

시스템 설계에서부터 난 로직을 이어가기 위해서 다른 서비스로부터의 응답을 받아오는 동기적 구조로 설계해왔다.

 

 

사용자의 nickname으로 해당 사용자가 작성한 게시글을 모두 조회하기 위해서는 membershipId-nickname 매핑 테이블이 필요하다.

 

하지만 게시글 서비스에서 알 턱이 있나? membership 서비스로부터 받아와야 하는데, 원하는 쿼리 결과를 받을때까지 Polling하면서 timeout, retry 등을 설정하는 똥꼬쇼를 진행해왔다. 

 

 

이론으로만 공부했던 Non-Blocking 시스템으로 동기적인 구조 설계해서 비효율을 쌓아왔단 말이다.

 

다행히 IO bound에 특화된 boundedElastic 쓰레드풀에서 처리해서 이벤트 루프의 블로킹을 막을 수 있었지만.. 잘 동작하면 뭐하나 비용이 문제인데!!

 

어떻게 이벤트 기반 비즈니스로 개선할건가?

더이상 응답을 기다리지 않고 이벤트를 비동기적으로 구독하는 형태로 개선하고자 함

 

핵심은 사실 매칭 과정의 데이터 파이프라인이고, feed 서비스같은 경우는 Axon 방식의 이벤트 브로커 통신으로 충분히 구현 가능하다.

 

이벤트 주도 디자인같은 경우는 기존에도 player 서비스나 result 서비스 등 일부에 대해서 이벤트 소싱을 적용하면서 도입한 적은 있지만, 시스템 전체를 이벤트 기반으로 이전한게 아니라 EDA(architecture)라고 보긴 어려운 상태였다.

 

이번 기회에 불필요한 Topic 개수를 줄여서 비용도 줄일 겸 완전히 이벤트 기반 아키텍처로 옮기고자 한다. 

 

Axon 기반의 QueryHandler를 통한 사용자 nickname 조회

private final QueryGateway queryGateway;

private Mono<String> findNicknameById(Long membershipId){
   return Mono.fromFuture(queryGateway.query(new GetUserNameQuery(membershipId)));
}


...

 return findNicknameById(comment.getUserId())
      .flatMap(nickname -> modifyCommentPort.modifyComment(nickname, request));

 

 

Membership 서비스에서의 QueryHandler 클래스

@Slf4j
@Component
@RequiredArgsConstructor
public class MembershipQueryHandler {
    private final FindUserPort findUserPort;

    @QueryHandler
    public Mono<String> handle(GetUserNameQuery query) {
        return findUserPort.findUserByMembershipId(query.getMembershipId())
                .map(user -> return user.getName())
                .doOnError(e -> log.error("GetUserNameQuery error: membershipId={}, message={}", query.getMembershipId(), e.getMessage(), e));
    }
}

 

 

이벤트 주도 설계를 통해 개선한 매칭 파이프라인

매칭서버로부터 매칭시 필요한 사용자 정보를 전달 (publish=match, subscribe=player)

  • 위 과정을 Axon 기반 이벤트 스트리밍으로 개선

기존 매칭 결과 전달 로직을 이벤트 기반 아키텍처로 개선 

  • player.events.topic: 게임서버로부터 게임 결과를 수신 (publish=game, subscribe=player)
  • match.events.topic: 매칭 결과를 게임서버로 전달 (publish=match, subscribe=game)
  • platform.logs.topic: 로그 수집 (게임서버에서 사용자 행위 데이터, 백엔드 수준의 AOP 로깅 통합 수집)

 

비용 개선의 결과 분석

Confluent Cloud의 공식 가격 계산기를 통해서 비용 문제를 비교했다.

  • 데이터 송수신(Ingress/Egress): GB당 요금이 나가서 1GB로 설정
  • 데이터 저장(Storage): GB당 요금이 나가서 1GB로 두되, 보존기간을 하루로 설정
  • 각 토픽별로 파티션 3개로 동일하게 비교

기본 Basic 요금제

  • Ingress/Egress: $0.025 - $0.03/GB (계산을 위해 $0.03/GB 사용)
  • Storage: 월 $0.08/GB (보존기간 1일, 1GB 사용 시)
  • Partitions: 최초 10개 파티션 무료 (10개 초과 시 $0.004/파티션/시간)

 

공통 비용 합계: $0.03 (데이터 송수신) + $0.08 (데이터 저장) = $0.11/월

이외에도 클러스터 유지에 따른 오버헤드가 발생할 수 있음

 

 

하지만 파티션 수에 따른 과금 내용에서 큰 차이를 나타낸다.

  • 기존 방식: 11개 토픽 * 3개 파티션 = 총 33개 파티션 (약 $66.24/month)
  • 재설계: 3개 토픽 * 3개 파티션 = 총 9개 파티션 (약 $0.11/month)

 

📌 Kafka 클러스터 운영 비용을 99.8% 개선

파티션 수가 무료 제공 범위(10개) 안으로 들어오면서 파티션 과금 자체가 없어졌기 때문에 매우 큰 비용 절감을 만들 수 있었다.

 

해삐~