전체 글 178

[Troubleshooting] 인텔리제이 의존성 인식 안됨, import 빨간 줄 해결 (Spring Boot 4)

상황 훑어보기Kafka와 Redis를 연습하려고 start.spring.io에서 Spring Boot 4.1.1 프로젝트를 만들고, 실습까지 한 후 이틀 뒤에 프로젝트를 열었다.그런데 프로젝트를 열자마자 클래스 파일이 빨간 줄 천지가 되었다.이상한 점은 같은 IntelliJ에서 다른 프로젝트(Spring Boot 3.5.6)는 멀쩡했다는 것이다.그래서 처음에는 "IntelliJ 캐시가 꼬였나? 싹 지우고 다시 깔아야 하나?"라고 생각했다.😭결론부터 말하면 원인은 IntelliJ 버전이 Spring Boot 4.1 프로젝트를 제대로 처리하지 못한 것이었고, IntelliJ를 업데이트해서 해결했다.오늘 글에서는 여기까지 오는 과정을 순서대로 정리해보려고 한다.항목내용잘 되는 프로젝트Spring Boot 3..

개발공부/SPRING 2026.09.30

Kafka 브로커 한 대를 중지하면? 리더 전환과 ISR 변화 관찰하기

Kafka는 데이터를 여러 브로커에 복제해 장애에 대비한다.그렇다면 실제로 브로커 한 대를 중지했을 때, 파티션과 복제본에는 어떤 변화가 발생하는지에 대해 실습을 해보기로 했다. 브로커 3대로 구성한 Kafka 환경에서 kafka-1을 중지하고, Kafka UI에 표시되는 order 토픽의 상태를 비교했다. 먼저 이번에 중지한 대상은 브로커 1이다.브로커는 파티션의 복제본을 저장하는 서버이며, 하나의 브로커에 여러 파티션의 복제본이 함께 존재한다.이번 환경에서도 브로커 1은 파티션 0·1·2의 복제본을 모두 가지고 있었다. 따라서 브로커 하나를 중지했지만 세 파티션 모두 영향을 받았다.1. 중지 전: 모든 복제본이 정상적으로 동기화된 상태order 토픽은 다음과 같이 구성되어 있었다.Number of P..

개발공부/Kafka 2026.09.25

Kafka가 필요한 이유와 핵심 개념 정리

기존 구조의 한계지금까지 배운 내용으로 기반으로 한 서버는 다음과 같은 구조였다.사용자 요청 → 서버 → DB/Redis 저장 / 조회이 구조는 평소에는 문제가 없지만, 트래픽이 갑자기 증가하면 세 가지 문제가 동시에 터진다.서버는 모든 요청을 "즉시" 처리해야 한다.요청량이 갑자기 증가해도 서버는 쉬지 않고 모든 요청을 즉시 처리해야 한다. 서버가 감당할 수 있는 범위를 넘어서면 장애로 이어진다.DB와 Redis는 동시에 많은 요청을 처리하지 못한다.트래픽 폭증은 다음과 같은 상황에서 자주 발생한다.대규모 세일 오픈인기 상품 재입고쇼핑몰 메인 배너 클릭 급증사용자 행동 데이터는 매우 빠르게 쌓인다.페이지 조회, 상품 클릭, 장바구니 추가, 구매, 스크롤 등 사용자 행동 로그는 실시간으로 쌓인다. 이 모..

개발공부/Kafka 2026.09.24

[Design]리프레시 토큰: 로테이션과 재사용 탐지를 선택한 이유

상황지금까지는 액세스 토큰 하나만으로 로그인을 구현했다.로그인에 성공하면 액세스 토큰을 발급하고, 이후 요청마다 그 토큰을 검증하는 단순한 구조였다.여기서 한 단계 업그레이드하고 싶어서 리프레시 토큰 도입을 알아보기 시작했다.그런데 찾아보다 보니, 리프레시 토큰을 붙이는 것 자체도 완전한 해법은 아니라는 이야기가 계속 나왔다. 리프레시 토큰이 탈취되면 액세스 토큰보다 훨씬 오래 살아있는 만큼 피해가 더 크고, 단순히 리프레시 토큰만 추가한다고 보안이 저절로 좋아지는 게 아니었다. 그래서 어떤 방식들이 있는지, 그리고 그 중 실무에서 실제로 쓰이는 조합이 뭔지 정리해보기로 했다.어떤 대안들이 있나?먼저 토큰 기반 인증에서 무엇을 절충해야 하는지 정리했다.JWT는 서버가 별도 저장소를 조회하지 않고도 서명과..

[Design]BCrypt 72바이트 제한: 비밀번호 검증이 바이트 단위여야 하는 이유

상황회원가입 로직은 비교적 간단하다고 생각이 들어서 후순위로 밀리기 쉬운 코드다.로그인, 비밀번호 찾기에 비하면 화려할 것도 없고, 이메일 형식과 비밀번호 길이 정도만 확인하면 끝이라고 생각하기 쉽다.그런데 비밀번호 필드 하나를 조금만 파고들면, 프레임워크 내부 동작과 실제 CVE까지 이어지는 이야기가 나온다는 사실을 알게 되었다.세 번째 줄, @Utf8ByteLength(max = 72)가 이 글의 주제이다.처음 봤을 땐 "회원가입 하나에 커스텀 어노테이션까지 굳이"라는 생각이 들기도 했지만... 파고들수록, 과한 설계가 아니라 정확히 필요한 만큼의 설계라는 생각이 들었다.72바이트라는 숫자의 정체는?72는 임의로 정한 값이 아니다.비밀번호 해싱에 흔히 쓰이는 BCrypt 알고리즘 자체가 입력을 72바..

Docker란? 왜 필요한지부터 VM 차이, 이미지·컨테이너·볼륨

Spring Boot 프로젝트를 만들었다면 내 컴퓨터에서는 IntelliJ의 실행 버튼만 눌러도 서버가 동작한다.그런데 이 프로젝트를 팀원의 컴퓨터나 배포 서버로 옮기면Java를 설치하고, 버전을 확인하고, MySQL을 준비하고, 실행에 필요한 설정도 맞춰야 한다.소스 코드는 Git으로 공유했지만, 그 코드를 실행할 환경까지 전달한 것은 아니기 때문이다.Docker를 이해하는 출발점은 여기에 있다. “코드뿐 아니라, 코드를 실행하는 환경도 함께 준비해서 전달할 수 없을까?”Git으로 같은 코드를 받았는데 왜 실행 결과가 다를까?쇼핑몰 프로젝트를 함께 개발한다고 가정해 보자. 모두 같은 코드를 내려받았지만, 각자의 컴퓨터 상태는 다를 수 있다.구분개발자 A개발자 BJava프로젝트에 맞는 버전다른 프로젝트에..

개발공부/Docker 2026.09.15

STOMP 채팅에 Redis Pub/Sub은 왜 필요할까? 단일 서버부터 다중 서버까지 이해하기

채팅 서버를 스케일 아웃했을 때 발생하는 메세지 전달 문제를 해결하는 방법 중 필요한 개념이 Redis Pub/Sub라는 것을 알게 되었다. Publisher가 Channel에 메시지를 발행하면 해당 Channel을 구독한 모든 Subscriber가 메시지를 받는다.하지만 STOMP에서도 이미 SUBSCRIBE와 메시지 전송을 사용하고 있기 때문에 다음과 같은 의문이 생긴다.STOMP도 구독이고 Redis도 구독이라면 둘은 무엇이 다른가?결론부터 말하면 두 기술은 서로 다른 구간을 담당한다.STOMP는 사용자와 Spring 서버 사이에서 메시지를 주고받기 위한 규칙이다.Redis Pub/Sub은 여러 Spring 서버가 메시지를 공유하기 위한 통신 방식이다.Redis Pub/Sub은 STOMP를 사용하기..

개발공부/WEB 2026.09.11

STOMP에서 JWT 인증은 어디서 해야 할까? CONNECT와 Interceptor 이해하기

채팅 메시지를 보낼 때 클라이언트가 다음과 같이 senderId를 함께 전달한다고 가정한다면{ "senderId": 1, "roomId": 10, "content": "안녕하세요"}서버가 이 senderId를 그대로 믿는다면 사용자는 값을 다른 회원의 ID로 바꿔 타인인 것처럼 메시지를 보낼 수 있다.클라이언트가 보낸 데이터는 언제든지 조작될 수 있으므로 발신자 정보는 메시지 본문이 아니라 서버가 검증한 JWT에서 찾아야 한다.HTTP API에서는 일반적으로 JWT를 Filter에서 검사한다. 그런데 WebSocket 위에서 동작하는 STOMP 메시지는 왜 Filter가 아니라 ChannelInterceptor에서 검사해야 할까?핵심은 HTTP 요청과 STOMP 메시지가 서로 다른 계층의 데이터라는..

개발공부/WEB 2026.09.10

OFFSET 페이징은 왜 느려질까? 커서 기반 페이징의 원리와 구현

게시글, 채팅 메시지, 알림처럼 데이터가 계속 쌓이는 서비스에서는 전체 데이터를 한 번에 조회할 수 없다.따라서 데이터를 일정한 개수로 나누어 가져오는 페이징이 필요하다.가장 익숙한 방법은 페이지 번호를 사용하는 OFFSET 기반 페이징이다. 구현은 간단하지만 데이터가 많아질수록 성능이 저하되고, 조회 도중 데이터가 추가되면 중복이나 누락이 발생할 수 있다.이러한 한계를 보완하기 위해 사용하는 방법이 커서 기반 페이징(Cursor-based Pagination)이다.OFFSET 기반 페이징의 동작 방식OFFSET 기반 페이징은 앞에서부터 일정한 개수의 데이터를 건너뛴 뒤 필요한 데이터를 조회한다.SELECT *FROM chat_messageORDER BY id DESCLIMIT 20 OFFSET 1000..

개발공부/JPA 2026.09.09

Spring Data JPA에서 조회 개수를 제한하는 방법: Pageable과 int 비교

채팅 기능을 구현하면서 최신 메시지를 일정 개수만 조회하기 위해 다음 코드를 사용했다.public List getRecentMessages(int size) { Pageable pageable = PageRequest.of(0, size); return repository.findRecentMessages(pageable) .stream() .map(ChatMessageResponse::new) .toList();}Repository는 다음과 같다.@Query(""" select m from ChatMessage m join fetch m.sender order by m.id desc """)List find..

개발공부/JPA 2026.09.08