[TroubleShooting] PDF 프리뷰시 자동 다운로드 현상 해결하기
·
만들어보기/TroubleShooting
개요현재 인턴 중인 곳에서 기존 1차 개발이 되어있던 프로젝트를 보수하고, 새로운 기능을 추가하여 정식 배포를 준비 중에 있다.그 중 QA 결과로 PDF 프리뷰를 제공하는 페이지에 진입 시 해당 PDF가 자동 다운로드 되는 현상이 발견되어 해결을 요청 받았다.확인해본 결과 문제 상황은 다음과 같았다.상세 페이지에서 html `` 태그로 pdf 프리뷰 제공 중일부 pdf를 대상으로 프리뷰가 성공적으로 렌더링 되지 않고, 자동 다운로드 되는 문제 발생원인 분석현재 프리뷰를 제공 대상인 pdf는 사용자가 서비스 내에서 업로드한 pdf로, CDN에서 제공하는 url을 사용하여 가져온다.프리뷰에 성공하는 pdf와 실패하는 pdf의 CDN url로 curl 명령어을 통해 응답 헤더를 확인해보았다.curl 명령어를 ..
[SpringBoot] SQS 메시지 발행 병목 @Async + Executor로 해결하기
·
만들어보기/TroubleShooting
☑️ 문제 정의 : 비동기처럼 보이는 동기 처리현재 우리 시스템의 알림 전송은 SQS 기반 Outbox 패턴을 따르고 있다.알림이 필요한 이벤트가 발생하면 다음과 같은 흐름으로 메시지가 처리된다.알림 정보를 Notification 테이블(사용자 조회용)과 Outbox 테이블(메시지 발행용)에 저장저장된 메시지를 SQS에 발행SQS 소비자가 메시지를 받아 실제 사용자에게 알림 전송알림 전송은 구조적으로 비동기처럼 보이지만, SQS로 메시지를 발행하는 로직만은 동기적으로 동작하고 있었다.이로 인해 대규모 알림 발송 시 병목이 발생할 수밖에 없는 구조였다.▶︎ 단계별 병목 지점 정리병목이 예상되는 지점은 다음과 같다.알림 데이터를 DB에 저장할 때메시지를 SQS로 발행할 때알림을 사용자에게 전송할 때단계처리 ..
[Springboot] AWS SQS를 이용한 알림 시스템 구현하기 - 메시지 발행 로직
·
만들어보기/Spring
서론기존에는 Spring의 `ApplicationEventPublisher`와 Redis의 Pub/Sub 구조를 활용해 알림 기능을 구현하고 있었다.이 구조는 내부 서버간 이벤트 전파와 브라우저 클라이언트로의 SSE 알림 전송에 효과적이었지만, 알림 수가 많아질수록 처리에 병목이 생길 수 있으며 실패시 재처리가 어렵다는 문제가 있었다.이러한 한계를 해결하고자 AWS SQS를 도입하여 알림 시스템을 재구성하게 되었다. 이 글에서 구조 설계, 고민했던 부분들과 해결 방안을 중심으로 알림 시스템 전환 과정을 정리하고자 한다.SQS를 도입하게 된 이유기존에는 웨이팅 호출 시 해당 웨이팅의 사용자에게 알림을 보내는 기능만 있었지만, 이후 쿠폰 이벤트가 시작되면 해당 가게를 찜한 사용자 전체에게 알림을 발송해야 하..
[AWS] AWS SQS(Simple Queue Service) 이해하기
·
공부하기/Cloud
AWS SQS란?Simple Queue Service로, AWS에서 서비스하는 메시지 큐이다.메시지 큐를 왜 사용할까?하나의 API 요청에 동시에 수행되는 후처리 작업들이 많은 경우 ⇒ 응답 지연 최소화 및 시스템 간 결합도 감소 가능문제 상황응답 지연 문제 : API 내부에서 동기로 처리한다면 응답 대기 시간이 증가함 → UX 저하장애 전파 위험 : 외부 API 호출이 포함되는 경우, 서비스 하나에 장애가 나도 전체 기능 장애로 이어질 가능성이 높음해결한 API는 관련 작업만 처리하고, 동반되어야 하는 각 작업을 메시지로 만들어 큐에 넣음각각의 작업을 담당하는 Consumer가 큐에서 메시지를 비동기적으로 소비하여 처리함효과고객의 응답 대기 시간 감소후처리 시스템에 장애가 나도 메인 작업 자체는 정상 ..
실시간 데이터 전송 기술 정리 | Polling, Long-Polling, SSE, WebSocket
·
공부하기/ETC
최근 실시간 알림 기능을 구현하면서 공부했던 실시간 데이터 전송에 대표적인 기술들을 정리해본다.1. Polling주기적으로 서버에 요청을 보내 업데이트를 확인하는 방식클라이언트에서 서버로 계속해서 request를 전송한다.서버는 반복되는 request에 응답하면서, 전달할 이벤트가 있는 경우 전달한다.▶︎ 장점구현이 간단하다. (기본 HTTP만 지원되면 구현 가능)▶︎ 단점불필요한 요청이 많아지므로 서버 부하가 증가한다.새 이벤트가 발생하자마자 확인할 수는 없어 지연(Latency)이 존재한다.다수 클라이언트가 있을 경우 네트워크 오버헤드가 증가한다.매우매우 간단하게 실시간 (비슷한) 서비스를 구현해볼 수 있는 방식 2. Long Polling클라이언트가 서버에 요청을 보내고, 서버는 새로운 데이터가 있..
[Spring] DI와 IoC 이해하기
·
공부하기/Spring
DI 적용 전 객체 사용 방식DI 개념을 적용하기 전에는 객체 사용 시 어떤 방식을 사용했을까?1. 직접 객체 생성사용하려는(=의존하려는) 객체를 ``new`` 생성자를 통해 직접 생성한다.public class CafeController { private StarbucksService starbucksService = new StarbucksService(); public void orderCoffee() { starbucksService.brew(); }}이러한 방법은 객체간 결합도가 강하다는 단점이 있다. 만일 스타벅스가 부도가 나서 서비스를 스타벅스가 아닌 팀홀튼으로 바꿔야 할 경우 (ㅎ) CafeController 내부의 코드를 직접 수정해야 한다.StarbucksService를 사용하고 있..
[SpringBoot] 파일 업로드를 위한 MultipartFile의 처리/동작 방식
·
공부하기/Spring
Spring에서는 ``MultipartFile`` 인터페이스를 통해 파일 업로드 기능을 간편하게 구현할 수 있다.1. Multipart Upload란?이미지, 영상, 문서 등의 바이너리 데이터를 업로드하기 위한 HTTP 요청 방식이다.요청의 ``Content-Type``은 ``multipart/form-data``로 지정되며,데이터는 요청 본문(Body)에 다음과 같이 구성된다.Header : Content-Type, 필드 이름 등 메타데이터Body: 실제 데이터 (파일, 폼 필드 값 등)Multipart Upload 요청 예시POST /upload HTTP/1.1Content-Type: multipart/form-data; boundary=----WebKitFormBoundary------WebKitF..
[SpringBoot] SSE를 이용한 실시간 알림 전송 구현기 (feat. Redis Pub/Sub)
·
만들어보기/Spring
1. 들어가며음식점 웨이팅 프로젝트를 진행하면서, 사용자의 웨이팅이 호출되었을 때 실시간 알림을 전송해야 했다.알림을 전송하는 기능은 처음 구현해보았기에 기록해본다.2. 기술 선택 배경▶ SSE + Redis Pub/Sub 조합을 선택했다, 그 이유는?다음과 같이 적용 가능한 다양한 기술들을 비교해보았다.기술설명장점단점프로젝트 기준 평가SSE서버 → 클라이언트 단방향 스트리밍 (HTTP 기반)구현 간단, 브라우저 지원, HTTP 기반이라 인프라 변경 최소양방향 불가, 커넥션 관리 필요 (브라우저마다 약 6개)✅ 현재 단방향 알림 구현 중이므로 적합함웹소켓서버 ↔ 클라이언트 양방향 실시간 통신강력한 실시간성, 양방향 가능, 낮은 지연인프라 구성 부담 (로드밸런서 설정 필요 등), 연결 유지 비용 ↑단방향 ..
[TroubleShooting] MySQL 락을 건 적이 없는데 데드락이 발생한다
·
만들어보기/TroubleShooting
배경동시성 제어 로직을 추가하기 전에, 티켓팅 프로젝트에서 다수의 사용자가 동시에 같은 좌석을 예매하는 상황을 테스트하기 위해 테스트 코드를 짰다.해당 테스트는 다음 목표를 가지고 있었다.동시성 제어 없이 중복 예매가 발생하는지 검증분산 락 없이 JPA 트랜잭션만으로는 안전하지 않다는 것을 검증이에 따라 n명의 유저가 하나의 좌석을 동시에 예매하는 시나리오를 구현했다.예상 결과테스트의 예상 결과는 다음과 같았다.아직 락을 걸지 않았기 때문에 티켓이 여러 개 생성되어 테스트가 실패해야 한다.즉 하나의 ``200 OK`` 응답과 n-1개의 ``400 BAD REQUEST`` 응답이 반환된다.하지만 ... 실제 결과실제 결과는 전혀 다르게 나왔다.실제로 생성된 티켓은 1개 뿐이었다.하나의 ``200 OK`` ..
[SpringBoot] AWS S3를 이용한 프로필 이미지 업로드 로직 구현기
·
만들어보기/Spring
1. ProfileImage 설계사용자는 하나의 프로필 사진을 갖는다. → OneToOneProfileImage에서 사용자를 참조할 일은 없다 → 단방향S3에서 객체를 삭제하기 위해서는 버킷에 저장된 이름이 필요하다.S3에서 제공하는 객체 url로 이미지에 접근한다.``객체 url``과 함께 저장할 ``버킷에 저장된 이름`` 정보가 필요하므로 해당 정보를 담은 테이블을 추가하기로 결정했다.✓ ProfileImage 엔티티다음과 같이 ProfileImage 엔티티를 추가해주었다.@Getter@Entity@NoArgsConstructor@Table(name = "profile_images")public class ProfileImage { @Id @GeneratedValue(strategy = G..
[Network] HTTP 응답 상태 코드
·
공부하기/Network
🌀 HTTP 응답 코드에 대해 설명해 주세요.클라이언트가 보낸 HTTP 요청이 성공적으로 완료되었는지 알려주는 코드이다.3자리 숫자로 이루어져 있으며, 100번대 ~ 500번대 까지 존재한다.코드의 첫 번째 자리에 따라 5개의 그룹으로 나뉜다.코드의미1xx정보 제공 응답, 요청 처리 중2xx성공, 요청 정상 처리3xx리디렉션, 요청 완료를 위해 추가 작업 필요4xx클라이언트 오류, 요청이 잘못됨5xx서버 오류, 서버측에서 오류 발생 💬 200(ok)와 201(created)의 차이에 대해 설명해 주세요.200(ok) : 요청이 정상 처리 되었을 때 범용적으로 사용201(created) : 요청이 정상 처리 되었으며, 그 결과 서버에서 새로운 리소스를 생성했을 때 사용일반적으로 POST 요청 성공 시 ..
Unique한 값이 필요할 때 사용하는 UUID, UUID란?
·
공부하기/ETC
🏷️ UUID (Universally Unique Identifier)이름 그대로 UUID는 전세계적으로 고유한 식별자이다. 이론상으로 중복될 가능성이 거의 없기 때문에 데이터베이스에서 고유한 값을 보장하는 데 매우 유용하게 사용된다.128비트 길이의 값이다.보통 8-4-4-4-12 형태의 36자 문자열로 표현된다. (ex. ``550e8400-e29b-41d4-a716-446655440000``)▶︎ 장점데이터의 고유성을 보장한다.서버간 동기화 없이도 고유한 ID를 생성할 수 있으므로 분산 시스템에 적합하다. ▶︎ 단점길이가 길어 저장 공간을 많이 차지한다. (128비트 = 16바이트 = 문자열로 36자)DB에서 인덱싱 효율이 낮을 수 있다.UUID는 무작위성을 기반으로 생성되기 때문에 순차적인 값이..