목록전체 글 (251)
FireDrago
프로젝트를 진행하며 방송 제목 변경, 카테고리 변경과 같은 스트림 메타데이터 변경을 추적하는 기능을 구현했다.초기에는 Redis Lua 스크립트 내부에서 상태 비교와 변경 감지까지 모두 처리하도록 구성했다.하지만 기능이 점점 추가되면서 비즈니스 로직이 계속 쌓이기 시작했다.그 과정에서 자연스럽게 이런 고민이 들었다.비즈니스 로직은 Redis가 담당하는 게 맞을까?Redis와 애플리케이션 중 어디까지 책임을 가져가야 할까? 이번 글에서는 Redis Lua 스크립트에 비대해진 비즈니스 로직을 어떻게 바라봤는지,그리고 Redis와 애플리케이션 사이에서 트레이드 오프를 고민하며 리팩토링했는지 정리해보려 한다.문제 : 비대해진 Lua 스크립트-- [AS-IS Lua 스크립트 중 일부] JSON 디코딩 및 상태 비..
기술면접1. Young GC와 Full GC의 차이가 뭐죠?2. 캐시 스탬피드(Cache Stampede)에 대해 설명해주세요. 해결방법은요? 암기 보단 사고과정"캐시 스탬피드에 대해서 설명해주세요" 머릿속이 하얘졌다. 생전 처음 듣는 개념이었기 때문이다. 다행히 면접관은 예시를 통해 설명을 이어갔다. "자 그럼 캐시 만료 시간을 1분으로 지정했다고 가정해보죠. 캐시 만료 이후, 폭발적 요청이 와서 db 부하가 폭증하는 상황이 오면 어떻게 해결할 수 있을까요?" 처음 접하는 문제였지만, 생각해보니 일단 '캐시 만료와 동시에 몰리는 요청'이 핵심이라고 생각했다.우선 모니터링을 통해 적절한 캐시 만료 시간을 찾아 조정하는 방법이 떠올랐다.그리고 여러 요청이 동시에 DB를 찌르는 것이 문제라면, 분산락을 도입..
기술면접1. Young GC와 Full GC의 차이가 뭐죠?2. 캐시 스탬피드(Cache Stampede)에 대해 설명해주세요. 해결방법은요? 최근 기술면접을 다녀왔다.이때까지 기술면접에서 받았던 질문들을 공부하고 정리하는 시리즈를 포스팅해보려고 한다.첫번째 질문은 "Young GC와 Full GC의 차이"이다. GC(Garbage Collection)가 뭔데?'자바의 특징'을 검색하면 바로 자동 메모리 관리가 뜬다. 자바가 처음 세상에 나올 당시 기존의 언어(c,c++)들은 개발자가 수동으로 메모리를 관리해야 했다.수동으로 메모리를 관리하는 프로그래밍 언어는 메모리를 효율적으로 최적화 할수 있지만,동시에 메모리 누수같은 치명적인 버그를 발생시킬 위험도 그만큼 높았다. 그래서 자바는 GC(Garbage ..
치즈픽 - Cheese-Pick 치즈픽 - Cheese-Pick cheesepick.me치지직의 상위 N개의 방송을 동적으로 인식하고, 자동으로 하이라이트 타임스탬프를 찍는 '치즈픽' 서비스를 운영 중이다. 이전 부하 테스트를 통해 가상 스레드를 적용하여 웹소켓 수집단의 I/O 병목을 개선했다. 하지만 트래픽을 지연 없이 수신하는 것과 이를 '분석하고 저장'하는 것은 별개의 문제다. 단일 애플리케이션 내에서 수천 건의 채팅 데이터를 지연 없이 버퍼링하고, DB I/O 부하를 최적화하여 안정적인 분석 파이프라인을 구축한 과정을 정리했다. 1. 강결합으로 인한 장애 전파 위험초기 구조에서는 웹소켓으로 채팅이 유입되면, 메인스레드가 채팅 수 집계와 DB 저장까지 동기적으로 처리했다. 이렇게 수집과 분석 로직..
치즈픽 - Cheese-Pick 치즈픽 - Cheese-Pick cheesepick.me 치지직의 상위 N개의 방송을 동적으로 인식하고, 자동으로 하이라이트 타임스탬프를 찍는 '치즈픽' 서비스를 운영 중이다.치즈픽의 핵심 엔진은 실시간으로 수백 개의 방송 채팅 웹소켓에 연결하여 `Kafka`를 통해 수집과 분석을 비동기적으로 분리하고,`Redis TimeSeries`를 활용해 시간 기반 채팅 데이터를 집계하여 하이라이트 분석하고, api 모듈에 전송하는 역할을 하고 있다. 전형적인 I/O 집약적인 작업이다. 2코어 2GB램 (t4g.medium 과 유사)의 제한된 로컬 리소스 환경에서 스프링 기본 스레드 (200개)를 사용했다. 하지만 부하테스트를 진행하며, 이 구조의 한계를 발견하고 가상스레드를 적용한..
https://cheesepick.me/치지직의 상위 N개의 방송을 동적으로 인식하고, 자동으로 하이라이트 타임스탬프를 찍는 '치즈픽' 서비스를 배포했다.실시간 방송 채팅 데이터를 수집하고 분석하는 엔진 특성상 Kafka와 Redis를 구동하고 연산을 처리하기 위해 꽤 큰 메모리와 CPU 성능이 필요했다. AWS 에서 구동하기 위해서는 꽤 큰 비용이 예상됐다. 그래서 역할별로 모듈을 구분하고, 홈서버와 오라클 클라우드에 나누어 배치했다. 그 과정을 알아보자 1. 인프라 역할 분리 (Cloud vs On Premise)핵심은 모듈간의 역할을 분리하는 것이다. Engine (Home Server): 웹소켓 채팅 수집, Kafka 메시지 큐잉, 실시간 화력 분석 등 메모리와 연산이 많이 필요한 무거운 작업은 ..
https://cheesepick.me/ 치즈픽 - Cheese-Pick cheesepick.me치지직의 상위 N개의 방송을 동적으로 인식하고, 자동으로 하이라이트 타임스탬프를 찍는 '치즈픽' 서비스를 배포했다.스트리머들의 채팅화력을 통해 하이라이트를 추출하는 알고리즘을 고도화하는 과정은 쉽지 않았다.실제 스트리머의 채팅화력과 데이터 분석을 통해 알고리즘을 고도화한 과정을 정리했다. 절대값으로 하이라이트 판정 (V1)스트리머측정시간 (UTC)오프셋초당 채팅판정결과대형 스트리머 A2026-02-15 16:40:212418433417PEAK대형 스트리머 A2026-02-15 16:40:242418733432PEAK대형 스트리머 A2026-02-15 16:40:272419033416PEAK대형 스트리머 A20..
4. EOS 설정 데이터의 유실과 중복을 방지하는 '정확히 한 번(Exactly-Once)' 처리를 위해서는 프로듀서(데이터를 보내는 앱)와 브로커(카프카 서버) 사이의 약속이 필요하다. 하지만 이 설정들을 활성화하면 단일 노드로 구성된 로컬 환경(Docker)에서는 에러가 발생한다. EOS를 구현하기 위해 프로듀서에서 설정하는 두 가지 핵심 옵션`acks=all` (유실 방지): 프로듀서가 메시지를 보낸 후, 메인 서버(Leader)뿐만 아니라 예비 서버(Follower)들까지 복제를 마쳤는지 확인하고 응답(ACK)을 받는 설정이다. 서버 한 대가 고장 나도 데이터가 사라지지 않게 보장한다.`enable.idempotence=true` (중복 방지): 프로듀서가 메시지마다 고유 번호(PID, Sequ..
왜 Kafka가 필요할까?치지직 라이브 채팅 데이터를 실시간 분석해 하이라이트를 포착하는 엔진을 개발하며 카프카를 도입했다. 초당 수천 ~ 수만 건의 채팅 데이터를 유실 없이 처리하고, 수집 서버와 분석 엔진 간의 의존성을 끊기 위해 카프카를 사용하는 분산 아키텍쳐가 필요했다. 하지만 파이프라인만 구축하면 모든 게 해결될 줄 알았던 생각은 오산이었다. 카프카는 메시지를 배달해줄 뿐, 중복 처리 방어(Idempotency)나 데이터 순서 보장, 이벤트 시간(Event Time) 정렬 같은 데이터 무결성은 온전히 개발자의 설계 영역이었다. 분산 시스템의 문제들을 어떻게 해결했는지, 삽질을 통해 배운것을 6가지 원칙으로 정리한다. 멱등성 : 카프카가 메시지를 여러개 보낼때카프카는 기본적으로 'At-least-..
문제 상황@Scheduled(fixedRate = 3000)public void monitorHighlights() { // 추적중인 방송id 목록을 조회 List activeStreamIds = streamProvider.getActiveStreamIds(); // 스트림을 사용하여 방송분석 로직을 비동기로 호출하기 위한 코드 // CompletableFuture을 통해 비동기 호출한뒤 // join을 통해 결과를 조합 List signals = activeStreamIds.stream() .map(id -> CompletableFuture.supplyAsync(() -> processStream(id), virtualThreadExecutor)) ..