Spring 이벤트와 핸들러 패턴으로 유연한 FCM 알림 시스템 구축하기
·
백엔드
1. 다양한 알림 저희는 서비스 간 강한 결합 문제를 해결하기 위해 Spring의 내장 이벤트를 도입했습니다. 이벤트 기반으로 전환하면서 서비스 간 의존성은 낮아졌지만, 알림이라는 또 다른 복잡한 요구사항에 직면하게 되었습니다.저희 스터디 플랫폼에서는 정말 다양한 종류의 알림이 필요했습니다.새로운 채팅 메시지가 도착했을 때내가 만든 스터디에 누군가 참여 신청했을 때내 신청이 수락/거절되었을 때스터디 규칙이나 공지사항이 변경되었을 때등등이 모든 알림은 각기 다른 내용, 다른 수신 대상, 그리고 알림 클릭 시 이동해야 하는 링크나 앱에서 처리해야 할 추가 데이터를 가집니다.만약 이 모든 알림 발송 로직을 하나의 NotificationService 같은 곳에서 if/else나 switch로 분기 처리한다면, ..
Spring Boot 비동기 S3 파일 업로드 구현기 (Transfer Manager + 이벤트 + 임시저장)
·
백엔드
1. 파일 업로드, 쉽지 않았던 이유저희가 만들던 스터디 플랫폼에서는 스터디 자료를 공유하거나, 스터디 모집 글에 이미지를 첨부하는 등 다양한 파일 업로드 기능이 필수적이었습니다. 처음에는 단순하게 구현했지만, 프로젝트가 고도화되면서 몇 가지 해결해야 할 과제들이 생겼습니다.대용량 파일 처리 문제: 스터디 자료 같은 경우 파일 크기가 클 수 있는데, 동기 방식으로 S3에 업로드하면 요청 스레드가 응답을 받기까지 오랫동안 대기해야 했습니다. 이는 시스템 전체의 성능 저하로 이어질 수 있는 문제였습니다.강한 의존성 문제: 파일 업로드가 끝나면 DB에 파일 정보를 저장하고 사용자에게 알림도 보내야 했습니다. 초기에는 파일 업로드 로직 내에서 NotificationService나 StudyMaterialServ..
Spring Boot 서비스 강한 의존성 탈출 : Spring 내부 이벤트 기반 아키텍처 도입
·
백엔드
이 글을 쓰는 이유프로젝트가 진행되며 서비스가 점점 고도화 되었습니다. 이런 과정에서 여러 서비스 간의 강한 의존성이 만들어지게 되었습니다. 특히 저희 프로젝트는 Study라는 핵심 도메인을 기준으로 스터디 rule, curriculum, file, applyQuestion 등 다양한 하위 도메인과 연결되어 진행되는 작업이 많았습니다. 이외에도  특정 도메인 처리 후부가적인 작업(알림 발송, 인기글 점수 업데이트, 비동기 파일 업데이트)이 필요해졌는데 기존 초기 작업에서는 이를 직정 해당 서비스를 의존 관계 주입 받아 메서드를 직접 호출하는 방식으로 이루어졌습니다.이렇게 서비스 간의 강한 의존성이 생겼을 때 다양한 문제가 발생합니다.1. 순환 참조2. 테스트의 어려움3. 책임 분산 모호4. 변경의 어려움..
스프링 제네릭 이벤트와 타입 소거: ResolvableType으로 해결하기
·
트러블 슈팅
배경프로젝트를 진행하며 작업이 고도화 될 수록 클래스 간 의존성이 점점 강해졌다. 그러다보니 클래스가 상호 의존 관계를 갖는 순환 참조 문제가 발생했다. 특정 메서드에서 연관 작업 수행을 위해 다른 서비스의 메서드를 호출하는 과정이 빈번해졌는데, 예를 들어 인기글 순위 갱신의 경우 게시글의 조회, 좋아요, 지원, 삭제 등에 따라 인기글이 서비스를 각 메서드에서 직접 호출하며 인기글 업데이트를 진행하는 등으로 인해 다음과 같은 문제들에 직면하게 되었다.강한 결합도순한 참조테스트의 어려움단일 책임 원칙 위배 가능성따라서 이 문제를 해결하기 위해 이벤트 기반으로 다양한 로직을 처리하는 것을 고민하게 되었다. 이벤트 기반으로 로직을 설계며 다음과 같이 관련 클래스를 정의했다.EventEventTypePayloa..
Redis SortedSet을 사용한 인기글 구현
·
백엔드
많은 커뮤니티가 인기글 서비스를 제공한다.내가 진행하는 프로젝트에서도 당연히 인기글 서비스를 제공하는데, 인기글 서비스를 구현한 방법을 공유한다. 인기글을 구현하는 방법은 되게 다양하게 구현할 수 있다.이때 우리 서비스에서는 하루 단위로 인기글을 인기글을 초기화 한다는 요구 명세가 존재했다. 또한 프로젝트에서 인기글을 계산하는 방식은 조회수, 좋아요, 스터디 지원이 발생했을 때 해당 이벤트에 따라 가중치를 주는 방식으로 인기글 점수를 업데이트 하도록 하였다. 인기글 점수 업데이트 시점1. 조회 발생(어뷰징 제외 실제 조회)2. 좋아요 발생(+)3. 좋아요 취소(-)4. 스터디 지원(+)5. 스터디 지원 취소(-)6. 글 삭제(인기글 목록에 존재하면 삭제) 이외에도 인기글 갱신 방식은 변경될 수 있기에 추..
Redis + Ip 기반 조회 수 어뷰징 방지
·
백엔드
프로젝트를 진행하며 조회 수 어뷰징 방지 기능을 개발한 경험을 공유하고자 한다. 배경현재 내 프로젝트에서는 특정 게시글을 조회할 때 발생하는 조회 수를 사용하여 인기글을 구현하고 있다. 따라서 조회 수 어뷰징은 큰 문제가 될 수 있다. 때문에 조회 수 어뷰징을 막기 위한 방법을 고민했고 그 결과 IP를 Redis에 특정 시간 동안 저장해두고, 해당 시간 내에 조회 요청이 발생했을 경우 조회수를 업데이트 하지 않는 방식으로 구현했다. 이외에도 많은 조회수 어뷰징 방지 방법이 존재했는데 다음과 같은 이유로 기각하게 되었다.1. 쿠키 : 조회 수 어뷰징 방지 쿠키를 만들고, 이를 통해 검증하는 방식이다. 하지만 이는 어뷰징 방지 하나를 위해 네트워크 전송 시 데이터 크기가 더 커질 수  있으며, 무엇보다 사용..
Jpa 테스트 시 TransactionRequiredException 발생과 해결
·
트러블 슈팅
배경조회 수 증가 로직을 개발하고 동시성 문제와 성능을 측정하기 위해 멀티 쓰레드 기반으로 테스트를 진행했다.이때 내가 작성한 쿼리를 실행하니 TransactionRequiredException 문제가 발생했고, 이를 해결한 과정을 공유하려고 한다. 먼저 조회 수 증가에서 동시성 문제를 해결하기 위해 다양한 방법이 있지만, 나는 원자성 쿼리를 통한 비관적 락을 사용했다.원자성 쿼리를 사용한 비관적 락 적용 시 낙관적 락과 비교하여 성능 테스트 결과 차이가 없다라는 결론을 얻었기 때문이다.  따라서 이와 같은 원자성 쿼리를 작성했다. 문제 int numberOfThreads = 100; ExecutorService executorService = Executors.newFixedT..
목록 조회 시 페이징 쿼리 최적화를 통한 최소 10배 성능 개선
·
백엔드
여러 데이터를 목록 조회 시 페이징 쿼리를 작성하여 데이터를 쿼리하는 작업을 진행했다.나의 경우 게시글 목록을 불러오는데, 이때 커버링 인덱스를 활용하여 페이징 쿼리 최적화를 통해 성능을 개선했던 방법에 대해 작성해보려 한다. 배경위와 같이 메인페이지에서 스터디 목록을 조회할 수 있어야 한다.이때 스터디 목록 조회 시 다양한 필터링(카테고리, 진행 방식, 모집 방식, 모집 여부, 좋아요 등)이 있을 수 있으면 가장 최신 순으로 데이터가 보여져야 하는 흔한 페이징 쿼리가 필요했다. 초기 구현 - 단순 페이징 쿼리페이징 쿼리를 작성할 때, 여러 필터 옵션들에 대해 동적으로 쿼리를 생성해야 했다. 이때 여러가지 방법이 있겠지만, 타입 안정성을 보장 받을 수 있는데 QueryDsl을 선택하여 구현했다.방식은 ..
SpringBoot 버전 업에 따른 RestClient 에러 발생 해결
·
트러블 슈팅
좋아요 구현 시 동시성 문제를 해결하기 위해 비관적 락과 낙관적 락을 테스트하던 도중 문제가 생겼다.기존 SpringBoot3.3 (Spring Framework 6.0.x) 버전에서는 정상 작동 되는 코드가 SpringBoot 3.4 (Spring Framework 6.1.x) 버전에서는 정상 작동하지 않고, 추가적인 설정이 필요해졌기 때문이다.상황낙관적 락에서 좋아요 요청 시 처리에 대한 테스트를 RestClient를 사용하여 진행했다.테스트 상황은 ThreadPool에 100개의 Thread를 만들어놓고, 해당 쓰레드를 사용하여 비동기 처리로 총 3000번의 좋아요 요청을 보내도록 했다.// 테스트 @Testvoid likePerformanceTest() throws InterruptedExcept..
스터디 관련 사이트 프로젝트 초기 구상 (Svelte)
·
프로젝트
프로젝트 기획 이유평소에 공부를 할 때, 혼자서 공부하면 아무래도 꾸준히 적당한 진도를 유지하며 공부하는 것이 어렵기 때문에 스터디를 자주 진행하는 편이다.스터디를 진행하는 방식은 보통 인프런이나 홀라에 글을 올려서 모집을 진행하는데, 전체적인 흐름은 다음과 같았다. 홀라 또는 인프런에 스터디원 모집 글 게시오픈 톡방 또는 Google form으로 지원 접수를 받는다.이후 승낙 여부를 전달 후 디스코드와 노션 링크 공유디스코드에서 화면 공유하며 스터디 진행공지 및 회의록 등 기록을 노션 페이지를 통해 공유이러다 보니 스터디 하나를 진행하기 위해 계속 인프런, 홀라, 카톡, 노션, 디스코드 등 다양한 서비스를 계속 돌아다니며 사용해야만 했다. 또한 스터디장으로 스터디를 진행을 많이 하다 보니 스터디원 관리..