Search
moon
sun

2024년 회고

순서
4
날짜
2025/01/06
사람
상태
Done
24년도는 신규 프로젝트 및 다양한 경험을 하였던 한 해였습니다. 운이 좋게? 신규 프로젝트를 처음부터 끝까지 기일에 맞춰 오픈하였고, 중간중간의 문제를 해결하기 위해 공부했던 내용들도 많았습니다. 각각의 내용에 대해 간단하게 작성하고 24년도에 정리한 내용을 링크로 남아 기록하도록 하겠습니다.

1.1 부정거래 어드민 웹 사이트

처음으로 프로젝트를 맡아 신규로 오픈한 웹 사이트 입니다.

1.1.0 패키지 분리

├── cache └── core │ └── domain │ └── domainA │ │ └──repository │ │ │ └──domainRepository │ │ │ └──domainRepository │ │ └──service │ │ └──domainService │ └── domainB │ └── common ├── storeage └── web
Java
복사
1.
패키지 분리 기준
•
cache, storage 등 기술/기능 중심 패키지를 최상단에 배치.
•
core는 도메인과 공통 비즈니스 로직을 포함하도록 설계.
2.
도메인 패키지 하위 분리
도메인(domainA, domainB)을 개별적으로 구성하고, 각 도메인의 엔티티, 리포지토리, 서비스, DTO 등을 세분화.
예를 들어, domainA 안에서 엔티티와 관련된 모든 파일을 쉽게 찾을 수 있음.
3.
웹 계층 분리
•
web에 컨트롤러와 **웹 전용 로직(DTO, 예외 처리)**를 한곳에 모아둠.
•
Interceptor, ArgumentResolver를 별도로 관리하여 구조 명확화.
4.
공통 코드 위치
•
모든 도메인에서 공통적으로 사용하는 코드는 core/common으로 분리.
•
공통 유틸, 상수, 예외 등은 여기에 위치.

1.1.1 종속성 문제 해결

├── cache └── core │ └── domain │ └── domainA │ │ └──repository │ │ │ └──domainRepository │ │ │ └──domainRepository │ │ └──service │ │ └──domainService │ └── domainB │ └── common ├── storeage │ └── coroe │ └── jpa │ │ └── domainA │ │ │ └── domainJpaEntity │ │ │ └── domainJpaEntity │ │ └── domainB │ │ └── domainJpaEntity │ │ └── domainJpaEntity │ └── mybatis │ └── domainB │ └── domainMybatisDTO │ └── domainMybatisDTO ├── web │ ├── controller │ ├── dto │ └── exception └── external
Java
복사
1. 도메인 중심의 계층화
•
core/domain 아래에 도메인별로 repository와 service를 포함하여 도메인 중심 설계를 유지했습니다.
◦
repository는 도메인 로직에서 직접 호출 가능하며, 저장소의 세부 사항은 storeage에 위임.
◦
service는 도메인별 비즈니스 로직의 집합체로, 핵심 기능을 캡슐화.
2. 저장소 세부 사항 분리
•
storeage/coroe 아래에 JPA 및 MyBatis를 명확히 분리하여 구현 기술별로 관리.
◦
jpa와 mybatis가 공존하더라도 서로 영향을 주지 않음.
◦
도메인 모델과 DB 엔티티, DTO 간의 변환은 각 계층에서 관리 가능.
3. 웹 계층 독립
•
web 패키지에서 요청/응답 DTO, 컨트롤러, 예외 처리를 관리.
◦
도메인 계층과 별도로 분리하여, 확장성과 유지보수성을 높임.
4. 확장성 확보
•
external 패키지를 통해 외부 API 연동 코드를 분리하여, 다양한 외부 서비스와의 통합 가능.
•
cache 패키지로 캐시 관련 로직을 통합 관리해 성능 향상을 도모.

1.1.2 낙관적 락, 비관적 락, 분산 락

1. 낙관적 락 (Optimistic Lock)
•
개념
데이터 충돌 가능성이 낮다고 가정하고, 트랜잭션이 완료될 때까지 잠금을 걸지 않으며 데이터를 처리하는 방법입니다.
트랜잭션이 끝날 때 데이터 변경 여부를 검증하여 충돌이 없을 경우에만 데이터를 갱신합니다.
일반적으로 **버전 관리(versioning)**를 통해 구현합니다.
•
특징
◦
잠금을 걸지 않기 때문에 성능이 좋습니다.
◦
충돌 가능성이 높은 환경에서는 실패율이 증가할 수 있습니다.
•
사용 사례
◦
데이터 갱신 빈도가 낮고 충돌 가능성이 적은 환경.
◦
데이터 일관성을 트랜잭션 종료 시점에만 보장하면 되는 경우.
•
관련 정리 링크
2. 비관적 락 (Pesimistic Lock)
•
개념
데이터 충돌 가능성이 높다고 가정하고, 트랜잭션이 시작되자마자 잠금을 걸어 다른 트랜잭션이 접근하지 못하도록 하는 방법입니다.
락을 통해 강제적으로 자원을 보호하며, **공유 락(Shared Lock)**과 **배타 락(Exclusive Lock)**으로 나뉩니다.
•
특징
◦
충돌이 발생하지 않도록 보장하지만, 잠금으로 인해 성능 저하가 발생할 수 있습니다.
◦
데드락(Deadlock)이 발생할 가능성이 있습니다.
•
사용 사례
◦
데이터 갱신 빈도가 높고 충돌 가능성이 큰 환경.
◦
자원의 일관성을 트랜잭션 실행 중에도 보장해야 하는 경우.
•
관련 정리 링크
3. 분산 락 (Distributed Lock)
•
개념
멀티스레드 또는 멀티 프로세스 환경에서 공유 자원에 대한 동시 접근을 제어하기 위해 사용되는 락입니다.
주로 분산 시스템에서 데이터 정합성을 보장하기 위해 사용합니다.
•
구현 방법
◦
Redis: SETNX 명령어와 EXPIRE를 활용해 락을 설정.
◦
ZooKeeper: 분산 락 구현에 사용되는 대표적인 툴로, ephemeral znode를 활용.
◦
Database: 특정 테이블을 활용하여 락 정보를 관리.
•
특징
◦
분산 환경에서 데이터 일관성을 보장합니다.
◦
구현이 복잡하고, 네트워크 지연 및 장애 상황에 대비해야 합니다.
•
사용 사례
◦
분산 시스템에서 자원 접근 동기화가 필요한 경우.
◦
클러스터 환경에서 동일 데이터에 대한 경쟁 조건을 방지해야 하는 경우.
•
관련 정리 링크

1.1.3 Test Code 도입

•
TestCode 설명

1.1.4 코드리뷰 도입

•
ADS 프로젝트를 신규로 구축하면서 PRMS에서 발생되었던 문제를 개선하고자 코드 리뷰를 진행함
•
각자 맡고 있는 개발을 설명하고, ADS에서 적용하고 있는 코드 규칙과 문제점은 없는지 확인
•
코드리뷰를 새로 도입하면서 제일 중요한 부분은 개발자들간의 신뢰
•
신뢰속에서 더 좋은 방법이라 생각될 시 편하게 말하는 분위기가 중요

1.1.5 DBCP

DBCP는 데이터베이스와의 연결을 미리 생성해 풀(Pool)에 보관함으로써, 클라이언트 요청 시 매번 TCP 연결을 생성/해제하는 과정을 생략해 성능을 개선하는 기술입니다.
DBCP가 없는 경우
1.
클라이언트 요청 → 애플리케이션에서 TCP 연결 생성 (3-way Handshake)
2.
데이터 조회 후 TCP 연결 해제 (4-way Handshake)
3.
반복적으로 연결 생성/해제가 발생해 성능 저하.
DBCP가 있는 경우
•
미리 생성된 연결 풀에서 Connection을 가져와 재사용.
•
3-way 및 4-way Handshake 과정 최소화로 빠른 응답 제공.
DB 설정에서 중요한 항목
1.
MaxConnections
•
DB가 처리할 수 있는 최대 연결 수를 적절히 설정.
2.
wait_timeout
•
유휴 상태 연결을 자동 종료하여 불필요한 연결 점유 방지.
DBCP 주요 설정
1.
minimumIdle
•
유지할 유휴 연결의 최소 개수.
2.
maximumPoolSize
•
동시에 열 수 있는 최대 연결 수.
•
최소/최대 값을 동일하게 설정하는 것이 권장됨.
3.
maxLifetime
•
연결 유효 시간.
•
DB의 wait_timeout보다 2초 작게 설정 필요.
4.
connectionTimeout
•
풀에서 연결을 가져오기 위한 최대 대기 시간.
결론
•
DB 설정(MaxConnections, wait_timeout)과 DBCP 설정(minimumIdle, maximumPoolSize, maxLifetime)을 조화롭게 관리.
•
부하 발생 시 설정 최적화 또는 장비 증설로 대응.이를 통해 시스템 안정성과 성능을 유지할 수 있습니다.
관령 링크

캐시 Stampede 현상과 해결 방안 요약

1. 캐시 Stampede란?

•
정의: 캐시가 만료될 때 여러 요청이 한 번에 DB로 몰려가면서 DB 부하가 급증하고 성능 저하를 일으키는 현상.

2. 기존 해결 방안과 한계

•
분산락 방식
◦
장점: 캐시 만료 시점에 단일 요청만 DB를 접근하도록 하여 DB 부하를 감소시킴.
◦
단점: 락을 획득하지 못한 요청은 대기하게 되어 응답 지연이 발생.
•
캐시 웜업 (Cache Warm-up)
◦
의미: 애플리케이션 시작 시나 특정 시점에 캐시를 미리 채워 놓는 방식.
◦
방법: 배치 작업을 통해 자주 사용되는 데이터를 미리 캐시에 적재.
◦
문제점:
▪
리모트 캐시 서버 부하로 인한 응답 지연 가능성.
▪
캐시 웜업 대상 누락 시 기존 문제(Stampede)가 재발생할 수 있음.

3. 하이브리드 캐시 솔루션

•
구조: 로컬 캐시와 리모트 캐시를 함께 사용.
◦
데이터 조회 순서: 로컬 캐시 → 리모트 캐시 → DB
•
데이터 특성별 캐시 활용:
◦
로컬 캐시: 개인화되지 않고 업데이트 빈도가 낮은 데이터.
▪
예: 마케팅 카드, 내비게이터, 리뷰 등.
◦
리모트 캐시: 최신 상태를 유지해야 하는 데이터로 모든 인스턴스에서 동일한 응답을 보장.

핵심 포인트

•
캐시 Stampede를 방지하기 위한 해결책으로 분산락과 캐시 웜업 방식이 있지만 한계가 존재.
•
하이브리드 캐시 솔루션을 도입하면 로컬 캐시와 리모트 캐시의 특성을 잘 활용하여 효율적인 데이터 관리를 할 수 있습니다.

PRMS 상품 리스크 어드민 웹사이트

기존에 유지보수 하고 있는 프로젝트
•
중복상품, 중복모니터링 문제의 원인과 해결방법 모색
문제분석
•
기존 상태: 단일 ID(Long)를 사용하고, @GeneratedValue(strategy = GenerationType.IDENTITY)로 ID를 자동 생성했습니다.
•
변경된 상태: 복합키(ID + createdAt)로 변경되었으나, JPA에서 @GeneratedValue를 제거하고 @Id만 사용하도록 수정했으며, 기존의 조회 메서드들이 이 변경을 반영하지 않아서 중복 데이터가 반환됩니다.
문제 해결 방법
•
엔티티로 변환하지 않고 Object로 변환해서 일단 개발은 완료
•
파티셔닝 변경하여 다시 적용

인프런 워밍업 클럽 백엔드 스터디 2기

•
1주차 발자국
•
2주차 발자국
•
3주차 발자국
•
4주차 발자국

2024년 수료 인프런 인터넷 강의

•
오브젝트 - 기초편
•
[아파치 카프카 애플리케이션 프로그래밍] 개념부터 컨슈머, 프로듀서, 커넥트, 스트림즈까지!
•
Practical Testing: 실용적인 테스트 가이드
•
Readable Code: 읽기 좋은 코드를 작성하는 사고법
•
스프링 시큐리티 완전 정복 [6.x 개정판]
•
Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트

경험 및 인사이트

2024년에는 프로젝트를 진행하면서 다양한 방법과 어떻게 하면 프로젝트를 진행하면서 과거 프로젝트보다 좀 더 나은 프로젝트로 만들 수 있을까 고민을 많이 하면서 작업을 하였습니다. 그럼에도 불과하고 아직 많이 부족하다고 생각하고 왜?라는 질문에 명확하고 쉽게 설명할 수 있는 개발자로 방향을 잡을 것입니다.
24년도에 아쉬운 점
1.
프로젝트를 진행하면서 문서화를 많이 못했음
2.
인프라에 대해 쉽게 설명하지 못했
3.
개인 프로젝트 1개는 올렸지만, 너무 간단한 프로젝트였음
a.
MBTI 롤 포지션
25년 목표
1.
개발 책을 8권 이상 읽어보자
2.
인프라에 대해 공부하자
3.
사용자가 인입될수 있는 개인 프로젝트를 2개 이상 진행하자
4.
적극적으로 다른 사람들에게 설명할 수 있는 자리를 마련하자
25년에도 속도보다 방향으로 발전하는 사람이 되는 것으로 하겠습니다.