ERD
개요
- 한정 수량의 쿠폰을 먼저 신청한 사용자에게 제공하는 이벤트
- Mysql 기반 쿠폰 발급 기능을 개발한다.
- Redis 기반 구판 발급 기능을 개발한다.
- AWS에 서버를 배포하고 Locust 를 통해 부하테스트를 진행 한다.
요구사항
- 이벤트 기간내에 발급
- 유저당 1번의 쿠폰 발급
- 선착순 쿠폰의 최대 쿠폰 발급 수량 설정
기능
- 쿠폰 발급 기능
- 쿠폰 발급 기간 검증
- 쿠폰 발급 수량 검증
- 쿠폰 전체 발급 수량
- 중복 발급 요청 검증
- 쿠폰 발급
- 쿠폰 발급 수량 증가
- 쿠폰 발급 기록 저장
- 쿠폰 ID
- 유저 ID
목표
- 정확한 발급 수량 제어 (동시성 이슈 처리)
- 높은 처리량
- 멀티 모듈 사용
- gradle - kotlin 경험.
깃 컨벤션
- build: 빌드, 의존성 추가
- feat: 새로운 기능 추가
- fix: 에러 수정
- docs: 문서 수정
- style: 코드 포맷팅, 세미콜론 누락 등 코드에 변경이 없는 경우
- refactor: 코드 리팩토링
- test: 테스트 코드 작성, 리팩토링
- rename: 파 이름 변경
- remove: 파일 삭제
- conf: 설정 파일
기술 스택
- Java 17
- Spring Boot3
- IntelliJ
- MySql
- h2
- JPA
- QueryDel
- Redis
- Spring Actuator
- Grafana
- AWS
- Locust
멀티 모듈 설정
프로젝트 생성(프로젝트 이름 coupon) - gradle Kotlin 선택 후 설정한다.
프로젝트의 src 폴더를 삭제하고, root 폴더에 coupon-api, coupon-core, coupon-consumer 모듈을 추가한다. 설정값은 coupon 프로젝트와 동일하다.
각 모듈의 기능
coupon-api
- 쿠폰에 대한 api 서버이다
- 유저의 요청을 처리한다.
coupon-consumer
- 쿠폰을 비동기적 구조로 발급할 것인데, 발급에 대한 요청이 쌓일 텐데 그 목록을 읽어 실제 쿠폰 발급을 처리 하는 서버이다.
coupon-core
- api, server 에서 공통적으로 사용하는 기능들을 담을것이다.
- entity, repository 접근 등을 구현해 중복되는 코드를 줄인다.
패키지 구조 정리
coupon-api, coupon-consumer, coupon-core 모듈에서 src, .gitognore, build.gradel.kts 파일 제외하고 모두 삭제해준다.
Gradle 구조 정리
coupon 에서 api, core, consumer 를 관리할 것인데 기존 구조는 맞지 않는다.
coupon 제외 모두 삭제해준다.
삭제 후, coupon의 setting.gradle.kts 에 include 를 추가해준다.
rootProject.name = "coupon"
include("coupon-core", "coupon-api", "coupon-consumer")
build.gradle.kts 의존성 추가
val bootJar: org.springframework.boot.gradle.tasks.bundling.BootJar by tasks
bootJar.enabled = false
plugins {
java
id("org.springframework.boot") version "3.4.0"
id("io.spring.dependency-management") version "1.1.6"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
subprojects {
apply(plugin = "java")
apply(plugin = "io.spring.dependency-management")
apply(plugin = "org.springframework.boot")
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
runtimeOnly("com.h2database:h2")
runtimeOnly("com.mysql:mysql-connector-j")
implementation("org.springframework.boot:spring-boot-starter")
implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("io.micrometer:micrometer-registry-prometheus")
annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jakarta")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")
annotationProcessor("jakarta.persistence:jakarta.persistence-api")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
subprojects:
최상단 프로젝트 coupon 의 하위인 모듈에 대해 위 설정값을 적용하겠다.
coupon-core 의 build.gradle
val bootJar: org.springframework.boot.gradle.tasks.bundling.BootJar by tasks
bootJar.enabled = false
repositories {
mavenCentral()
}
dependencies {
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("org.redisson:redisson-spring-boot-starter:3.16.4")
implementation("org.springframework.boot:spring-boot-starter")
implementation("com.github.ben-manes.caffeine:caffeine")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
coupon-api, coupon-consumer 의 build.gradle
dependencies {
implementation(project(":coupon-core"))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
api, consumer 둘 다 coupon-core에 의존하게 설정한다. = core 에 있는 모듈을 사용한다.
설정 했다면, 잘됐는지 확인해준다
- gradle - reload all project
- coupon - Tasks-build-build ㅕ
최상단 프로젝트이기 때문에 하위 프로젝트 모두 빌드된다.
BUILD SUCCESSFUL 이게 뜨면 설정 완료.
application.yml 파일 설정
하위 모듈의 applicaiton.properties 파일을
applicaiotn-core.yml
applicaion-api.yml
applicaion-consumer.yml
이런 형식으로 바꿔준다.
Coupon-core 모듈 정리
coupon-core 는 독립적으로 사용하는 것이 아닌, 다른 프로젝트에 의존해 사용할 것이기 때문에 CouponCoreApplication class를 삭제하고 - CouponCoreConfiguration class 를 생성한다.
package com.example.couponcore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
public class CouponCoreConfiguration {
}
CouponCoreApplicationTest class 또한 삭제해준다.
Coupon-consumer모듈 설정
CouponConsumerApplication 를 수정해준다.
package com.example.couponconsumer;
import com.example.couponcore.CouponCoreConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@Import(CouponCoreConfiguration.class)
@SpringBootApplication
public class CouponConsumerApplication {
public static void main(String[] args) {
System.setProperty("spring.config.name", "application-core, application-consumer");
SpringApplication.run(CouponConsumerApplication.class, args);
}
}
yml파일을 수정해준다.
spring:
application:
name: coupon-consumer
server:
port: 8081
coupon-api 모듈 설정
CouponApiApplication class를 수정해준다.
@SpringBootApplication
public class CouponApiApplication {
public static void main(String[] args) {
System.setProperty("spring.config.name", "application-core, application-api");
SpringApplication.run(CouponApiApplication.class, args);
}
}
yml 파일을 수정해준다.
spring:
application:
name: coupon-api
server:
port: 8080
api, consumer Application 을 실행 시켜보고, 8080, 8081 포트가 잘 실행된다면
성공~
'JAVA > 프로젝트' 카테고리의 다른 글
쿠폰 선착순 발급 이벤트 - locust 설정, docker-compose.yml 작성 (0) | 2024.11.28 |
---|---|
쿠폰 선착순 발급 이벤트 - MySql, Docker 설정, 포트 충돌 해결. (0) | 2024.11.28 |
배포 자동화 - jenkins를 통해 만든 .jar 파일 운영 환경 서버에 배포하기 (0) | 2024.11.26 |
배포 자동화 - jenkins, ngrok, Webhooks (0) | 2024.11.26 |
배포 자동화 - 이론. CICD, Gradle, Jenkins (0) | 2024.11.25 |