Search

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 아래에 도메인별로 repositoryservice를 포함하여 도메인 중심 설계를 유지했습니다.
repository는 도메인 로직에서 직접 호출 가능하며, 저장소의 세부 사항은 storeage에 위임.
service는 도메인별 비즈니스 로직의 집합체로, 핵심 기능을 캡슐화.
2. 저장소 세부 사항 분리
storeage/coroe 아래에 JPA 및 MyBatis를 명확히 분리하여 구현 기술별로 관리.
jpamybatis가 공존하더라도 서로 영향을 주지 않음.
도메인 모델과 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년에도 속도보다 방향으로 발전하는 사람이 되는 것으로 하겠습니다.