저희 팀은 실시간 데이터 동기화를 위해 Kafka를 도입했습니다.
토픽과 컨슈머를 잘 설계해도 데이터 변경 시점에 이벤트를 발행하지 않으면 실시간성을 보장할 수 없습니다.
그래서 서비스의 변경 포인트마다 적절한 Kafka 토픽에 메시지를 발행하는 코드가 필요했고, 이 과정에서 개발자의 휴먼 에러 가능성이 늘 존재했습니다.
• 데이터 변경 시 Kafka 메시지를 발행하지 않으면 동기화가 누락됨
• 이를 감지할 방법이 없어, 정기 배치 작업으로 누락된 데이터를 동기화
• 데이터 양이 늘어날수록 BatchJob의 부하 증가
문제 정의:
“실시간 동기화를 위해 과도한 리소스(Batch)와 휴먼에러 위험을 감수해야 한다.”
책 데이터 중심 애플리케이션 설계 를 참고하여 CDC(Change Data Capture) 기법에서 아이디어를 얻었습니다.
• 다양한 사례에서 Debezium을 사용
• 저희는 AWS DMS의 CDC 기능을 선택:
• RDS → MSK(MSK는 AWS Kafka)로 데이터 복제
• 관리형 환경, 빠른 복제 속도, 네트워크 설정 용이
• DMS가 Kafka 토픽에 이벤트 발행
• 애플리케이션이 이 메시지를 소비하려 했으나 데이터베이스 스키마에 강하게 의존
• ALTER, DROP 등 변경에 민감
Apache Flink 등의 스트리밍 프레임워크를 고려했으나,JVM 기반이기도 하고
단순 consume → produce 구조여서 추후 도입을 미루고 직접 구현하기로 결정
Lambda 고려 이유
• Kafka 토픽을 트리거로 직접 연결 가능
• 간단한 기능, DB 커넥션/HttpContext 불필요
두 언어로 Lambda 함수 구현 후 성능 비교:
• Go:
• 라이브러리: sarama
• 최적화를 위해 goroutine 사용
• Node.js:
• 라이브러리: kafkajs
• Promise.allSettled로 병렬 처리
BatchSize (1~10000) 테스트 결과:
6천개 이상의 메시지를 발행해보았습니다
윗 줄이 Go 아랫줄이 Node.js입니다 (Lambda Insight)
메모리는 압도적으로 Go가 우위여서 비용은 조금 아낄 수 있겠으나,
생각과 다르게 속도는 Node.js가 더 우위에 있었습니다.
(BatchSize를 달리해봐도 항상 같은 결과였습니다.)
특징으로는 Golang은 BatchSize가 달라져도 일정한 평균치를 유지했지만, Node.js는 BatchSize에 따라 100ms이하의 속도를 보이기도, 200ms 이상의 속도를 보이기도 했습니다.
콜드스타트 지속시간은 Go가 더 짧았습니다.
언어의 차이도 있을 수 있겠으나 sarama, kafkajs의 라이브러리 성능 차이도 있겠죠.
아무튼 유지보수성까지 생각하면, 서비스에도 사용중인언어로 Node.js가 나았다고 생각했지만
서버와 비교해봐야겠습니다.
• 유지보수성과 기존 서비스 호환성 고려 시 Node.js가 유리
• @nestjs/microservices 사용해 Kafka consumer 구현
• Lambda와 동일한 로직을 NestJS 서버로 운영하며 Kafka UI로 consumer lag 비교
kafka-ui를 통해 확인한 장면입니다.
위부터 go-lambda / nodejs-lambda / nestjs-server 입니다
약 6천개의 메시지를 처리하는 동안 서버는 거의 lag을 가지지 않았습니다.
메시지를 스트리밍하는데에 지연이 거의 없다는 뜻이겠죠
바로 서버를 올리기로 결정했습니다.
서버 기반이 성능 및 안정성 모두 우수
• CDC(DMS) → Kafka → NestJS 서버로 실시간 이벤트 스트리밍
• 개발자가 따로 신경 쓰지 않아도, 데이터 변경이 발생하면 **모든 채널(외부 채널, 캐시 등)**이 실시간 동기화됨
• Batch에 의존하던 동기화 방식에서 벗어나 실시간 이벤트 기반 아키텍처로 전환
• Kafka와 AWS DMS의 CDC 조합은 휴먼에러를 줄이고 리소스 효율을 개선
• Golang, Node.js, Lambda, ECS를 직접 구현하고 비교한 끝에, NestJS 서버 기반 구조를 최종 선택
“동기화를 신경 쓰지 않아도 되는 시스템”을 만든 경험이었습니다.