Skip to content

je-pa/ecommerce

Repository files navigation

🛒ECOMMERCE

Project

🔗 프로젝트 관리

Monolithic Architecture

🔗 MONOLITHIC ECOMMERCE

MicroService Architecture

🔗 USER SERVICE 🔗 PRODUCT SERVICE 🔗 ORDER SERVICE

🔗 GATEWAY 🔗 EUREKA SERVER

🔗 CONFIG SERVER(PRIVATE) 🔗 CONFIG REPOSITORY(PRIVATE)

image

⭐ 기술 스택

분류 기술 비고
프로그래밍 언어 Java
빌드 도구 Gradle
프레임워크 Spring Boot
Spring Security
ORM JPA(Hibernate)
데이터베이스 MySQL
H2 테스트 DB
Redis 캐시
테스트 도구 JUnit5 통합 테스트
Mockito 단위 테스트
JaCoCo 테스트 커버리지 리포트
정적 분석 도구 SonarQube 코드 품질 분석
쿼리 빌더 QueryDSL
인증/인가 JWT
Google SMTP mail 인증
컨테이너화 도구 Docker
스프링 클라우드 Spring Cloud
Spring Cloud Config config value Serving
Spring Cloud Gateway endpoint 단일화
Eureka Discovery
Eureka Client Registry

⭐ API

메서드 엔드포인트 설명 요청 데이터 및 쿼리 파라미터 예시
POST /api/auth/login 로그인
application/x-www-form-urlencoded
[email protected]&password=Password1!
POST /api/auth/send-email-auth-code 인증코드 발송
application/json
{ "email": "[email protected]" }
POST /api/auth/signup 회원가입
application/json
{
    "name": "홍길동",
    "email": "[email protected]",
    "password": "Password1!",
    "confirmPassword": "Password1!",
    "tellNumber": "010-7777-7777",
    "address": "서울시 용산구 351 오오오",
    "authCode": "131327"
}
POST /api/orders 주문 생성
application/json
[{
    "wishlistItemId": 1505
},
{
    "wishlistItemId": 1504
}]
PATCH /api/orders/{orderId}/status 주문 상태 변경
application/json
"CANCEL"
GET /api/products/{productId} 제품 조회
GET /api/products 제품 목록 조회
쿼리 파라미터
pageSize=5&listSort=PRICE_DESC&pageNumber=2&storeId=56
제품 검색
쿼리 파라미터
pageSize=5&listSort=PRICE_DESC&pageNumber=2&searchKeyword=21
카테고리별 제품 조회
쿼리 파라미터
pageSize=5&listSort=PRICE_DESC&pageNumber=2&productCategory=ACCESSORY
POST /api/wishlists 위시리스트 생성
application/json
[{
    "optionId": 1516,
    "quantity": 2
},
{
    "optionId": 1517,
    "quantity": 1
}]
GET /api/wishlists 위시리스트 조회
쿼리 파라미터
memberId=58
PATCH /api/wishlists/items/{itemId}/quantity 위시리스트 항목 수량 변경
application/json
{
  "action": "DECREASE"
}

⭐ 요구사항

💊 회복 탄력성(Resilience) 적용

📌 Resilience4j

Resilience4j를 통해 외부 API 호출 시 발생할 수 있는 장애로부터 시스템을 보호하는 기능을 구현하였습니다.

외부 서비스의 장애가 시스템에 미치는 영향을 최소화하여 회복 탄력성을 강화할 수 있도록 도와줍니다.

Resilience4j 도입 배경

프로젝트가 기존의 단일 애플리케이션 아키텍처(Monolithic Architecture, MA)에서 마이크로서비스 아키텍처(Microservices Architecture, MSA)로 변경되었습니다.

이 과정에서 Feign Client를 사용하여 다른 마이크로서비스와 통신하는 부분이 추가되었습니다. 이에 따라 외부 API 호출 시 발생할 수 있는 장애로부터 시스템을 보호하고, 각 마이크로서비스 간의 안정적인 통신을 보장하기 위해 Resilience4j를 도입하였습니다.

  • Circuit Breaker: 외부 서비스가 불안정할 때 자동으로 요청을 차단하여 시스템 과부하를 방지하고, 잠시 후 다시 시도할 수 있는 상태로 전환합니다.
  • Retry: 외부 서비스가 일시적으로 사용 불가능한 경우(예: 네트워크 문제, 서버 다운 등) 일정 횟수까지 재시도를 수행하여 일시적인 오류를 해결합니다.
Resilience4j 설정

리플라이 설정

resilience4j:
  retry:
    retry-aspect-order: 2 
    configs:
      default:
        max-attempts: 2 
        wait-duration: 500 
        retry-exceptions:
          - feign.FeignException.ServiceUnavailable  
        ignore-exceptions:
          - feign.FeignException.BadGateway
          - feign.FeignException.NotImplemented
          - feign.FeignException.FeignClientException
    instances:
      simpleRetryConfig:
        baseConfig: default
  • 설정 설명
    • 최대 재시도 횟수: 2회로 설정. 선착순 구매 시스템의 특성상 지나치게 많은 재시도가 시스템에 부담을 줄 수 있어 제한
    • 재시도 간격: 500ms로 설정. 너무 긴 대기 시간이 아니라 빠른 재시도를 통해 오류 해결 시도
    • 재시도할 예외: 서버가 일시적으로 사용 불가능한 경우(ServiceUnavailable)에만 재시도
    • 무시할 예외: 게이트웨이 오류나 클라이언트 오류 등은 재시도가 의미 없으므로 무시

서킷 브레이커 설정

resilience4j:
  circuitbreaker:
    circuit-breaker-aspect-order: 1
    configs:
      default:
        sliding-window-type: COUNT_BASED
        minimum-number-of-calls: 7
        sliding-window-size: 10
        wait-duration-in-open-state: 10s
        failure-rate-threshold: 50  
        slow-call-duration-threshold: 3000ms  
        slow-call-rate-threshold: 60  
        permitted-number-of-calls-in-half-open-state: 5
        automatic-transition-from-open-to-half-open-enabled: true
        record-exceptions:
          - feign.FeignException.ServiceUnavailable
          - feign.FeignException.GatewayTimeout
          - java.net.SocketTimeoutException
          - feign.FeignException.BadGateway
        ignore-exceptions:
          - feign.FeignException.NotImplemented
          - feign.FeignException.FeignClientException
    instances:
      simpleCircuitBreakerConfig:
        baseConfig: default
  • 설정 설명:
    • 슬라이딩 윈도우 유형: 요청 수 기반(COUNT_BASED)으로 빠르게 상태 판단
    • 최소 호출 수: 7회로 설정, 실패율 판단을 위해 최소 호출 수를 설정하여 안정성 확보
    • 실패율 임계값: 50%로 설정, 절반 이상의 요청이 실패하면 서킷이 열림
    • 느린 호출 임계값: 3초 이상 걸리는 호출을 실패로 간주
    • 반 개방 상태에서 허용할 호출 수: 5회, 시스템이 반 개방 상태에서 천천히 트래픽을 다시 받아들일 수 있도록 설정
    • 처리할 예외: 일시적인 서버 오류나 게이트웨이 문제를 처리
    • 무시할 예외: 클라이언트 측 오류는 서킷 브레이커를 무시

☁️ MSA 환경 구축

📌 Monolithic Architecture vs MicroService Architecture

  • MA(Monolithic Architecture) : 모든 기능이 하나의 애플리케이션 내부에 통합되어 있으며, 단일 코드베이스에서 작동하도록 하는 소프트웨어 설계
    • 장점: 개발과 관리가 용이합니다.
    • 단점: 시스템이 복잡해지고 커질수록 코드를 이해하기가 어려워지고 그럴수록 유지보수하기 어려워집니다.
  • MSA(Microservice Architecture) : 소프트웨어 시스템을 여러 작은 독립적인 서비스로 나누고, 각 서비스를 독립적으로 배포하고 운영하는 소프트웨어 설계
    • 장점: 대규모 애플리케이션을 더 작고 관리 가능한 단위로 분해함으로써, 개발, 배포, 확장, 유지보수 등의 측면에서 더 높은 유연성과 확장성을 제공합니다.
    • 단점: 여러 모듈들이 분산되어 있어 관리 및 모니터링이 힘들며, 통합 테스트가 힘듭니다.
MA vs MSA 비교표
MA (Monolithic Architecture) MSA (Microservices Architecture)
구조 하나의 통합된 애플리케이션 독립적인 여러 마이크로서비스
배포 전체 시스템을 하나의 단위로 배포 각 서비스 개별 배포 가능
확장성 전체 시스템 단위로 확장해야 함 필요한 서비스만 확장 가능
개발 속도 초기 개발은 빠름 복잡도 높아 초기 구축이 어려울 수 있음
유지 보수 코드베이스 커지면 어려워짐 서비스가 작아 유지 보수에 유리
기술 스택 하나의 통일된 기술 스택 사용 각 서비스별로 다른 기술 스택 선택 가능
복잡도 상대적 단순 서비스 간 통신, 데이터 일관성 관리가 어려움
운영 비용 단순, 적은 운영 리소스 필요 많은 리소스 필요 (모니터링, 네트워크 통신 등)
MSA 도입 배경
  • 확장성 : MSA는 개별 마이크로서비스 단위로 확장이 가능하여 특정 서비스의 트래픽이 많을 때만 확장이 가능합니다.
  • 유지보수
    • 모든 기능이 통합된 하나의 코드베이스는 시간이 지남에 따라 복잡해집니다.
    • 코드 수정 시 다른 기능에 영향을 미치는 경우가 많아 유지보수가 어려워집니다.
    • MSA는 서비스 단위로 코드가 나뉘어져 있어 유지보수가 용이합니다.
  • 의존성 : MSA에서는 서비스 간 의존성을 줄일 수 있습니다.

📌 Spring Cloud

분산 시스템을 구축하기 위한 Spring Framework의 확장 도구

MSA 환경에서 마이크로서비스 간의 통신, 설정 관리, 서비스 디스커버리, 로드 밸런싱, 장애 복구, 모니터링 등 다양한 기능을 제공하여 마이크로서비스의 복잡한 인프라 문제를 쉽게 해결할 수 있도록 돕는 도구입니다.

Spring Cloud 도입 배경
  • 서비스 간 통신 문제 해결
    • MSA 환경에서는 서비스들이 서로 다른 네트워크 상에서 통신해야 합니다.
    • 이를 쉽게 구현하기 위해 Spring Cloud는 서비스 디스커버리와 API Gateway를 제공합니다.
  • 설정 관리의 복잡성 해결 : 마이크로서비스가 많아질수록 각 서비스의 설정을 일관성 있게 관리하는 것이 어려워지는데, Spring Cloud Config를 통해 중앙에서 설정을 통합 관리할 수 있습니다.
  • 추적 및 모니터링의 필요성: 분산 추적과 모니터링 도구를 제공하여 운영의 투명성을 높입니다.
3개의 마이크로 서비스로 만들기
  • 서비스
    • 유저 서비스: 회원 로직(회원가입, 이메일 확인 등) 기능을 담당하는 서비스를 구현합니다.
    • 상품 서비스: 상품 로직(상품 조회 등) 기능을 담당하는 서비스를 구현합니다.
    • 주문 서비스: 주문 로직(주문 생성, 수정, 반품) 기능을 담당하는 서비스를 구현합니다.
  • 각 서비스는 독립적으로 배포 가능해야 합니다.
Feign client를 활용한 마이크로 서비스 간의 상호 작용

📌 서버간 통신

서비스 기능별로 구분해서 독립적인 애플리케이션을 개발하면 각 서비스 간 통신을 해야하는 경우가 발생합니다.

한 서버가 다른 서버에 통신을 요청하는 것을 서버간 통신이라고 합니다. 서버와 클라이언트의 구조가 되며 대표 적인 통신방식이 HTTP/HTTPS입니다.

📌 Feign Client

Spring Cloud에서 제공하는 HTTP 클라이언트로, 마이크로서비스 간의 통신을 간편하게 하기 위해 사용됩니다.

REST API를 호출할 때 HTTP 요청을 직접 작성하는 대신, 인터페이스를 정의하고 필요한 서비스 호출을 메서드처럼 사용할 수 있게 해줍니다.

  • 유저 서비스
    • 유저관련 내부 통신 api 제공
      • GET,/internal/v0/members/{memberId}/exists: memberId 존재 유무 확인 api
  • 상품 서비스
    • 상품관련 내부 통신 api 제공
      • PUT,/internal/v0/products/options/stock:상품 재고 업데이트 api
  • 주문 서비스
    • 유저 서비스, 상품 서비스 내부 통신 api feign client를 활용해 상호 작용
      @FeignClient(name = "member")
      public interface UserFeignClient {
      
        @GetMapping("/internal/v0/members/{memberId}/exists")
        boolean existsMemberId(@PathVariable Long memberId);
      
      }
      @FeignClient(name = "product")
      public interface ProductFeignClient {
      
        @PutMapping("/internal/v0/products/options/stock")
        void updateProductStock(@RequestBody UpdateQuantityByProductOptionsDto dto);
      
      }
Spring Cloud Gateway 만들기

📌 Spring Cloud Gateway

MSA 가장 앞단에서 클라이언트들로 부터 오는 요청을 받은 후 경로와 조건에 알맞은 마이크로서비스 로직에 요청을 전달하는 게이트웨이

📌 도입 배경

클라이언트에 제공되는 API가 세 서비스로 분산되어 있어
클라이언트는 각 서버가 제공하는 API 목록을 알아야 하며, 각 서버에 맞는 요청을 보내야 합니다.

각 서버의 정보를 클라이언트가 알아야해서 불편하고, 서비스 구조가 외부로 공개된다는 단점이 있어 Gateway가 필요합니다.

  • API GATEWAY 서비스를 새로 만들어 실행시키기(port: 8080)
  • 기존의 모노리스 서비스가 가지고 있던 모든 API 들을 API GATEWAY에 노출한다.
  • 해당 API로 들어온 요청을, 내부의 마이크로 서비스로 전달한다.
Eureka Server 만들기

📌 Eureka Server

Eureka는 Netflix에서 개발한 서비스 등록 및 디스커버리 도구로, MSA 환경에서 서비스 간 통신을 돕기 위해 각 서비스의 정보를 관리합니다. Eureka Server는 마이크로서비스들을 등록하고, 서로의 위치를 찾아주는 역할을 합니다.

📌 도입 배경

MSA에서는 서비스들이 독립적으로 배포되며, 각 서비스의 위치(IP, 포트)가 동적으로 변할 수 있습니다. 이를 해결하기 위해 서비스의 위치 정보를 동적으로 관리하는 Eureka Server가 필요합니다. 클라이언트는 Eureka에 등록된 서비스 주소를 통해 해당 서비스에 접근할 수 있습니다.

  • Eureka Server를 Spring Boot로 구성 (port: 8761)
  • @EnableEurekaServer 애너테이션으로 Eureka Server 활성화
  • 각 마이크로서비스들이 Eureka Client로 등록되도록 설정
  • Eureka Dashboard로 각 서비스 상태 확인 (http://localhost:8761)
Config Server & Config Repository 만들기

📌 Config Server

Config Server는 외부 설정 파일을 중앙에서 관리하며, 모든 마이크로서비스가 설정을 공유하고 동기화할 수 있도록 돕는 도구입니다. 이를 통해 서비스 재시작 없이 설정을 동적으로 변경할 수 있습니다.

📌 도입 배경

MSA 환경에서는 서비스마다 개별 설정이 존재하며, 이를 관리하는 것이 복잡합니다. Config Server를 사용하면 모든 설정을 중앙에서 관리하고 버전 관리가 가능해져, 서비스 간 설정 불일치 문제를 해결할 수 있습니다.

  • Spring Cloud Config Server를 사용하여 Config Server를 구축 (port: 8888)
  • Github를 Config Repository로 활용하여 설정 파일 관리
  • 각 마이크로서비스는 Config Server를 통해 설정을 로드하도록 설정
  • @EnableConfigServer 애너테이션을 사용하여 Config Server 활성화
  • Git Repository에 *.yml 파일을 생성하여 마이크로서비스별 설정 파일 저장

✅ 자동 테스트

본 프로젝트는 자동화된 테스트를 사용하여 안정성을 보장합니다.

📌 사용 도구

  • JUnit5:

    • 프로젝트의 주요 테스트 프레임워크로 사용되었으며, 각 계층의 테스트 케이스를 작성하고 실행하는 데 사용되었습니다.
  • Mockito:

    • Controller 단위 테스트에서 의존성 주입을 Mocking하여 외부 종속성과의 결합을 줄이고, 독립적으로 메서드를 테스트하기 위해 사용되었습니다.
  • JaCoCo:

    • 코드 커버리지 분석 도구로, 테스트 케이스가 전체 코드베이스에서 얼마나 많은 부분을 커버하고 있는지 확인하기 위해 사용했습니다. 현재 프로젝트의 커버리지는 92.7%입니다.
  • SonarQube:

    • 코드 품질 분석 도구로, 코드 내의 잠재적인 버그, 보안 문제, 중복 코드, 유지보수성 등을 검토하고, 코드 품질을 지속적으로 개선하기 위해 사용했습니다.

커버리지 및 품질 결과

  • JaCoCo 보고서:
    • 테스트 커버리지는 전체 코드베이스의 92.7%에 달하며, 이를 통해 주요 비즈니스 로직이 충분히 검증되었음을 확인했습니다.
  • SonarQube 분석 결과:
    • SonarQube에서 보안, 신뢰성, 유지보수성 측면에서 모두 A 등급을 받았으며, 코드 품질에 대한 높은 기준을 유지하고 있습니다.
    • 중복 코드 비율은 0.0%이며, 보안 취약점 및 핫스팟도 발견되지 않았습니다.
테스트 종류 및 계층
  • Controller 단위 테스트:

    • Controller 계층에서는 JUnit5와 Mockito를 사용하여 단위 테스트를 수행했습니다. 이를 통해 각 Controller 메서드의 로직을 개별적으로 검증하고, Mock 객체를 사용하여 종속성을 분리하였습니다.
  • Service 및 Repository 통합 테스트:

    • Service 및 Repository 계층에서는 통합 테스트를 진행하여 각 계층 간의 상호작용을 검증했습니다. 이를 통해 실제 데이터베이스와의 연동을 포함한 통합적인 로직의 정상 작동을 보장하였습니다.

🙆🏻‍♀️ 유저 서비스

회원가입 및 로그인
  • 회원가입 기능을 통해 사용자는 계정을 생성할 수 있습니다.
    • 이메일 인증을 통한 회원가입 기능을 만든다.
    • 개인정보, 이름, 비밀번호, 주소, 이메일암호화하여 저장한다.
회원가입 및 로그인 회원가입 및 로그인
  • 로그인 시 access-token 발급한다.

📦 상품 서비스

상품 상세&리스트 조회
  • 등록되어 있는 상품의 리스트를 보여주고 사용자가 구매할 수 있는 인터페이스를 제공합니다.

  • 상품을 클릭시 상품의 상세 정보를 제공해야합니다.

    • 상품의 재고 관리를 위한 유저 인터페이스는 별도로 구현하지 않습니다.
    상품 조회 상품 조회

💸 주문 서비스

위시리스트 등록 및 조회
  • 사용자의 노출된 상품에 한하여 주문 및 WishList에 등록

  • WishList에서 내가 등록한 상품에 대한 정보 조회

    • 제품의 상세 페이지로 이동
  • 상품의 수량 변경

  • 위시리스트 내 항목의 수정

    위시리스트 로직 위시리스트 로직
마이페이지에서 주문 생성
  • 마이페이지에서 위시리스트를 통해 주문을 생성할 수 있습니다.

    상품 조회 마이페이지에서 주문 생성
주문 상태 자동 변경
  • 주문 상태 변경

    • 주문 상품에 대한 상태 조회(주문 후 D+1에 배송 중, D+2일에 배송 완료가 됩니다.)
    주문 상태 자동 변경 주문 상태 자동 변경
주문 취소
  • 상품에 대한 주문 취소 기능을 제공합니다.

    • 주문 내역중 일부 상품에 대한 취소는 없다고 가정합니다.
  • 주문 취소

    • 주문 상태가 배송중이 되기 이전까지만 취소가 가능합니다.
    • 취소 후에 는 상품의 재고를 복구 되어야 합니다 주문 취소 후 상태는 취소 완료로 변경 됩니다.
    주문 취소 주문 취소
주문 반품
  • 상품에 대한 주문 반품 기능을 제공합니다.

    • 주문 내역중 일부 상품에 대한 반품은 없다고 가정합니다.
  • 반품신청

    • 배송 완료 후 D+1일까지만 반품이 가능하고 그 이후에는 반품이 불가능 합니다.
    • 배송 완료가 된 상품에 대해서만 반품이 가능합니다.
  • 반품완료

    • 반품한 상품은 반품 신청 후 D+1에 재고에 반영 됩니다. 재고에 반영된 후 상태는 반품 완료로 변경됩니다.
    주문 반품 주문 반품

⭐ 데이터베이스

DB

About

전자상거래 MA에서 MSA로

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published