TIL

24.09.11 TIL - MSA Service 공통 처리

개발공명 2024. 9. 12. 03:08

오늘 배운 것

  • Dependency 추가
  • BaseEntity 추가

 

 

개요

MSA 형태의 프로젝트를 진행하는데 각 서비스에서 설정해야 하는 것이 많이 있다. 

 

이때 공통적으로 각 서비스에 설정해야 하는 것들이 있다. 

 

이런 공통적인 것들을 작성해 봤다. 

 

각 서비스에서 추가해야 하는 것들이 어떤 것들이 있는지 알아보자. 

 

 

Dependency 추가

우선 추가한 Dependency들은 다음과 같다. 

  • Spring Web
  • Lombok
  • Spring Security
  • Spring Data JPA
  • PostgreSQL Driver
  • Validation
  • Spring Boot Actuator
  • Zipkin
  • Prometheus
  • Eureka Discovery Client
  • OpenFeign

위의 dependency는 Spring Initializer에서 추가하였다.

 

 

여기에 추가로 서킷 브레이커를 사용하기 위해 Resilience4j를 별도로 추가했다. 

 

Resilience4j도 Spring Initializer에 있는데 따로 추가한 이유는 아래와 같다. 

 

Spring Initializer에 있는 Resilienece4j는 추상화 계층이라 실제 사용하려면 구현되어 있는 Github의 dependency를 추가해야 한다. 

  • Resilience4j
  • Resilience4j Dashboard

 

 

코드를 보면 아래와 같다. 

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.3.3'
	id 'io.spring.dependency-management' version '1.1.6'
}

group = 'msa.logistics.service'
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

ext {
	set('springCloudVersion', "2023.0.3")
}

dependencies {
	// actuator
	implementation 'org.springframework.boot:spring-boot-starter-actuator'

	// Spring Data JPA
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

	// Spring Security
	implementation 'org.springframework.boot:spring-boot-starter-security'

	// Bean Validation
	implementation 'org.springframework.boot:spring-boot-starter-validation'

	implementation 'org.springframework.boot:spring-boot-starter-web'

	// Zipkin
	implementation 'io.micrometer:micrometer-tracing-bridge-brave'
	implementation 'io.zipkin.reporter2:zipkin-reporter-brave'

	// Eureka Client
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

	// FeignClient
	implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

	// Resilience4j
	implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
	implementation 'org.springframework.boot:spring-boot-starter-aop'

	// Resilience4j dashboard
	implementation 'io.github.resilience4j:resilience4j-micrometer'
	implementation 'io.micrometer:micrometer-registry-prometheus'

	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
	runtimeOnly 'org.postgresql:postgresql'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

tasks.named('test') {
	useJUnitPlatform()
}

 

Spring Boot는 3.3.3 버전이고 Java는 17버전 사용했다.

 

Gradle-Groovy 프로젝트로 설정했고 Packging은 JAR를 사용하였다. 

 

 

각 dependency에 대해서 보자. 

 

우선 기본적으로 웹 백엔드 프로젝트를 위해 아래의 것을 추가한 것이다. 

  • Spring Web
  • Lombok

그리고 아래의 test나 junit은 Spring Initializer로 생성한 경우 자동으로 추가되는 테스트 관련 dependency다. 

implementation 'org.springframework.boot:spring-boot-starter-web'

compileOnly 'org.projectlombok:lombok'

annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

 

그리고 DB는 Postgresql을 사용하기로 하였다. 

 

또한 DB를 편하게 사용하기 위해 Spring Data JPA를 추가하였다. 

  • Spring Data JPA
  • PostgreSQL Driver
// Spring Data JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// Postgresql
runtimeOnly 'org.postgresql:postgresql'

 

그리고 MSA에서 각 서비스에서 권한 처리를 해줘야 한다고 한다. 

 

Request Header에서 오는 JWT를 가지고 정보를 얻어야 한다. 

 

그 후 SecurityContextHolder에 권한을 넣고 서비스에서 권한 체크를 해야 한다. 

 

이런 기능을 사용하기 위해 Spring Security를 추가하였다. 

  • Spring Security
// Spring Security
implementation 'org.springframework.boot:spring-boot-starter-security'

 

그리고 Bean Validation을 사용하기 위해 Validation을 추가하였다. 

  • Validation
// Bean Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

 

Zipkin, Prometheus 등을 사용하기 위해 Spring Actuator를 추가해줘야 한다. 

  • Spring Boot Actuator
// actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'

 

 

그리고 MSA에서 각 서비스를 분산 추적하기 위해 Zipkin을 사용하기로 하였다. 

 

현재 개발하려는 서비스도 분산 추적의 대상이 되어야 하니 Zipkin dependency를 추가해줘야 하는 것이다. 

  • Zipkin
// Zipkin
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave'

 

모니터링을 위해 Prometheus와 Grafana를 사용할 것이다. 

 

Prometheus와 Grafana를 사용하기 위해 Prometheus dependency도 추가했다. 

  • Prometheus
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'

 

그리고 이제 이 Service를 MSA에서 사용하니 Eureka Client로 설정해줘야 한다. 

 

그리고 다른 Service와 통신하기 위해 FeignClient를 사용하니 이것도 추가해줘야 한다. 

  • Eureka Discovery Client
  • OpenFeign
// Eureka Client
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

// FeignClient
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

 

서킷 브레이커로 Resilience4j를 사용하고 이것을 모니터링 하기 위해 Resilience4j Dashboard도 사용하기로 했다. 

 

이를 위해 아래의 코드를 직접 추가해줘야 한다. 

  • Resilience4j
  • Resilience4j Dashboard
// Resilience4j
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
implementation 'org.springframework.boot:spring-boot-starter-aop'

// Resilience4j dashboard
implementation 'io.github.resilience4j:resilience4j-micrometer'
implementation 'io.micrometer:micrometer-registry-prometheus'

 

 

BaseEntity 추가

그리고 모든 엔티티들에 추가해줘야 하는 값들이 있다. 

 

생성자, 생성 시간, 수정자, 수정 시간, 삭제자, 삭제 시간 이런 필드들은 DB에서 엔티티들을 관리하는데 중요한 필드들이다. 

 

이런 모든 엔티티에 필요한 공통 필드들을 BaseEntity라는 클래스에 넣는다.

 

그리고 모든 엔티티가 BaseEntity를 상속 받게 하면 된다. 

 

그리고 JpaAuditing 기술을 사용하여 이 필드들의 값을 자동으로 넣게 해주면 된다. 

 

하지만 삭제의 경우 직접 DB에서 값을 날리는 것보다 is_delete 같은 필드에 true, false 값을 넣어 처리하는 것이 좋다고 한다. 

 

왜냐하면 DB에서 값을 실제로 삭제하게 되면 백업하거나 롤백할 때 그 정보를 되돌릴 수 없기 때문이다. 

 

이런 것을 soft delete라고 하는데 이번 프로젝트에서는 soft delete를 사용하는 것이다. 

import static lombok.AccessLevel.PROTECTED;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
@NoArgsConstructor(access = PROTECTED)
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity implements Serializable {

    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @CreatedBy
    private String createdBy;

    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    @LastModifiedBy
    private String updatedBy;

    @Column(name = "deleted_at")
    protected LocalDateTime deletedAt;

    protected String deletedBy;
    
    @Column(name = "is_delete")
    protected Boolean isDelete;
}

 

to be continued

여기에 각 기술들을 사용하는데 필요한 설정들을 해줘야 한다. 

 

application.yml 파일에 각 설정들에 대한 정보를 넣어줘야 한다. 

 

추후에 기회가 되면 각 설정들을 어떻게 해야 하는지 작성해 보겠다. 

 

그리고 팀 프로젝트에서 정한 공통 응답, 공통 예외 처리가 있다. 

 

이런 것도 설정하는 방법을 추후에 작성해 보겠다.