프로젝트명

  • MSA-Delivery

프로젝트 인원

  • 김지수, 김예원, 윤홍찬, 이현민

API 명세서

허브

생성

 

수정

 

삭제

 

전체 조회 및 검색

 

상세 조회


허브간 이동 경로

생성

 

수정

 

삭제

 

전체 조회 및 검색

 

상세 조회


주문

생성

 

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제


슬랙 메시지

생성

 

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제


유저

회원가입

 

로그인

 

전체 조회 및 검색

 

수정

 

상세 조회

 

삭제


배송

배송 및 배송 경로 생성

 

전체 조회 및 검색

 

상세 조회

 

수정

삭제


배송 경로

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제

 


배송 담당자

생성

 

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제


업체

생성

 

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제

 


상품

생성

 

전체 조회 및 검색

 

상세 조회

 

수정

 

삭제


테이블 명세서

 


ERD 명세서


인프라 설계서

포트 번호

  • EUREKA : 19090
  • GATEWAY : 19091
  • SLACK : 19092
  • USER : 19094
  • COMPANY : 19096
  • ORDER: 19098
  • DELIVERY: 19100
  • HUB : 19102

[241206 TIL]

대규모 AI 시스템 설계 프로젝트


1. 브랜치 생성 및 작업

Step 1: 브랜치 생성

develop 브랜치에서 새 브랜치를 생성합니다.

git checkout develop  # develop 브랜치로 이동
git pull origin develop  # 최신 상태로 동기화
git checkout -b feature/add-templates  # 새 브랜치 생성

2. 템플릿 파일 생성

.github 디렉터리와 템플릿 파일을 생성합니다.

Step 1: 디렉터리 생성

mkdir -p .github/ISSUE_TEMPLATE  # 이슈 템플릿 디렉터리 생성

Step 2: 파일 생성

# Bug Report 템플릿 생성
cat > .github/ISSUE_TEMPLATE/bug_report.md << EOF

내용 작성

EOF

# Feature Request 템플릿 생성
cat > .github/ISSUE_TEMPLATE/feature_request.md << EOF

내용 작성

EOF

# Pull Request 템플릿 생성
cat > .github/PULL_REQUEST_TEMPLATE.md << EOF

내용 작성

EOF

3. 변경사항 커밋 및 푸시

Step 1: 변경사항 확인

git status  # 변경된 파일 확인

Step 2: 스테이징

git add .github/  # .github 디렉터리 및 내부 파일 추가

Step 3: 커밋

git commit -m "feat: add issue and PR templates"

Step 4: 푸시

git push -u origin feature/add-templates

4. PR 생성

GitHub 웹사이트에서 feature/add-templates 브랜치에 대해 PR을 생성하고, 코드 리뷰를 요청합니다.


[241205 TIL]

JPA 도움닫기


REST API, Spring Security, JPA 연관관계와 영속성 컨텍스트 정리


1. REST API 메서드와 역할

REST API는 클라이언트-서버 간 통신을 위한 표준으로, 5가지 주요 메서드를 제공합니다.

REST API 메서드

  1. GET
    • 서버의 리소스에 액세스.
    • 데이터를 필터링하기 위해 쿼리 파라미터 사용 가능.
    • 예: GET /users?id=1
  2. POST
    • 데이터를 서버에 전송하여 리소스를 등록하거나 저장.
    • Body에 JSON, XML 등의 데이터를 포함하여 전송.
    • 예: POST /users (Body: { "name": "John" })
  3. PUT
    • 서버의 기존 리소스를 전체 업데이트.
    • 제공된 데이터로 리소스의 모든 필드를 수정.
    • 예: PUT /users/1 (Body: { "name": "John", "age": 30 })
  4. PATCH
    • 서버의 기존 리소스를 부분 업데이트.
    • 예: PATCH /users/1 (Body: { "name": "John" } → "name" 필드만 수정)
  5. DELETE
    • 리소스를 제거.
    • 인증 및 권한이 필요.
    • 예: DELETE /users/1

2. Spring Security - 인증과 인가

Spring Security는 애플리케이션 보안을 위한 강력한 도구로, **인증(Authentication)**과 인가(Authorization) 기능을 제공합니다.

Authentication (인증)

  • 사용자의 신원을 확인하는 과정.
  • 다양한 인증 방식을 지원:
    • Username/Password
    • OAuth2
    • Bearer Token
  • 인증 흐름: Authentication Filter에서 요청의 인증 정보를 추출 및 검증.

Authorization (인가)

  • 사용자의 권한을 확인하여 특정 리소스에 대한 접근 제어.
  • 엔드포인트 별로 권한을 설정할 수 있음:
    • /admin/** → ADMIN 권한 필요.
    • /users/** → USER 권한 필요.
    • /auth/** → 인증 불필요.
  • 설정 예:
    http.authorizeRequests()
        .antMatchers("/auth/**").permitAll()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated();
    

3. JPA의 연관관계와 영속성 컨텍스트

JPA는 데이터베이스의 테이블 간 관계를 객체지향적으로 매핑하여 관리합니다.

JPA 연관관계

  1. 일대일(1:1)
    • 한 엔티티가 다른 엔티티와 1:1로 매핑.
    • 예: 상품 기본정보/상품 상세정보, 회원 정보/회원 프로필 정보.
  2. 일대다(1:N), 다대일(N:1)
    • 한 엔티티가 여러 개의 엔티티와 매핑.
    • 예: 게시글/좋아요, 주문/상품.
  3. 다대다(N:M)
    • 여러 엔티티가 여러 개의 다른 엔티티와 연결.
    • 예: 학생/과목, 게시글/태그.
    • 보통 중간 테이블을 사용하여 관리.

Persistence Context (영속성 컨텍스트)

JPA의 핵심 요소로, 엔티티 객체를 저장 및 관리하며 데이터베이스와의 작업을 효율화.

상태

  1. 비영속 (Transient)
    • 엔티티가 영속성 컨텍스트에서 관리되지 않는 상태.
  2. 영속 (Managed)
    • 엔티티가 영속성 컨텍스트에서 관리되는 상태.
    • 변경 감지(Dirty Checking), 쓰기 지연 등의 기능 지원.
  3. 준영속 (Detached)
    • 관리되던 엔티티가 영속성 컨텍스트에서 분리된 상태.
  4. 삭제 (Removed)
    • 엔티티가 삭제 상태로 표시되며, 트랜잭션이 끝나면 데이터베이스에서도 삭제.

장점

  • ACID 보장: 트랜잭션의 원자성, 일관성, 격리성, 지속성 보장.
  • 쓰기 지연 (Write-Behind)
  • 변경 감지 (Dirty Checking)

영속 상태로 만드는 방법

  1. @Transactional 선언.
  2. Repository에서 엔티티를 저장하거나 조회.

[241204 TIL]

프로젝트 관리 심화

대규모 스트림 처리 강의


 

⚠️ 트러블슈팅 ⚠️


1. 문제 정의

Kafka 실습 중 Docker Compose로 Kafka 환경을 구성했으나, Kafka UI에서 클러스터가 Offline 상태로 표시되고 정상적으로 동작하지 않음.


2. 원인 추론

  1. Docker 이미지 아키텍처 문제
    • Docker Desktop에서 "image may have poor performance, or fail if run via emulation" 경고 메시지가 출력됨.
    • 이는 Docker 이미지가 호스트 아키텍처와 일치하지 않아 발생.
  2. Kafka UI 타임아웃 문제
    • Kafka UI 이미지를 다운로드하는 과정에서 TLS handshake timeout 오류 발생.
    • 네트워크 문제 또는 Docker Hub와의 연결 문제로 인해 이미지 다운로드 실패.
  3. Docker Compose 설정 문제
    • 기존 docker-compose.yml 파일이 AMD64 아키텍처용 이미지로 구성되어 ARM64 호스트 시스템에서 실행 불가.

3. 해결 방안 및 결과

1) 호스트 아키텍처 확인

  • uname -m 명령어를 실행하여 호스트 시스템 아키텍처를 확인:
    uname -m
    
  • 출력 결과: arm64
    → 호스트 시스템이 ARM64 아키텍처임을 확인.

2) Docker Compose 이미지 교체

  • 기존 Docker Compose 파일에서 AMD64 전용 이미지ARM64 지원 이미지로 교체.

변경된 Docker Compose 파일:

version: '3.8'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    platform: linux/arm64
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: confluentinc/cp-kafka:latest
    platform: linux/arm64
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:29092,OUTSIDE://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_LISTENERS: INSIDE://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092
      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181

  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    platform: linux/arm64
    ports:
      - "8080:8080"
    environment:
      KAFKA_CLUSTERS_0_NAME: local
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
      KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181
      KAFKA_CLUSTERS_0_READONLY: "false"

3) Kafka UI 이미지 수동 다운로드

  • Kafka UI 다운로드 시 타임아웃 오류 해결을 위해 수동으로 이미지를 다운로드:
    docker pull provectuslabs/kafka-ui:latest
    
  • 수동 다운로드 완료 후, docker-compose up 명령어로 다시 실행.

결과

  1. Kafka UI에서 클러스터가 Online 상태로 표시됨.
  2. Zookeeper, Kafka, Kafka UI 모두 ARM64 환경에서 정상 실행.
  3. Kafka 실습을 성공적으로 진행 가능.

[241203 TIL]

프로젝트 관리 심화

MSA 개인 프로젝트


3단계: 핵심 기능 추가

  1. Weighted Load Balancing (상품 서비스)
    • 상품 서비스를 19093, 19094 포트로 각각 실행.
    • Weighted Load Balancing (70:30) 구성.
    • 상품 목록 조회 시 로드 밸런싱이 작동하는지 확인.
  2. Fallback 처리
    • Resilience4j를 Order Service에 적용하여 상품 서비스 호출 실패 시 Fallback 처리 구현.
    • Fallback 메서드에서 적절한 메시지 반환.
  3. Redis 캐싱
    • Product Service에 캐싱 적용 (GET /products).
    • 주문 서비스의 GET /orders/{id} 결과를 Redis에 캐싱하여 조회 성능 향상.
    • 캐싱 갱신
      • Product Service에서 상품 추가 시 Redis 캐시를 갱신하도록 구현.
  4. 주문에 상품 추가
    • PUT /orders/{orderId} API 구현.
    • Feign Client를 사용하여 상품 존재 여부 검증 후 주문에 상품 추가.

[241202 TIL]

프로젝트 관리 심화

MSA 개인 프로젝트


1단계: 초기 환경 설정

1. 프로젝트 설계

  • 서비스 정의
    • Eureka Server: 서비스 등록/발견.
    • Gateway: API Gateway 역할로 라우팅, 인증/인가 담당.
    • Product Service: 상품 관리.
    • Order Service: 주문 관리.
    • Auth Service: 사용자 인증/인가.
  • 기술 스택
    • Spring Boot, Spring Cloud Netflix (Eureka, Gateway).
    • Spring Security (OAuth2, JWT).
    • Redis (캐싱), RabbitMQ (비동기 처리).
    • Zipkin (분산 추적).

2. 환경 설정

  • 공통 설정
    • application.yml을 dev/prod 환경으로 나눠 설정.
    • Eureka Server 실행 후 서비스들이 정상적으로 등록되도록 구성.
  • Docker Compose
    • Redis, Zipkin 등 의존성 추가.
    version: '3.8'
    services:
      redis-stack:
        image: redis/redis-stack
        container_name: redis-stack-compose
        restart: always
        ports:
          - 6379:6379
          - 8001:8001
      zipkin:
        image: openzipkin/zipkin:2.24.0
        container_name: zipkin
        ports:
          - 9411:9411
    

3. 기본 모듈 생성

  1. 각 서비스의 디렉토리 구조를 생성하고 Spring Boot 프로젝트로 초기화.
  2. 각 서비스에 application.yml 작성:
    spring:
      application:
        name: product-service
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:19090/eureka/
    

2단계: API 설계 및 기본 기능 구현

1. Eureka Server

  • 구현 방법
    • Spring Boot 프로젝트 생성 후 @EnableEurekaServer 추가.
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    }

2. Gateway

  • 라우팅 설정
spring:
  cloud:
    gateway:
      routes:
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/auth/**
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/products/**
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/orders/**
  • JWT 인증 필터
@Component
public class LocalJwtAuthenticationFilter implements GlobalFilter {
    @Value("${service.jwt.secret-key}")
    private String secretKey;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // JWT 검증 로직
        String token = extractToken(exchange);
        if (token == null || !validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

3. Auth Service

  • 회원가입 API
@RestController
@RequestMapping("/auth")
public class AuthController {
    @PostMapping("/sign-up")
    public ResponseEntity<?> signUp(@RequestBody SignupRequestDto requestDto) {
        return ResponseEntity.status(HttpStatus.CREATED).body(authService.signUp(requestDto));
    }
}
  • JWT 생성
public String createAccessToken(String username, UserRoleEnum role) {
    return Jwts.builder()
            .claim("username", username)
            .claim("role", role)
            .signWith(secretKey, SignatureAlgorithm.HS512)
            .compact();
}

4. Product Service

  • 상품 추가 API
    @PostMapping("/products")
    public ResponseEntity<Product> addProduct(@RequestBody Product product) {
        return ResponseEntity.ok(productService.addProduct(product));
    }

5. Order Service

  • 주문 추가 API
    @PostMapping("/orders")
    public ResponseEntity<OrderResponseDto> createOrder(@RequestBody OrderRequestDto requestDto) {
        return ResponseEntity.ok(orderService.createOrder(requestDto));
    }

+ Recent posts