목록전체 글 (253)
FireDrago
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개의 방송을 동적으로 인식하고, 자동으로 하이라이트 타임스탬프를 찍는 '치즈픽' 서비스를 배포했다.스트리머들의 채팅화력을 통해 하이라이트를 추출하는 알고리즘을 고도화하는 과정은 쉽지 않았다.실제 스트리머의 채팅화력과 노트북 lm을 통한 데이터 분석을 통해 알고리즘을 고도화한 과정을 정리했다. 절대값으로 하이라이트 판정 (V1)스트리머측정시간 (UTC)오프셋화력 (채팅 수)판정결과시라유키 히나2026-02-15 16:40:212418433417PEAK시라유키 히나2026-02-15 16:40:242418733432PEAK시라유키 히나2026-02-15 16:40:272419033416PEAK시라..
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)) ..
개인 프로젝트에서 Java 25 + Spring Boot 4.0.1 + Kafka 4.1.1이라는 가장 최신버전을 사용했다. 왜 최신버전을 신중히 도입해야 하는지 제대로 느꼈다. 이 조합에서, 예상치 못한 `NoClassDefFoundError`를 만나 몇일동안 디버깅을 해야했다. Kafka 4.x의 구조적 특징과 가상 스레드(Virtual Thread) 환경이 맞물려 발생한 문제를 해결해보자 문제 상황우선 치지직의 100개 이상의 방송 웹소켓 채팅을 동시에 연결하여 카프카로 전송하는 과정에서 발생한 문제이다. 가상 스레드를 활용하기 위해서 가장 최신 환경의 버전을 사용했다. - 언어 : java 25- 프레임워크 : Spring Boot 4.0.1- 메시지 큐 : Kafka Client 4.1.1 (S..
지난 1편에서는 수백 개의 동시 웹소켓 연결을 효율적으로 관리하기 위해 스프링 이벤트와 자바 가상 스레드를 도입한 과정을 소개했다. 이번 2편에서는 시스템의 안정성과 데이터 파이프라인의 완성도를 높이는 실전 구현 디테일을 다룬다. 불안정한 네트워크 환경에서도 데이터를 안정적으로 수집하고, 수집된 데이터를 안전하게 다음 단계로 전달하는 과정을 살펴보자. 1. 안정적인 연결 생명주기: 지수 백오프(Exponential Backoff) 재연결 전략실시간 데이터를 수집하는 시스템에서 가장 중요한 것은 '연결의 안정성'이다. 웹소켓 연결은 다양한 이유(일시적인 네트워크 단절, 서버 재시작 등)로 예기치 않게 끊어질 수 있다. 이때, 무작정 즉시 재연결을 시도하면 오히려 서버에 부담을 주거나 계속 실패할 수 있다...
실시간으로 다수의 치지직 방송 채팅을 분석하여 하이라이트 타임스탬프를 생성하는 서비스를 개발하고 있다. 이 프로젝트는 수시로 시작하고 종료되는 수백 개의 채팅 데이터를 누락없이 수집해야한다. 각 방송마다 독립적인 웹소켓 연결이 필요했기에, 동적인 커넥션 관리와 장애 복구 능력이 필요하다. 이 문제를 해결하기 위해 최신 JDK 25 버전과 가상 스레드(Virtual Threads)를 도입했다. I/O 대기가 긴 웹소켓 작업의 특성상, 기존 플랫폼 스레드 방식은 리소스 낭비가 심각하다. 가상 스레드는 적은 비용으로 수천 개의 동시 연결을 효율적으로 처리해 준다. 또한 이벤트 기반 아키텍처를 통해 모듈 간 결합도를 낮추고, Redis와 Kafka를 결합해 데이터 파이프라인을 구축했다. 대규모 실시간 수집 시스..
현재 상태를 읽고(Read), 이를 바탕으로 로직을 판단하여, 결과를 업데이트(Write)'하는 과정은 Redis를 사용할 때 매우 빈번하게 발생한다. 흔히 Redis는 싱글 스레드라 안전하다고 생각하기 쉽지만, 애플리케이션 레벨에서 여러 명령어를 조합하는 순간 데이터 정합성은 깨질 위험이 생긴다. 개인프로젝트 코드에서 원자성 문제를 리뷰받고 해결방법을 정리했다. 오늘은 Java 환경에서 발생할 수 있는 원자성 결여 문제를 살펴보고, `MULTI/EXEC 트랜잭션`과 `Lua 스크립트`를 비교하여, 상황에 맞는 해결책을 찾아보자문제코드 예시public void updateStreams(List newIds, Map newData) { // [1] 조회: 기존 목록을 가져옴 Set oldIds ..
spirng 7.0 (spirng-boot 4.0.1) 에서재시도 담당하는 기능이 변경됐다.재시도 `@Retryable` 에너테이션이 spring-core로 편입되었다.또한 기존의 `@Recover` 에너테이션이 삭제 되었는데 그 이유가 흥미로웠다. 1. Spring.core 패키지로 편입https://github.com/spring-projects/spring-framework/issues/34529 Introduce `@Retryable` AOP support (based on `core.retry` and Reactor retry functionality) · Issue #34529 · spring-projects/spThere have been several requests for retry fu..
