728x90
반응형

문제 확인

r2dbc-mysql을 사용해 개발한 애플리케이션에서 netstat | grep 3306으로 조회시 ESTABLISHED로 조회되는 개수가 커넥션 풀에 설정한 값과 상이한것을 확인함 .

r2dbc 풀 설정시 initSize가 20, maxSize가 50인데 아래와 같이 설정과는 다르게 커넥션이 생성되 있는 것을 확인함.

  • A 인스턴스는 2개
  • B 인스턴스는 10개
  • C 인스턴스는 20개

테스트 환경

  • Kotlin:1.4.21
  • spring boot:2.3.7.RELEASE
  • dev.miku:r2dbc-mysql:0.8.2.RELEASE

원인 파악

as-is

import io.r2dbc.pool.ConnectionPool
import io.r2dbc.pool.ConnectionPoolConfiguration
import io.r2dbc.spi.ConnectionFactories
import io.r2dbc.spi.ConnectionFactory
import io.r2dbc.spi.ConnectionFactoryOptions.*

@Configuration
@EnableR2dbcRepositories
class DatabaseConfiguration: AbstractR2dbcConfiguration() {

    override fun connectionFactory(): ConnectionFactory {

        val connectionFactory = ConnectionFactories.get(
            builder()
                .option(DRIVER, "mysql")
                .option(HOST, host)
                .option(USER, userName)
                .option(PORT, port)
                .option(PASSWORD, passWord)
                .option(DATABASE, db)
                .build())

        val configuration = ConnectionPoolConfiguration.builder(connectionFactory)
            .maxIdleTime(Duration.ofSeconds(maxIdleTime))
            .maxCreateConnectionTime(Duration.ofSeconds(maxCreateConnectionTime))
            .maxLifeTime(Duration.ofMinutes(maxLife))
            .initialSize(initialSize)
            .maxSize(maxSize)
            .build()

        return ConnectionPool(configuration)
    }

}    

분명 ConnectionPoolConfiguration에 initialSize와 maxSize를 넣었는데 비정상적으로 동작하는 것을 확인.

to-be

option(DRIVER, "pool")을 추가하였음. 이 설정은 추가하는 이유는 github.com/r2dbc/r2dbc-pool를 보면 Supported ConnectionFactory Discovery Options섹션에 아래와 같이 무조건 pool(Must be pool)로 설정하라고 되어 있음

driver Must be pool

 

import io.r2dbc.pool.PoolingConnectionFactoryProvider.*
import io.r2dbc.spi.ConnectionFactories
import io.r2dbc.spi.ConnectionFactory
import io.r2dbc.spi.ConnectionFactoryOptions.*

@Configuration
@EnableR2dbcRepositories
class DatabaseConfiguration: AbstractR2dbcConfiguration() {

   override fun connectionFactory(): ConnectionFactory =
        ConnectionFactories.get(
            builder()
                .option(DRIVER, "pool")
                .option(PROTOCOL, "mysql")
                .option(HOST, readPoolProperties.host)
                .option(USER, readPoolProperties.username)
                .option(PORT, readPoolProperties.port)
                .option(PASSWORD, readPoolProperties.password)
                .option(DATABASE, readPoolProperties.db)
                .option(MAX_SIZE, r2dbcPoolProperties.maxSize)
                .option(INITIAL_SIZE, r2dbcPoolProperties.initialSize)
                .option(MAX_IDLE_TIME, Duration.ofSeconds(r2dbcPoolProperties.maxIdleTime))
                .option(MAX_CREATE_CONNECTION_TIME, Duration.ofSeconds(r2dbcPoolProperties.maxCreateConnectionTime))
                .option(MAX_LIFE_TIME, Duration.ofMinutes(r2dbcPoolProperties.maxLife))
                .build()
        )

}        

netstat으로 조회시 초기값에 맞춰서 ESTABLISHED된 것을 확인함.

r2dbc-pool 소스를 디버그해보니 option(DRIVER, "pool")이 있고 없고에 따라서 ConnectionFactoryProvider가 달라지는 것을 확인 함

option(DRIVER, "mysql")로 설정시 dev.miku.r2dbc.MySqlConnectionFactoryProvider가 동작하고
option(DRIVER, "pool")로 설정시 io.r2dbc.pool.PoolingConnectionFactoryProvider가 동작하는데
dev.miku.r2dbc.MySqlConnectionFactoryProvider에는 initSize, maxSize에 대한 설정이 없고(github.com/mirromutth/r2dbc-mysqlgithub.com/mirromutth/r2dbc-mysql) 풀링되는 커넥션 팩토리가 아니기 때문에 그때그때마다 필요한 커넥션을 생성하는 방식이었음.

결론

r2dbc-pool을 사용해 커넥션 풀링을 정상적으로 이용하고 싶다면 option(DRIVER, "pool") 옵션은 필수이다.

728x90
반응형

+ Recent posts