전체 글 61

[트러블슈팅] Redis 호출 5번을 Pipeline으로 1번에 끝내기

공고 상세 조회 API에서 Redis 명령을 개별로 5~6번 호출하던 구조를 Pipeline으로 개선한 과정을 정리해 보겠습니다.이전에 공식문서를 통해 Redis를 공부하고 있었을 때 Pipeline이라는 것을 알게 되었습니다 Redis 공식문서의 예제 코드는 다음과 같습니다 //pop a specified number of items from a queueList results = stringRedisTemplate.executePipelined( new RedisCallback() { public Object doInRedis(RedisConnection connection) throws DataAccessException { StringRedisConnection stringRedi..

캐시 3대 문제

최근에 레디스에 대해 정리하고 , 사이드 프로젝트에서 캐싱 관련 작업을 하던 도중 인사이트를 얻기 위해서 자료를 찾아보고 있었습니다. 자료를 찾아보니 흔히 캐시 3대 문제라고 하는 문제가 있습니다.그 종류는Cache PenetrationCache AvalancheHot Key Problem해당 내용을 정리해보고 싶어 글을 쓰게 되었습니다1. Cache Penetration (캐시 관통) Cache Penetration은 캐시를 아예 뚫고 지나가는 문제입니다.원래 캐시는 이렇게 동작해야 합니다.요청이 들어오면 먼저 캐시에서 찾고 → 있으면 캐시에서 바로 반환하고 → 없으면 DB에서 가져온 다음 캐시에 저장 근데 여기서 문제가 생깁니다. 만약 DB에도..

[트러블 슈팅] SOS 상세 조회 API의 Row Explosion 문제 해결

모든 연관 데이터를 단일 LEFT JOIN 쿼리로 조회하던 구조에서 OneToMany 관계인 SosImage를 별도 쿼리로 분리하여 Row Explosion 문제를 해결하고 조회 안정성을 확보했습니다.그 과정에서 알게 된 내용을 정리해 보겠습니다문제 상황SOS 상세 조회 API를 구현하면서 아래 모든 데이터를 단일 QueryDSL 쿼리에서 LEFT JOIN으로 한 번에 조회하도록 설계했습니다.Member 정보 (badge)ProfileImageBusiness 정보 (name, address)BusinessCodeSos 정보SosImage 리스트문제는 SosImage가 OneToMany 관계라는 점이었습니다. 이미지가 5개라면 결과 Row도 5개가 생성됩니다. 데이터는 하나인데 이미지 수만큼 행이 복제되는..

[트러블슈팅] getReferenceById를 이용한 연관 관계 저장 최적화

문제 상황특정 엔티티를 다른 엔티티의 외래 키(FK)로 저장할 때, 기존에는 findById를 사용하여 해당 엔티티를 DB에서 완전히 조회한 후 세팅하는 방식을 사용했습니다.를 사용하여 해당 엔티티를 데이터베이스에서 완전히 조회한 후 세팅했습니다. 하지만 단순히 연관 관계를 맺기 위해 전체 데이터를 SELECT 하는 것이 비효율적이라는 판단하에 리팩토링을 진행했습니다. java@Transactionalpublic void addFavorite(Long announceId, Long memberId) { Member member = memberRepository.findById(memberId) .orElseThrow(() -> new EntityNotFoundException()); ..

[트러블 슈팅]공고 상세 조회 API의 불필요한 DB 쿼리 줄이기

문제 상황공고 상세 조회 API에서 공고 상세 정보(Announce), 사용자의 즐겨찾기 여부(MemberFavorite), 제출 서류 목록(Document) 세 가지 데이터를 함께 반환해야 했습니다.초기 구현에서는 이 세 가지를 모두 개별 쿼리로 분리하여 조회했습니다. sqlSELECT * FROM announce WHERE announce_id = ?SELECT EXISTS ( SELECT 1 FROM member_favorite WHERE member_id = ? AND announce_id = ?)SELECT * FROM document WHERE announce_id = ?API 요청 한 건당 DB와 3번의 Round Trip이 발생하는 구조였습니다. 참고)사실 exist를 쓰는 것..

[JWT 트러블슈팅] 매 요청마다 DB 조회가 발생하는 문제와 해결 방법

문제 상황JWT 기반 인증을 구현하는 과정에서 모든 요청마다 DB 조회가 발생하는 구조로 구현되어 있었습니다.기존 인증 로직은 JWT 토큰에서 email을 추출한 뒤 UserDetailsService를 호출하여 사용자 정보를 다시 DB에서 조회하는 방식이었습니다. JWT를 사용하면서도 매 요청마다 DB 조회가 발생하여 JWT의 핵심 장점인 Stateless 구조를 전혀 활용하지 못하는 문제가 있었습니다.기존 코드 javaif (jwtService.validate(token)) { String email = jwtService.extractSubject(token); UserDetails user = userDetailsService.loadUserByUsername(email); Use..

[트러블슈팅] @OneToOne(mappedBy) LAZY 로딩이 동작하지 않는 이유와 해결 방법

문제 상황회원가입 및 로그인 기능을 구현하던 중 memberRepository.findMemberByEmail() 메서드를 호출했을 때, 조회하지 않은 연관 엔티티의 쿼리까지 함께 실행되는 문제가 발생했습니다.단순히 Member만 조회했지만 실제로는 다음과 같은 SQL이 실행되었습니다. sqlSELECT * FROM member WHERE email = ?SELECT * FROM business WHERE member_id = ?SELECT * FROM profile_image WHERE member_id = ?SELECT * FROM auth WHERE member_id = ? @OneToOne(fetch = FetchType.LAZY)로 설정했기 때문에 연관 엔티티는 실제 접근 시점에 Lazy Lo..

[트러블슈팅] JPA Cascade와 Aggregate Root 적용하기

회원가입 기능을 구현하면서 여러 엔티티가 함께 생성되는 구조를 설계하게 되었습니다.처음에는 각 엔티티를 개별 Repository를 통해 저장하는 방식으로 구현했지만 이 방식은 JPA를 사용하면서도 ORM의 장점을 제대로 활용하지 못하는 구조였습니다.이번 글에서는 회원가입 로직을 Cascade와 Aggregate Root 개념을 활용하여 개선한 과정을 정리해보려고 합니다. 문제 상황회원가입 시 다음과 같은 여러 엔티티가 함께 생성되었습니다.MemberProfileImageAuthBusinessBusinessCode 기존 구현에서는 이렇게 필요한 각 엔티티를 Repository를 통해 각각 개별적으로 저장하였습니다.코드를 보면 아래와 같습니다 기존 회원가입 로직@Transactionalpublic Long..

Spring에서 Redis 쉽게 사용하는 방법 정리 -활용

Spring은 Redis를 편하게 사용할 수 있도록다양한 추상화와 기능을 제공합니다.즉 단순 Redis Client 수준이 아니라Template 패턴Cache 자동 처리메시징 지원Reactive 지원까지 제공하여Redis를 매우 쉽게 사용할 수 있는 환경을 만들어 줍니다.이번 글에서는실무에서 자주 사용하는 기능만 핵심 위주로 정리해 보겠습니다 Spring에서 Redis 쉽게 쓰게 해주는 핵심 기능RedisTemplateStringRedisTemplateSpring Cache abstractionRedis RepositoryMessage Listener (Pub/Sub)Reactive Redis 1. RedisTemplate (가장 핵심)Spring Redis의 중심 클래스입니다.Redis 명령어를 Jav..

Spring Data Redis 공식문서로 내부 동작 이해하기

Spring Boot에서 Redis를 사용할 때 우리는 보통 아래처럼 아주 간단하게 사용한다.stringRedisTemplate.opsForValue().set("user", "donguk"); 하지만 이 한 줄 뒤에서는 생각보다 많은 계층과 추상화가 동작하고 있다.이 글에서는 Spring Data Redis 공식 문서 기반으로RedisTemplate 내부 동작Lettuce의 역할RedisConnection 추상화StringRedisTemplate 차이HashMapper 동작Redis 트랜잭션 구조Spring Boot Auto Configuration까지 전체 흐름을 깊게 정리해 본다. 참고 : https://docs.spring.io/spring-data/redis/reference/ Spring Da..