본문 바로가기
Database

MyBatis 성능 개선포인트

by BTC_동동 2023. 9. 27.

베하! 안녕하세요.

추석이 다가 왔습니다!

오늘 알아볼 내용은 MyBatis 사용 시 성능 개선 포인트에 대해서 알려드릴까 합니다.

 

개선 포인트에 대해 알려드리기 전 먼저 제가 경험했던 부분에 대해 국한된 부분이라 각 환경에 따라 다를 수 있다는 점, 대용량 데이터 배치 처리 환경에서 MySQL을 사용했고 대용량 데이터는 정확히 100만개의 row, 40개 컬럼을 기준으로 메모리 안정화를 주 목적으로 한 작업에서 개선 포인트를 알려드리니 참고 부탁드리겠습니다 ^^

또한, 저는 대부분의 설정 및 성능 포인트를 setting보다는 java 코드로 구현했습니다.

 

MyBatis란?

먼저 MyBatis 성능 개선 포인트를 알기전 MyBatis에 대해 간략하게 알아볼까요?

MyBatis는 자바 어플리케이션과 관계형 데이터베이스 사이의 데이터 연동을 관리하기 위한 자바 ORM(Object-Relational Mapping) 프레임워크입니다. MyBatis를 사용하면 SQL 쿼리와 자바 객체 사이의 매핑을 간편하게 할 수 있으며, 복잡한 데이터베이스 작업을 쉽게 수행할 수 있습니다.

특히나 MyBatis는 mapper 를 통해 java 소스와 SQL을 분리하여 업무 분리를 하는 장점이 있습니다.(단점이 될 수 있습니다 ㅎㅎ)

 

대용량 데이터 처리 작업에서의 성능 개선 포인트

1. ExecutorType.BATCH 사용: 대용량 데이터 작업을 수행할 때, ExecutorType.BATCH를 사용하는 것이 좋습니다. 이 모드를 사용하면 MyBatis가 한 번의 커넥션을 열고 여러 개의 SQL 쿼리를 배치 처리할 수 있으므로 데이터베이스 연결 및 해제 오버헤드를 줄일 수 있습니다. 이로써 실행 시간을 크게 단축할 수 있습니다.

configuration.setDefaultExecutorType(ExecutorType.BATCH);

2. ResultHandler 활용: 대용량 데이터를 조회할 때는 ResultHandler를 사용하여 결과를 조금씩 가져오는 것이 메모리 관리 측면에서 중요합니다. 대용량 데이터를 한 번에 메모리에 로드하면 메모리 부족 문제가 발생할 수 있으므로, ResultHandler 를 활용하여 결과를 순차적으로 처리하세요. 저는 ResultHandler를 통해서 일괄 select를 조금 씩 분산 시키는 로직으로 늘 100%까지 치솓던 메모리 점유율을(자주 OOM 발생) 40%까지 낮췄습니다.

void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

3. flushStatements 사용: MyBatis에서는 flushStatements라는 설정 옵션을 제공합니다. 이 옵션을 활용하면 일정량의 SQL 문을 배치 처리하고 커밋하기 전에 임시로 버퍼에 저장하는 방식으로 대용량 데이터 처리 작업의 성능을 개선할 수 있습니다. 대용량 데이터 작업을 수행하는 동안 많은 SQL 문을 생성하고 실행할 수 있습니다. 이때 flushStatements를 사용하면, 일정한 개수나 시간 간격으로 SQL 문을 배치로 처리하고 커밋하므로 다음과 같은 장점이 있습니다.

  • 메모리 사용 최적화: 많은 SQL 문을 한 번에 메모리에 보관하지 않고 일부분씩 처리하므로 메모리 부하가 줄어듭니다.
  • 작업 속도 향상: 일정한 간격마다 SQL 문을 배치로 처리하기 때문에 작업이 빨라집니다. 트랜잭션 관리: 일정한 간격마다 커밋하므로 큰 트랜잭션 범위에서 발생하는 장애의 영향을 줄일 수 있습니다.
public interface SqlSession extends Closeable {
	....
	....
	....
	List<BatchResult> flushStatements();
	....
	....
}

 

4. Bulk Insert 사용: 데이터베이스에 대량의 데이터를 삽입해야 할 때는 MyBatis의 foreach를 활용하여 일괄 삽입을 수행하세요. 이렇게 하면 여러 개의 INSERT 문을 한 번의 쿼리로 실행할 수 있어 성능이 향상됩니다. 또한, 데이터베이스 벤더 별로 제공하는 일괄 삽입 기능을 활용하는 것도 고려해보세요. 저 같은 경우 100만 데이터를 insert 하는 작업에서 Bulk Insert를 구현해서 64개의 데이터를 insert하여 실행 시간 단축을 성공했습니다

<insert id="insertBulkData" parameterType="java.util.List">
        INSERT INTO your_table (column1, column2, column3)
        VALUES
        <foreach collection="list" item="item" separator=",">
            (#{item.value1}, #{item.value2}, #{item.value3})
        </foreach>
    </insert>

 

성능 개선 기본

성능 개선을 추구할 때 주 목적은 안정성과 메모리 안정화는 물론 실행 시간 단축도 포함되어 있었습니다. 대용량 데이터 배치 처리에서 OOM이 자주 발생한게 너무 큰 이슈였고 새벽시간에 배치 작업이 돌기 때문에 실행시간이 예상보다 늦어져도 크리티컬한 이슈로는 받아들이지 않았지만 성능 개선 작업을 진행하면서 실행시간도 어느정도 단축해보자 하여 해당 부분도 성공했던 것 같습니다.

하지만 개선 작업을 진행할 때 주의할 점이 있습니다.

  • 트랜잭션 관리: 대용량 데이터 작업은 오랜 시간이 걸릴 수 있으므로 트랜잭션 관리를 신중하게 해야 합니다. 트랜잭션 범위를 적절히 조절하여 안정성을 확보하세요.
  • 에러 처리: 대용량 데이터 작업 중에 발생할 수 있는 에러를 처리하는 방법을 고려해야 합니다. 롤백 및 에러 로깅을 효과적으로 수행하여 데이터 무결성을 보장하세요.
  • 성능 모니터링: 대용량 데이터 처리 작업의 성능을 모니터링하고 최적화를 위해 지속적으로 개선 작업을 수행하세요. 데이터베이스 쿼리의 실행 계획을 확인하고 인덱스를 최적화하는 등의 작업이 필요할 수 있습니다.

위 주의사항이 사실 개선 포인트 보다 더 선행되어야 하고 작업을 진행하는 중에도 1순위로 신경써야 하는 부분입니다.

개선작업을 진행할 때 트랜잭션이 적용되지 않은 문제가 발생했는데 그로 인해 (데이터 백업을 안했어요..) 데이터를 쌓는 작업을 다시 진행해야 했습니다..

성능을 개선하는 것도 좋지만 아주 기본적인 것을 잊어버리면 안됩니다.

 

 

앗 그래서 결론적으로 저는 배치 작업에서 약 3600초 걸리는 작업을 300초 전후로 줄일 수 있었고 OOM은 발생하지 않았으며 jvm heap 메모리 점유율을 30%로 유지할 수 있게 되었습니다.

 

오늘의 저의 경험을 바탕으로 mybatis 관련 성능 개선 포인트를 알아봤습니다. 이 경험에 대한 내용으로 다들 안정적인 애플리케이션을 구성하길 바람입니다. 감사합니다!

모두 즐거운 연휴 되세요~!

'Database' 카테고리의 다른 글

Airflow Task의 BQ Job 다루기  (0) 2023.09.28
GA4 (Google Analytics 4)  (1) 2023.09.27
트랜잭션의 이해(ACID)  (0) 2023.09.15
Cloud Composer의 내부DB 접근  (0) 2023.09.14
문서 검색 챗봇 만들기  (0) 2023.09.13

댓글