DataAccessResourceFailureException 이슈 해결기

0️⃣1️⃣·2023년 7월 28일
0

개발

목록 보기
4/7
post-thumbnail
post-custom-banner

Situation

DataAccessResourceFailureException: Failed to obtain R2DBC Connection

  • 정상적으로 데이터베이스에 연결이 된 상황
  • 스프링 배치가 R2DBC를 통해서 쿼리를 정상적으로 호출하다가, 위의 예외가 발생

Analysis

  • 배치 시스템 성능을 고도화하려고, 병렬 프로그래밍이 적용된 부분이 있었음
  • 병렬 처리로 인해 커넥션 할당이 많아져, 데이터베이스에서 커넥션을 더 이상 할당해주지 못하는 상황으로 인지

TroubleShotting

  • 매번 커넥션을 맺는 방식보다는, 일반 MYSQL처럼 커넥션 풀에서 커넥션을 재사용할 수 있도록 설정이 필요
  • R2DBC는 io.r2dbc.r2dbc-pool를 통해서, 커넥션 풀을 설정할 수 있었음

Dependency 추가

implementation("io.r2dbc:r2dbc-pool:1.0.0.RELEASE")

@Bean 추가

    @Bean
    fun connectionFactory(): ConnectionFactory {
        val connectionFactory = ConnectionFactories.get(
            builder()
                .option(DRIVER, "pool")
                .option(PROTOCOL, "mysql")
                .option(HOST, mysql.url)
                .option(PORT, mysql.port.toInt())
                .option(USER, mysql.username)
                .option(PASSWORD, mysql.password)
                .option(DATABASE, mysql.database)
                .build()
        )

        val configuration: ConnectionPoolConfiguration =
            ConnectionPoolConfiguration
                .builder(connectionFactory)
                .initialSize(2)
                .maxSize(10)
                .maxLifeTime(Duration.ofSeconds(600))
                .maxIdleTime(Duration.ofSeconds(600))
                .build()

        return ConnectionPool(configuration)
    }
  • maxSize는 일반적으로 사용하는 10개를 지정헀지만, 실제로는 응답속도, DB 시스템 관리자와 협의가 필요해보임
  • maxLifeTime, 커넥션의 생명 주기를 600초로 지정하여 슬로우 쿼리 방지
  • maxIdleTime, 커넥션 재사용에 가장 핵심인 부분, 600초동안 사용되지 않더라도 커넥션을 해제하지 않음
  • 커넥션을 해제하지 않으므로, 커넥션을 재사용할 수 있게 됨

Result

  • 해당 옵션을 추가하고, 위 예외는 더이상 발생하지 않음 🎉
  • 위 설정으로도 문제가 발생한다면, DBA와 실제로 커넥션 사용에 대해서 모니터링하고 적정한 수치를 협의

Reference

post-custom-banner

2개의 댓글

comment-user-thumbnail
2023년 7월 28일

잘 봤습니다. 좋은 글 감사합니다.

1개의 답글