Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

피드백

Git Merge 전략

Squash Merge

  • 설명: 브랜치의 모든 변경 내역을 하나의 커밋으로 압축하여 병합합니다.
  • 장점: 히스토리가 간결해지고, 불필요한 커밋을 제거할 수 있습니다.
  • 단점: 개별 커밋 히스토리가 사라지므로 디버깅에 어려움이 있을 수 있습니다.

ReservationService

Create

메소드에서 너무 많은 기능을 담고있음

함수의 역할이 뭔지 불분명함

알림을 create에서 보낼 필요가 없다 → 어차피 비동기라 관리가 안되는데 왜 포함되어 있는가?

create가 아니고 역할에 맞는 이름이 있을 것 같다

직관적인 느낌을 줘야하는데 어디서 어디까지가 뭘 하는 코드인지가 이해가 안됨

추상화를 한번 더 하는게 좋을 것 같음(관점의 차이니까 고민해볼 것)

Static MAX_SEATS

4매까지 예매가능 이런 숫자 전부 상수처리

이런 것들이 쌓이면 다른 개발자에게 설명을 하는데에 내 시간을 써야함

ERD Convention fix

카멜, 스네이크 표기법 혼용되어 있음

마인드

내가 어떤사람인지

회색 영역을 찾아가면서 일하는 사람인지

분업화된 각자 업무에 초점이 맞는 대기업형 사람인지

자기 마음속의 최저점을 인지할 것

싫어하는 것과 하고싶은 것, 도달하고 싶은 목표, 싫어도 할 수 있는것

TossPayments

클라이언트키가 왜 멱등해야 하는지

A대한 요청을 보내야하는데 이게 왜 유니크 해야하는지

→ 중복결제 요청이 들어갈 수 있기 때문입니다

저장하는 정보 시큐어코딩

정산을 고민해 보세요

ISMS 시큐어코딩 찾아볼것!

DTO

Request와 DTO 네이밍의 충돌

기능이 추가되면 dto가 너무 많아지지 않는가?

Test Code

리팩토링하면서 테스트가 깨지면 안된다!

“구현 세부사항이랑 결합하지 말라”

객체지향 SOLID원칙과 연관지어 수정하지 말고 확장하라~

내부로직에 관계없이 테스트 코드가 깨지지 않도록!

Mail

500에러 발생시

계속 재시도 하는 로직 몇번 시도 할건지도 생각해야함

재발송 시간대에 다시 시도 하거나

하는 방법 등을 생각해봄

뭔가 실패했을 때 재시도하는 로직이 필요

이게 과도하게 실행될 수도 있으니까 백오프 전략이 필요하다

이런것들을 고민을 해보세요

image

🎫 TICKET BLUE

공연 등 다양한 문화 및 엔터테인먼트 이벤트의 티켓을 온라인으로 예매할 수 있는 서비스

🚀 Infra Architecture & STACK

[ STACK ]

Development & Communication

IntelliJ Gradle GIT GitHub gitignore

Jira zoom Slack Notion

Frameworks & Languages

SpringBoot SpringBatch Java

Data & Monitoring

MySQL Redis Elasticsearch prometheus grafana

Deployment & Operations

AWS docker jenkins logstash kibana

API & Testing

swagger Postman sonarqube sonarLint

[ ERD ]

ERD

[ Infra ]

Infra

⚽ Goals

[ 사용자 편의기능 최적화 ]

  • Elasticsearch 도입으로 검색 속도 50% 이상 향상
  • Redis caching 도입으로 검색 속도 50% 이상 향상

[ Spring Batch ]

  • Spring Batch로 대용량 데이터 처리
  • JDBC Bulk Insert 방식으로 70% 속도 개선

[ 이중화 DB ]

  • DB 이중화로 부하 방지 및 데이터 안정성 보장
  • 에러율 0%를 목표로 이중화 환경 구성

🔍 Main Features

[ Admin ]

  • 관리자 전용 계정으로 가입
  • 포스터 파일을 첨부하여 공연을 등록하고 관리 (이미지는 AWS S3에 저장)
  • 공연장, 출연자, 공연에 대한 회차, 쿠폰 등록 및 관리
  • 공연에 출연하는 출연자 등록 및 관리
  • 조건에 따라 사용자 예매내역을 검색 (특정 공연에 대한 예매 내역 등) - Elasticsearch

[ Admin - Spring Batch ]

  • OldUsers - 휴먼계정 처리
  • OldUsersAlert - 휴먼계정 대상자 알림
  • OldPerformances - 오래된 공연 정보 삭제
  • TimeoutReservation - 기간 만료 예매 취소처리
  • UpcomingReservationAlert - 관람일 알림
  • ReservationReviewAlert - 관람평 작성 유도 알림
  • Spring Batch Application GitHub 바로가기

[ Search ]

  • 키워드를 입력하여 한번의 검색으로 공연장, 출연자, 공연 모두 조회 가능 - Elasticsearch
  • 사용가능한 쿠폰, 전체 공연, 배우, 공연장 등 조회
  • Redis Caching 기능을 적용하여 재검색시 빠른 응답속도를 제공
  • 원하는 공연회차의 잔여좌석을 조회

[ Reservation ]

  • 원하는 공연회차의 좌석을 지정하여 예매
  • 예매에 대한 결제, 결제취소 기능 (토스페이먼츠 API)
  • 예매, 결제 시 Slack, SSE 알림과 Mailing 서비스 제공

🌟 Key Summary

[ JPA → Elasticsearch 검색 속도 개선 ]

상세보기

JPA → Elasticsearch 검색 속도 개선

[ Spring Batch JPA -> JDBC ]

상세보기

Spring Batch JPA -> JDBC

🔥 Technical Enhancements

[ Swagger ]

상세보기
[내가 구현한 기능]

- API 테스트 도구 Swagger

[주요 로직]

- SwaggerConfig에서 기본 정보, 보안 스키마 등을 구성
- @Schema 사용하여 Sample Date Setting
- ResponseDto를 자동으로 인식할  있도록 inner Class 제거

[배경]

- 기존 사용하던 Postman은 HTTP Method, URL, port 등을 모두 직접 입력하여 테스트 하는 방식으로 사용자의 오류로 인한 에러가 발생할  있음

[요구사항]

- API 자동 문서화 기능 구현
- Swagger UI를 통해 API를 테스트할  있는 환경 제공
- API 명세 업데이트 , 코드 변경 사항에 따라 문서 자동 갱신

[선택지]

- Swagger
- PostMan

[의사결정/사유]

- Controller에 작성한 RESTful API 자동 문서화
- API 요청에 필요한 파라미터  요청 형식을 명확히 표기

[회고]

- PostMan에서 사용했던 API Document를 생성할 수는 없음
- 개발 과정에서 훨씬  효율적인 방식으로 API 테스트 가능
- https://everyday-spring.com/625

[ AWS S3 File Upload ]

상세보기
[내가 구현한 기능]

- 공연 등록  포스터 파일을 입력받아 S3 Bucket에 업로드
- 공연 삭제시 S3 Bucket의 포스터 파일도 함께 삭제
- 포스터 수정  S3 Bucket의 기존 이미지 삭제  새로운 이미지 등록

[주요 로직]

- MultipartFile을 사용하여 클라이언트로부터 파일 입력
- AWS SDK의 AmazonS3 클라이언트를 활용하여 S3 Bucket에 파일 저장
- 파일 이름 충돌 방지를 위해 고유 식별자(UUID) 파일 이름에 추가

[배경]

- 효율적인 파일 관리: 로컬 서버에 파일을 저장하면 확장성과 보안 측면에서 한계가 있음
- 클라우드 스토리지 활용: AWS S3는 고가용성과 비용 효율적인 스토리지 서비스를 제공

[요구사항]

- 업로드된 파일이 S3에 저장되었음을 확인할  있는 URL 반환
- 공연 삭제  관련 포스터 파일도 S3에서 삭제
- 파일 사이즈 제한

[선택지]

- AWS S3
- 로컬 파일 시스템
- AWS S3 Presigned URL
        
[의사결정/사유]

- 로컬 저장 방식에 비해 확장성과 데이터 보존성이 뛰어남
- 파일 업로드와 삭제가 비교적 간단하며, AWS SDK로 손쉽게 관리 가능

[회고]

- 소스 코드 내에 AWS IAM 계정의 보안키 정보를 포함하여 push가 불가능한 상황이 발생했음
- 보안 키에 대한 관리의 중요성을 한번더 확인함

[ Toss payments 결제 API 연동 ]

상세보기
[내가 구현한 기능]

- Toss Payments API를 이용한 결제시스템 구축

[주요 로직]

- Toss Payments 템플릿을 활용하여 결제 시스템 구축
- 데이터 무결성 검증
  - 결제 요청  주문 ID와 가격을 서버에 임시 저장
  - Toss Payments로부터 반환된 데이터와 비교하여 데이터 위조  변조 방지

[배경]

- 예매 서비스 특성상 결제가 완료되어야만 예약이 확정되므로 결제 시스템 필요

[요구사항]

- 다양한 결제 수단을 지원할 
- 결제 과정에서의 위조, 변조를 방지하기 위해 데이터 검증 로직 필요

[선택지]

- TossPayments
- KCP
- PAYCO

[의사결정/사유]

- Toss Payments 템플릿이 Restful API이며, 가이드를 제공해줘서 빠르고 쉽게 구현 가능
- 다양한 결제 수단 지원  결제 화면 디자인이 깔끔함

[회고]

- 비교적 짧은 개발 시간에 안정적인 결제 시스템 구현
- 주문 ID와 가격을 검증하여 데이터 무결성 강화
- 결제 실패, 취소에 대한 로깅 필요

[ Jenkins CI/CD ]

상세보기
[내가 구현한 기능]

- Jenkins를 활용한 CI/CD 파이프라인 구축
- GitHub에서 소스 코드 변경사항을 감지하여 자동으로 빌드, 테스트, 배포를 수행하도록 Jenkins 설정
- Docker를 활용하여 Application 컨테이너를 생성하고, EC2 서버에 자동 배포

[주요 로직]

- Jenkins Pipeline 구성 : Clone, Build, Bulid Docker, Push Docker, Deploy to EC2
- Jenkins의 Git Plugin을 사용해 GitHub에서 푸시 이벤트를 감지하도록 Webhook 설정
- Application을 Docker 컨테이너로 빌드  배포

[배경]

- 지속적 통합(CI) 지속적 배포(CD): 팀원들이 동시에 개발하는 환경에서 코드 충돌을 줄이고, 안정적인 배포 프로세스를 구축하기 위함

[요구사항]

- GitHub에서 변경사항 발생  자동으로 빌드  테스트 수행
- Jenkins를 통해 EC2 서버로 Docker 이미지를 배포
- 배포 실패  롤백 가능
- Jenkins Pipeline으로 CI/CD 단계를 시각적으로 확인 가능

[선택지]

- GitHub Actions
- Jenkins
- AWS

[의사결정/사유]

- 플러그인 생태계가 풍부하여 참고 레퍼런스 자료가 다양함

[회고]

- CI/CD 자동화로 개발부터 배포까지의 시간이 크게 단축됨
- 초기 환경 설정(SSH 연결, Docker 설치 ) 많은 시간이 소요됨
- Docker 이미지 저장소(ECR) 통합하여 이미지 관리 최적화를 추후 도입함
- 추후 병렬 처리로 배포 성능 최적화가 목표
- https://everyday-spring.com/628
[성능 개선 / 코드 개선 요약]

- 빌드  테스트 단계에서 메모리 부족으로 인한 비정상 종료 빈도 증가

[문제 정의]

- Jenkins CI/CD 파이프라인 실행 , EC2 인스턴스의 메모리 용량 부족으로 인해 빌드가 중단되고 작업 실패 발생
- 사용 중인 EC2 인스턴스: t2-micro (메모리 1GB)

[가설] 

- Jenkins 빌드 작업에서 Gradle 빌드, 테스트, Docker 이미지 빌드  메모리를 과도하게 사용
- t2-micro 인스턴스의 1GB 메모리가 Jenkins의 동시 처리 요구를 충족하지 못함

[해결 방안]

- EC2 인스턴스 업그레이드 : 인스턴스를 t3-small (메모리 2GB) 업그레이드
- 스왑 메모리 추가 설정 : 인스턴스의 메모리 부족 문제를 보완하기 위해 스왑 공간을 생성
- 리소스를 많이 소모하는 정렬 플러그인 제거

[해결 완료]

- EC2 인스턴스를 t3-small로 업그레이드하여 2GB 메모리 확보
- 스왑 공간 추가로 Jenkins가 빌드 작업  메모리 부족 문제를 겪지 않도록 설정
- Jenkins와 빌드 도구(Gradle) 메모리 사용량 최적화를 통해 안정적인 파이프라인 실행 환경 마련
- 문제 발생  실행한 파이프라인 모두 정상 작동 확인

[회고]

- 현재와 같은 Docker in Docker 구조가 아닌 Jenkins를 단독 설치하여 리소스 효율성을 높일  있음
- 하나의 인스턴스가 아닌 여러개의 인스턴스로 Application을 분리해야 
- https://everyday-spring.com/634

[ Redis - 동시성 제어 ]

상세보기
[내가 구현한 기능]

- 동시성 제어를 위한  적용 : 선착순 쿠폰 발급 로직에 동시 요청이 발생하는 상황에서 데이터 일관성을 보장하기 위해 낙관적 , 비관적 , 분산   가지 방식을 비교 적용
-   방식의 장단점과 결과를 분석하여 최적의 해결 방안을 도출

[주요 로직]

- 낙관적  : JPA의 @Version 어노테이션을 사용하여 쿠폰 엔티티의 버전을 관리, 데이터 충돌이 발생할 경우 예외를 던지고, 예외 처리 로직을 통해 재시도 또는 오류 처리
- 비관적  : JPA의 @Lock(LockModeType.PESSIMISTIC_WRITE) 어노테이션을 사용하여 트랜잭션 내에서 데이터 수정  락을 강제로 설정, 트랜잭션 완료 시까지 다른 트랜잭션의 접근을 차단하여 데이터 충돌 방지
- 분산  : Redis와 Redisson 라이브러리를 활용하여 여러 서버  락을 관리,   생성, 대기 시간  임대 시간 설정을 통해 안정적인  해제  관리 구현, AOP를 통해 락을 간편하게 적용 가능하도록 어노테이션 방식 도입

[배경]

- 문제 상황: 선착순 쿠폰 발급 과정에서 동시 요청이 발생하면 데이터 일관성이 깨지고, 중복 발급 또는 발급 실패가 빈번하게 발생
- 목표: 데이터 일관성을 유지하면서 동시에 가능한 많은 요청을 처리할  있는 최적의 동시성 제어 방식을 도입

[요구사항]

- 동시성 제어를 통해 쿠폰 발급  데이터 일관성 유지
- 여러 서버에서 요청이 발생하는 환경에서도 안정적으로 처리 가능
-  적용 방식에 따라 성능(처리 속도) 안전성 간의 균형을 유지

[선택지]

- 낙관적  : 충돌 가능성이 낮은 환경에서 높은 성능 제공, 하지만 충돌이 잦을 경우 성능 저하와 높은 예외 처리 비용 발생
- 비관적  : 데이터 충돌 가능성이 높은 경우 적합하며, 안전성이 뛰어남, 트랜잭션 대기 시간이 길어질  있고 데드락 발생 가능성 존재
- 분산  : 여러 서버에서 동시 요청을 처리하는 분산 환경에 적합, Redis와 같은 외부 시스템 의존으로 인해 네트워크 장애가 발생하면 성능 저하 가능

[의사결정/사유]

- 분산  적용
- 단일 서버를 넘어서는 분산 환경에서도 안정적으로 동시성 제어가 가능
- AOP 기반의 어노테이션 방식으로 유지보수와 코드 재사용성이 높음
- 테스트 결과, 쿠폰 발급 수량과 고객 요청 수량 간의 일치 확인
- 데드락 발생 없이 요청이 안전하게 처리됨

동시성제어

[ Redis - Caching ]

상세보기
[내가 구현한 기능]

- Redis를 활용한 캐싱 시스템 구현
- 자주 요청되는 데이터를 Redis 캐시로 저장하여 애플리케이션 성능 향상
- DB 부하를 줄이고 데이터 조회 속도를 개선

[주요 로직]

- 캐싱 적용 데이터 선정
  - 데이터베이스에서 자주 조회되는 데이터를 분석
  - : 사용자 정보, 게시물 목록, 상품 데이터 
- Redis 캐시 저장
  - 데이터 조회  Redis에서 먼저 캐시 데이터 확인
  - Redis에 데이터가 없는 경우(DB 조회 발생) 데이터베이스에서 조회한  Redis에 캐싱

[배경]

- 데이터베이스에 자주 동일한 조회 요청이 들어와 성능 저하 문제 발생
- 대규모 트래픽에서 데이터베이스 부하를 줄이고 사용자 응답 속도를 개선하기 위해 캐싱 필요

[요구사항]

- 데이터 조회 성능을 개선하여 사용자 응답 시간을 단축
- 데이터 변경  캐시와 데이터베이스의 일관성을 유지
- 캐시 데이터의 유효 기간을 설정하여 오래된 데이터를 자동 삭제
- 트래픽이 많은 환경에서도 안정적으로 동작할  있도록 확장성 확보

[선택지]

- Redis 캐싱
- Ehcache 사용
- 데이터베이스 쿼리 최적화

[의사결정/사유]

- Redis 캐싱을 선택한 이유
  - 대규모 트래픽에서도 빠른 응답 시간 보장
  - TTL 설정을 통해 캐시 데이터의 유효성을 유지
  - 확장성과 안정성이 높아 분산 환경에 적합

[회고]

- 적용하지 못한 TTL 구현 예정

레디스_캐싱_성능개선_결과

[ Elasticsearch ]

상세보기
[내가 구현한 기능]

- Elasticsearch를 활용한 고성능 검색 시스템 구현
- 데이터베이스 대신 Elasticsearch를 사용하여 대량 데이터에 대해 빠른 검색  분석 기능 제공
- 사용자 쿼리 요청에 대해 정확하고 빠른 검색 결과를 반환

[주요 로직]

- 도슈먼트를 생성하여 데이터베이스의 데이터를 Elasicsearch로 sync
- 공연 제목 등의 부분 검색이 필요한 필드는 Keyword로 설정하여 index를 구성

[배경]

- 데이터베이스를 이용한 기존 검색 로직은 대량의 데이터 처리  복잡한 쿼리 실행에서 성능 저하가 발생
- 사용자 검색 요청에 대해 빠르고 정교한 결과를 제공하기 위해 전문 검색 엔진 도입 필요
- Elasticsearch는 텍스트 검색, 정렬, 필터링  다양한 고급 기능과 높은 확장성을 제공

[요구사항]

- 대량의 데이터에 대해 빠른 검색 결과를 제공
- 키워드 검색으로 공연, 공연장, 출연자를 모두 조회

[선택지]

- Elasticsearch
- Apache Solr
- JPA

[의사결정/사유]

- 대량 데이터 처리와 고급 검색 쿼리에 적합
- 동적 스케일링  분산 환경 지원으로 향후 트래픽 증가에도 대응 가능
- Spring Data Elasticsearch와의 통합으로 개발 편의성이 높음

[회고]

- 데이터 싱크를 savaAll메소드로 스케쥴링하여 새로운 데이터 반영이 안됨
- 데이터를 모두 삭제하고 업로드 하거나 새로운 방법을 도입해야함

ES검색_성능개선_결과

[ Logstash ]

상세보기
[내가 구현한 기능]

- Logstash를 추가하여 로그 수집  관리 시스템 구축

[주요 로직]

- AOP를 활용한 로그 수집
  - 예매, 쿠폰, 결제 이벤트 발생  AOP로 처리하여 Logstash에 로그 전달
  -  이벤트 별로 구분된 로그 저장  Index 설정
- ElasticSearch 서버  Local에도  단위로 로그 백업파일 저장
- 로그 필터링
  - "select" 쿼리 제외 : 로그 수집  불필요한 쿼리문 제외
  - 이벤트별 구분 : 예매, 결제, 쿠폰  이벤트 유형에 따라 별도 index 생성

[배경]

- 로그 수집  분석은 서비스 안정성을 확보하고 문제 발생  원인 추적에 필수적
- ELK 스택을 활용해 데이터 분석  모니터링 환경 구축

[요구사항]

- ElasticSearch 서버에 문제가 생길 경우에도 로그 유실 방지를 위해 로컬에 백업 저장
- 이벤트와 관련된 쿼리문(INSERT, UPDATE, DELETE) 수집
- 이벤트 유형별로 로그를 색인하여, 필요한 데이터를 신속히 검색 가능하게 설정

[선택지]

- Logstash
- Logger

[의사결정/사유]

- ELK 스택을 이미 도입했기 때문에 Logstash를 선택하여 ElasticSearch와
  통합된 데이터 수집/분석 환경 구축
- Logger는 단순한 로그 기록에는 유리하지만, 로그의 활용성과 분석 기능에서는 부족하다고 판단

[회고]

- 성공한 
  - AOP를 활용해 서비스 주요 이벤트(예매, 결제 ) 효과적으로 추적  수집
  - ElasticSearch와 로컬 백업을 통해 로그 유실을 최소화하고 안정성을 확보
  - 불필요한 SELECT 쿼리를 제외해 시스템 성능 최적화
- 개선가능 
  - 수집된 로그 분석  시각화 활용 방안을 구체적으로 마련하지 못함

[ Query 최적화 ]

상세보기
[성능 개선 / 코드 개선 요약]

[문제 정의]

- 공연 전체 조회  페이징 처리를 하지만 평균 응답시간이 늦고 에러가 발생하는 현상

[가설]

- 공연 조회  전체 조회, 키워드 조회 모두 같은 쿼리를 사용
- 불필요한 테이블 조인, 조건 처리로 인한 성능 저하

[해결 방안]

- 키워드/전체 조회 쿼리문 분리
  - 전체 조회  불필요한 테이블과 조건 처리 제외

[해결 완료]

- 10000, 30 성능테스트
  - 평균 응답 시간 23881ms211ms, 성능 99% 개선
  - 에러율 13.91% → 0%

[회고]

- 하나의 쿼리를 사용해 재사용하면 깔끔해보이고 좋다고 생각했으나
  성능적으로  문제가 발생할  있다는 것을 깨달음

쿼리최적화

[ Alert - SSE ]

상세보기
[내가 구현한 기능]

- Slack 알림 AOP

[주요 로직]

- SlackNotifier : Slack 웹훅 URL을 이용해 메시지를 Slack 채널에 전송
  - RestTemplate을 사용해 Slack API에 HTTP POST 요청을 전송
  - 제목과 메시지를 포함하여 Slack의 메시지 형식에 맞게 전송
- SlackNotificationAspect : AOP를 활용하여 서비스 로직 실행  자동으로 Slack 알림 발송
  - 예약 메서드 실행  관련 정보를 바탕으로 Slack 알림 메시지를 작성하고 전송

[배경]

- 시스템 이벤트(: 예약 확인, 시스템 알림 ) 대해 실시간으로 Slack 알림을 보내어 관리자가 시스템 상태를 모니터링할  있도록 하기 위함

[요구사항]

- 예약 관련 데이터(예약 정보, 공연 정보, 공연장 정보 ) Slack으로 알림을 보내기
- 알림 전송은 예약 메서드 실행  자동으로 이루어지도록 AOP를 활용

[선택지]

- AOP 사용
- RestTemplate 활용

[의사결정/사유]

- AOP 사용 이유 : 서비스 로직과 알림 로직을 분리하여 코드의 유지보수성을 높이고, 알림 기능이 다른 서비스 메서드에도 재사용될  있도록 하기 위해 AOP를 사용
- RestTemplate 선택 이유 : Spring에서 기본적으로 제공하는 HTTP 클라이언트 라이브러리로, RESTful API와의 통신에 용이하며, 외부 API와의 통합에서  작동하기 때문

[회고]

- Slack 알림 기능을 AOP로 자동화하여 시스템 상태를 실시간으로 모니터링할  있게 되었고, 관리자의 수동 작업을 줄일  있었다
- SlackNotifier와 AOP를 결합한 방식이 효과적이었고, 알림 전송에 필요한 데이터를 서비스 메서드에서 AOP로  전달하여 실제 알림 메시지가 실시간으로 발송됐다
[내가 구현한 기능]

- SSE 기반 실시간 알림 시스템
  - 클라이언트가 SSE를 통해 알림을 구독하고, 서버는 Redis를 통해 데이터를 전송하며 실시간 알림을 제공
  - Redis 채널을 활용하여 다중 서버 환경에서도 알림 전송 가능
  - Slack 알림과 함께 실시간 알림을 SSE로 처리

[주요 로직]

- 클라이언트 구독
  - /notifications/subscribe/{userId} 엔드포인트를 통해 클라이언트가 SseEmitter 객체를 구독
  - SseEmitter 객체를 사용자별로 HashMap에 저장하고 연결 관리
- Redis를 통한 메시지 발행
  - /notifications/send 요청을 통해 Redis의 notification-channel에 알림 데이터를 발행
  - 데이터 형식: userId, title, message
- 알림 데이터 전송
  - Redis 구독자가 데이터를 수신하면 해당 사용자의 SseEmitter로 실시간 전송
  - 동시에 Slack 알림 비동기 전송

[배경]

- 실시간 피드백이 중요한 티켓 예매, 선착순 쿠폰 발급과 같은 시나리오에서 실시간 알림 제공 필요
- 서버-클라이언트  즉각적인 데이터 전송을 지원하는 SSE가 알림 시스템에 적합하다고 판단

[요구사항]

- 클라이언트가 특정 엔드포인트를 통해 실시간 알림을 구독할  있어야 
- Redis를 활용하여 서버  메시지 전달  확장성 있는 실시간 알림 시스템 구축
- 알림은 클라이언트의 SseEmitter와 Slack 알림으로 각각 전송

[선택지]

- SSE(Server-Sent Events)
- WebSocket

[의사결정/사유]

- SSE   - 알림은 서버에서 클라이언트로의 단방향 전송이므로 SSE로 충분히 구현 가능.
  - 브라우저 지원이 기본 제공되며, 구현이 간단하여 빠른 적용이 가능.
  - Redis를 활용하여 다중 서버에서도 확장 가능.
- Redis 
  - 메시지 발행-구독 구조를 통해 다중 서버 환경에서도 데이터를 일관되게 전송.

[회고]

- SSE와 Redis를 결합하여 실시간 알림 시스템을 간단하면서도 효과적으로 구현할  있었다
- Slack과 SSE 알림을 병행 처리하면서 사용자 경험을 개선
- 다중 서버 환경을 구성하지 못하여 redis 활용의 장점을 얻지 못함

slack에서 sse로 알림변경

[ Alert - Mail ]

상세보기
[내가 구현한 기능]

- 예매  결제내역 이메일 발송

[주요 로직]

- JavaMailSender를 사용해 SMTP 서버를 통해 메일 발송

[배경]

- 사용자가 예매  결제를 완료한  확인 메일을 발송하여 신뢰도 향상

[요구사항]

- 글로벌  한국 사용자 모두 사용 가능한 메일 서버 선택
- 메일 발송이 암호화로 보호될 

[선택지]

- Google
- Naver

[의사결정/사유]

- Google은 글로벌 사용자, Naver는 한국 사용자 기반
- 비교적  간단하게 설정할  있는 "Google" 선택

[회고]

- 간단한 설정과 높은 안정성을 통해 예상보다 빠른 시간에 기능 구현
- 메일 발송이 실패했을 경우 별도의 재시도 로직, 예외 처리 추가 필요
[성능 개선 / 코드 개선 요약]

[문제 정의]

- 메일 발송  동기식 처리로 인해 응답 지연 발생
- 대용량 트래픽 처리  병목 현상 초래 가능

[가설]

- 메일 발송 구현  별도 처리를 하지 않아 동기식으로 동작
- 메일 발송이 완료  때까지 메인 쓰레드가 대기하는 현상

[해결 방안]

- 비동기 처리
  - Spring의 @Async를 활용하여 간단하게 비동기 처리 구현
  - 비동기 처리  메인 쓰레드가 아닌 별도 쓰레드에서 처리
- 스프링 배치
  - 일정 주기로 모아  번에 처리
- 사용자 만족도를 높이기 위해 메일 발송 로직을 비동기 처리로 구현하여
  - 즉시성 확보를 우선 적용

[해결 완료]

- @Async을 사용하여 메일 발송 메서드를 비동기 처리로 전환
- 예매 완료  응답시간 5.25s -> 0.8s로  84% 개선

[회고]

- 간단한 설정으로 비동기 처리를 구현 가능

async 성능

[성능 개선 / 코드 개선 요약]

[문제 정의]

- Jmeter를 사용해 예매 기능 부하테스트  에러율 98% 발생

[가설]

- Async 관련 쓰레드풀이 낮게 설정되어 요청 처리 한계 발생
- 대기  저장공간이 낮게 설정되어 용량을 초과한 요청 에러 발생

[해결 방안]

- 동시 요청 처리 능력 확장을 위해 최소/최대 쓰레드 수를 늘림
- 대기  저장공간이 크면 응답 지연 발생 가능성이 있지만 에러율을 낮추는 것이 우선이라고 판단

[해결 완료]

- 최소 쓰레드  : 5 -> 50
- 최대 쓰레드  : 10 -> 200
-  저장공간 : 100 -> 1000
- 적용 결과
  - 기존 에러율 98% -> 15% 대폭 감소
  - 15% 테스트 PC 성능과 인터넷 문제로 판단

[회고]

- Jmeter로 테스트하며 쓰레드  설정을 임의의 값으로 설정했으나
  보다 정확한 계산법으로 설정할 필요가 있다고 생각됨

mail troubleshooting

[ Spring Batch ]

상세보기
[성능 개선 / 코드 개선 요약]

- Spring Batch에서 JPA를 JDBC로 변경했음에도 성능 차이가 없었던 문제를 해결함
- batchList.clear() 추가하여 메모리 점유 문제를 해결한 , 확연한 성능 개선을 확인

[문제 정의]

- Spring Batch 처리에서 JPA에서 JDBC로 전환했지만, 성능 차이가 나타나지 않음
- JDBC `batchUpdate` 사용했음에도 불구하고 처리 속도가 기대만큼 개선되지 않음

[가설]

- JPA와 JDBC  성능 차이가 미비한 이유로는 JDBC 코드 내에서 잘못된 메모리 관리가 의심됨
- 반복문에서 batchList를 subList로 분리해 사용하면서 이전 batchList의 데이터가 clear되지 않아 메모리를 지속적으로 점유했을 가능성이 있음

[해결 방안]

- 메모리 누수 원인 파악
  - batchList를 subList로 사용한  clear되지 않아 메모리 증가를 유발한 것으로 판단
  - `batchList.clear();` 명시적으로 추가하여 batchList를 반복 처리  즉시 비우도록 수정

[해결 완료]

- batchList.clear() 추가  성능 차이가 확연히 개선

[회고]

- 메모리 관리의 중요성을 다시 한번 확인
- 배치 처리  데이터 누수를 방지하기 위해 사용된 리스트를 명시적으로 정리하는 습관 필요
- JPA와 JDBC  성능 차이 외에도 메모리 누수가 성능 문제의 주요 원인으로 작용할  있음을 알게 

jpa jdbc

[ Monitoring - Prometheus, Grafana ]

상세보기
[내가 구현한 기능]

- Prometheus와 Grafana를 활용한 시스템 모니터링 기능을 구현
- 애플리케이션  인프라 상태를 실시간으로 수집하고, Grafana 대시보드에서 시각화

[주요 로직]

- Prometheus:
  - 애플리케이션의 JVM  애플리케이션 메트릭을 수집하기 위해 Spring Boot Actuator와 Prometheus Exporter 통합
  - Prometheus 서버가 주기적으로 애플리케이션에서 메트릭 데이터를 스크래핑

- Grafana:
  - Prometheus를 데이터 소스로 사용하여 시각화 대시보드 구성
  - 주요 지표: CPU, 메모리 사용량, JVM 스레드 상태, 애플리케이션 응답 시간, 요청 처리량 

[배경]

- 시스템 상태를 실시간으로 모니터링하고 이슈를 빠르게 식별하기 위한 요구사항
- 특히 배치 작업  리소스 사용량을 모니터링하고 병목 현상이나 비정상적인 동작을 탐지하기 위해 Prometheus와 Grafana를 도입

[요구사항]

- Spring Boot 애플리케이션에서 주요 메트릭 데이터를 수집하여 Prometheus에 전달
- Prometheus에 수집된 데이터를 Grafana 대시보드에서 시각적으로 표현
- 알림 규칙(Alert Rules) 설정하여 특정 임계값을 초과하면 알림을 전송

[선택지]

- Prometheus & Grafana
   - 장점: 오픈소스 기반으로 비용 부담이 적고, 커스터마이징 가능
   - 단점: 초기 설정  데이터 소스 구성에 대한 학습 곡선이 존재
- 대체 모니터링 솔루션 (: Datadog, New Relic)
   - 장점: 간단한 설정과 풍부한 기능.
   - 단점: 높은 비용과 벤더 종속성.

[의사결정/사유]

- Prometheus와 Grafana를 선택한 이유
  - 오픈소스 기반으로 높은 확장성과 커스터마이징 가능성
  - Spring Boot Actuator와의 자연스러운 통합
  - 기존 인프라와의 적합성  사용 비용 절감

[회고]

- Prometheus와 Grafana를 활용하여 시스템 모니터링을 효과적으로 구현
- JVM 메트릭 수집  대시보드 시각화로 애플리케이션 성능을 실시간으로 추적 가능
- 실제 테스트시 Jmeter를 주로 사용하여 많이 활용하지 못한 부분이 아쉬움
- 초기 설정과 대시보드 구성에는 다소 시간이 소요됨
- 향후 시스템 확장에 따라 메트릭 지표를 세분화하고 알림 임계값을 조정할 계획

prometheus,grafana

[ Code Convention ]

상세보기
[성능 개선 / 코드 개선 요약]

- 다양한 툴을 활용한 코드 리팩토링

[문제 정의]

- 온라인 협업 프로젝트 방식으로 진행하여 코드의 일관성을 맞추는데 한계가 있음

[해결 방안]

- SonarQube, SonarLint : 정적 코드 분석 도구를 활용하여 코드를 개선함
- Spotless plugin을 사용하여 GooleJavaFormat을 반영함
- 버전별 개발이 완료될 때마다 전체 코드를 확인하고 직접 수정함

[회고]

- 개발 타임라인에 영향을 주지 않는 선에서 리팩토링을 진행하기 위해 주말에 진행함
- 여러명이서 작성한 코드기 때문에 코드를 이해하는데도 오랜시간이 소요됨
- 개발 시작시 설계의 중요성에 대해 한번더 생각하게됨
- Spotless 툴은 활용도가 좋았으나 merge 충돌이 많이 생기고 배포시에  제외해야함

Code Convention

💻 Contributors

[ 프로젝트 기간 ]

📅 2024.10.21 ~ 2024.11.22

[ 강은총 ] - GitHub

상세보기
  • CRUD
    • 공연장
    • 쿠폰
  • 동시성 제어
    • 쿠폰 발급시 동시성 제어 필요성
    • Redis의 Redisson 라이브러리 사용하여 분산 락 적용
  • 결제 시스템 쿠폰 적용
    • 토스페이먼츠에서 결제 시 쿠폰 적용 가능
  • 알림 시스템
    • 예매 성공/취소 시 슬랙 알림 전송
    • AOP 방식에서 SSE로 변경하여 비동기, 실시간 처리 기능 추가 및 향상
    • Redis pub/sub을 적용하여 서버 인스턴스 간 실시간 알림을 전파 할 수 있도록 구현
  • TEST
    • Jmeter 활용하여 쿠폰, 공연장 관련 성능 테스트 및 응답속도 확인

[ 김태주 (Leader) ] - GitHub

상세보기
  • CRUD
    • 관람평
  • s3 첨부파일 CRUD
    • 공연을 등록 시 s3에 포스터를 저장할 수 있음
  • 레디스 캐싱
    • Redis를 이용한 단순 조회 api 조회 속도 개선
  • 동시성 제어
    • 티켓 예매 시 동시성 제어 필요성
    • Redis의 Redisson 라이브러리 사용하여 분산 락 적용
  • TEST
    • Junit 테스트 코드 작성

[ 이봄 ] - GitHub

상세보기
  • 프로젝트 기본구조 생성
    • ERD기반 entity 설계
    • Test데이터 생성 domain 설계
  • CRUD
    • 예매 관련 기능 구현
    • 회원가입, 로그인 기능 구현
  • Swagger
    • API 테스트 환경 구성
    • 샘플 데이터 세팅
  • Jira
    • 프로젝트 관리 환경 구성
  • 결제 시스템 연동
    • 토스 페이먼츠 결제 DB 관련 기능 구현
  • CICD
    • 배포 환경 구성
    • Jenkins - github webhook 환경 구성
  • Elasticsearch
    • 공연 키워드 검색 기능 구현
    • JPA → ES 검색 성능 개선
  • Spring Batch
    • Batch 전용 프로젝트 구성
    • Jenkins Batch 자동화 환경 구성
  • TEST
    • Prometheus - Grafana 환경 구성
    • Jmeter 활용 성능 테스트
    • Junit 테스트 코드 작성
    • Refactoring
    • SonarQube 정적 코드 검증 및 개선
    • SonarLint 정적 코드 검증 및 개선
    • code convention 점검 및 수정
    • Spotless 활용

[ 이봉원 (Sub-Leader) ] - GitHub

상세보기
  • 공연 관리 시스템
    • CRUD : 생성, 전체 조회, 키워드 검색, 수정, 삭제, 출연자 등록, 삭제, 포스터 수정 기능 구현
  • 결제시스템 연동
    • 토스페이먼츠 API 연동 결제
  • OAuth2 소셜 로그인
    • 카카오 계정을 활용하여 사용자 인증 및 로그인 구현
  • 메일 발송 기능
    • SMTP 프로토콜 사용
    • 비동기 처리 : @Async를 활용
  • DB 이중화 및 분산 처리
    • AWS기반 이중화 DB 구성 : EC2를 활용
    • Master-Slave 역할 분리
      • Master 노드 : 데이터 쓰기 작업(Insert)
      • Slave 노드 : 데이터 읽기 작업(Read)
  • ELK 스택 통합 로그 관리
    • Logstash 필터 적용
    • AWS 환경 적용 : ELK 기반 로그 모니터링
  • 코드 리팩토링
    • Jmeter를 활용하여 성능테스트 및 응답속도 감소를
      위한 코드 리팩토링

[ 한강 ] - GitHub

상세보기
  • CRUD
    • 공연당 배우 등록, 삭제
    • 배우, 회차
  • 검색 기능 추가
    • 관리자 중심 예매, 결제 검색 기능 구현
  • ElasticSearch & kibana
    • elasticsearch 및 kibana 환경 구성
    • 인덱싱 설계 및 검색환경 구현
  • Logstash
    • 서비스 로그 수집, 백업로그파일 통합
    • kibana로 수집한 로그에 대한 모니터링

🤝 Development Guide

team guide

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages