[Springboot] web+jpa vs webflux+r2dbc 비교 (2)
이번 포스팅에서 starter-web + starter-data-jpa를 이용한 servlet-stack 방식과 starter-webflux + starter-data-r2 dbc를 이용한 reactive-stack 방식의 성능 비교를 해봤었다.
2022.12.04 - [Server] - [Springboot] web+jpa vs webflux+r2dbc 비교 (1)
[Springboot] web+jpa vs webflux+r2dbc 비교 (1)
기존의 개발 방식으로 많이 사용하는 starter-web + starter-data-jpa 라이브러리를 사용하여 servlet stack 방식을 많이 사용하고 있을것이다. 최근 webflux + r2dbc 라이브러리를 이용하여 비동기(async) & 논블
tistory.minikode.com
이전 포스팅에서 다른 방식으로 개선해볼 수 있을까?
이전 포스팅에서는 mariadb 를 이용해서 성능 비교를 해봤고, 이번 포스팅에서는 Nosql의 대표적인 mongodb 를 이용해서 비교를 해보려 한다.
mongodb connection을 이용하기 위해
implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
를 추가해준다.
그리고 mongodb 설정을 위해 application.yaml 설정을 추가해준다. 필자는 로컬에 mongodb를 설치해서 진행했다.
application.yaml
spring:
data:
mongodb:
database: 'webflux'
# username:
# password:
host: localhost
port: 27017
또 starter-data-monogodb-reactive 라이브러리에서 지원해주는 기능을 사용하기 위해 config 설정도 필요하다.
MongoConfig.kt
import org.springframework.context.annotation.Configuration
import org.springframework.data.mongodb.config.EnableMongoAuditing
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories
@Configuration
@EnableMongoAuditing
@EnableReactiveMongoRepositories(basePackages = ["com.minikode.webflux_demo.mongo.repository"])
class MongoConfig {
}
이후 이전 포스팅과 마찬가지로 비교에 필요한 코드를 구성해보았다.
servlet-stack 코드
기본적인 controller, service, repository, entity를 구성
controller
import com.minikode.webflux_demo.mongo.entity.MemberEntity
import com.minikode.webflux_demo.service.MemberService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.util.*
@RestController
@RequestMapping("/mg")
class MongoController(
private val memberService: MemberService,
) {
@PostMapping("/")
fun save(): ResponseEntity<Mono<MemberEntity>> {
return ResponseEntity.ok(memberService.saveMember())
}
@GetMapping("/")
fun find(): ResponseEntity<Flux<MemberEntity>> {
return ResponseEntity.ok(memberService.findMembers())
}
}
service
import com.minikode.webflux_demo.mongo.entity.MemberEntity
import com.minikode.webflux_demo.mongo.repository.MemberRepository
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.util.*
@Service
class MemberService(
private val memberRepository: MemberRepository,
) {
fun saveMember(): Mono<MemberEntity> {
val memberEntity = MemberEntity()
memberEntity.memberId = UUID.randomUUID().toString()
memberEntity.name = "이름은 minikode"
return memberRepository.save(memberEntity)
}
fun findMembers(): Flux<MemberEntity> {
return memberRepository.findAll()
}
}
repository
import com.minikode.webflux_demo.mongo.entity.MemberEntity
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
interface MemberRepository : ReactiveMongoRepository<MemberEntity, String> {
}
entity
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.relational.core.mapping.Column
import java.util.*
@Document(collection = "member")
class MemberEntity {
@Id
var memberId: String? = null
var name: String? = null
}
위 코드로 코드를 작성했고, jMeter를 이용해서 성능 비교를 해보았다.
각 controller의 save(), find()를 각각 동시 500명이 10번 반복하도록 설정했다.
-> save() 1000번 실행 -> find() 1000번 실행
결과는??
위처럼 결과가 나왔다.
이번 결과는 은 총 2분 26초 걸렸고, 저번 mariadb로 진행했었던 reactive stack 은 4분 35초와 비교해서 2분 이상 줄어드는 결과를 알 수 있었다. 그리고 이전의 mariadb + servlet-stack 방식의 46초와 비교해서는 더 많은 시간이 소요되는 것도 알 수 있었다.
이전 결과와 이번 결과로 얻을수 있는 것
이번 비교로 무거운 작업이 포함될수록 servlet-stack 방식이 좀 더 나은 결과를 보여주는 걸로 생각해볼 수 있는 경험이 된 것 같다.