ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Springboot] web+jpa vs webflux+r2dbc 비교 (2)
    Server 2022. 12. 7. 09:49
    728x90
    반응형

    이번 포스팅에서 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 를 이용해서 비교를 해보려 한다.

    저번 사용한 mariadb connection dependency
    저번 사용한 mariadb connection dependency

    mongodb connection을 이용하기 위해 

    implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")

    를 추가해준다.

    mongodb dependancy
    mongodb dependancy

    그리고  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번 실행

     

    결과는??

    Active Threads Over Time
    Active Threads Over Time
    Response Times Over Time
    Response Times Over Time
    Transactions per Second
    Transactions per Second
    생성된 data
    생성된 data

    위처럼 결과가 나왔다.

    이번 결과는 은 총 2분 26초 걸렸고, 저번 mariadb로 진행했었던 reactive stack 은 4분 35초와 비교해서 2분 이상 줄어드는 결과를 알 수 있었다. 그리고 이전의 mariadb + servlet-stack 방식의 46초와 비교해서는 더 많은 시간이 소요되는 것도 알 수 있었다.

     

    이전 결과와 이번 결과로 얻을수 있는 것

    이번 비교로 무거운 작업이 포함될수록 servlet-stack 방식이 좀 더 나은 결과를 보여주는 걸로 생각해볼 수 있는 경험이 된 것 같다.

    728x90
    반응형

    댓글

Designed by Tistory.