ebson

[ Spring Framework Transaction, LG CNS DEVON-Framework batch-insert ] 데브온 프레임웍의 배치인서트 사용해 성능 개선하기 본문

HANDS-ON

[ Spring Framework Transaction, LG CNS DEVON-Framework batch-insert ] 데브온 프레임웍의 배치인서트 사용해 성능 개선하기

ebson 2023. 4. 6. 09:31

JPA 개발자들이 스프링 프레임웍을 함께 사용하는 이유 중 하나가 스프링에서는 트랜잭션 관리를 해주기 때문이라고 한다. 내가 실무에서 만난 프로젝트도 스프링 프레임웍 기반의 프로젝트였고 트랜잭션 설정 파일이 있었다. 서비스 메서드를 호출한 후 트랜잭션을 처리하도록 하되 insert, update, delete 으로 시작하는 서비스 메서드에서 예외가 발생하는 경우에 트랜잭션을 롤백하도록 설정할 수 있었다.

 

트랜잭션 과다 생성으로 인한 성능저하

그런데 서비스 메서드를 호출할 때 적용되는 트랜잭션 설정과 어울리지 않는 일부 소스에서 성능저하를 일으키는 경우가 있었다. 서비스단에서 모아서 처리해야 할 트랜잭션 작업을 컨트롤러에서 for문을 돌면서 개별적으로 요청하고 같은 쿼리를 여러번 호출했기 때문이다. 

 

... (생략)
<tx:advice id="txAdvice" transaction-manager="txManager">
	<tx:attributes>
    	<tx:method name="retrieve*" read-only="true" />
		<tx:method name="insert*" rollback-for="Exception" />
		<tx:method name="update*" rollback-for="Exception" />
		<tx:method name="delete*" rollback-for="Exception" />
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut id="txPointcut" expression="execution(*.service..impl.*ServiceImpl.*(..))" />
	<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>

[소스1] 일부 접두어의 서비스 메서드 호출 이후 트랜잭션을 commit 하거나 rollback 하는 설정의 모습 (*모든 소스는 원본 소스와 세부적으로 다를 수 있음)

// *Controller.java

	for(int i=0; i<customerModelArray.length; i++){
		... 생략
		warrantyService.insertWtysvcingInfoModel(input);
	}

[소스2] 컨트롤러에서 반복적으로 서비스단의 INSERT 요청메서드를 호출하고 있는 모습 (*모든 소스는 원본 소스와 세부적으로 다를 수 있음) 

 

 

트랜잭션 생성 구조 개선 및 배치인서트를 사용해 성능개선

그래서 해당 반복문에 사용되는 파라미터 리스트를 포함한 데이터를 서비스단으로 통째로 넘겨주고, 서비스 단에서도 매퍼의 인자로 VO 대신 List를 넘겨 줌으로서 배치인서트를 할 수 있도록 했다. 이 프로젝트의 경우는 LG CNS에서 스프링 프레임웍을 개량한 데브온 프레임웍이라는 것을 사용 중이었고, 마이바티스 배치인서트를 커스텀한 기능을 지원해서 이것을 사용하기로 했다. PM과 아키텍트의 가이드 메일을 따른 것이었다. 가능한 기 제공되는 메서드를 사용하려는 의도였다.

 

// *Controller.java

	int cnt = warrantyService.insertWtysvcingInfoModelList(input);
	mv.addObject("cnt", cnt);

[소스3] 파라미터 리스트를 포함한 데이터를 서비스 메서드로 전달하고 insert 개수를 반환받는 모습 (*모든 소스는 원본 소스와 세부적으로 다를 수 있음) 

// *ServiceImpl.java

    @Override
	public int insertWtysvcingInfoModelList(Map<String, Object> input) {
		int count = 0;
		try{
			... (생략)
			count = commonDao.batchInsert("Warranty.insertWtysvcingInfoModel", list, "publ"); 
		} catch(Exception e) {
			throw new AjaxException(e);
		}
		return count;
	}

[소스4] 전달받은 데이터에서 파라미터 리스트를 추출하고 반복문을 돌면서 정제 후 배치인서트하는 모습 (*모든 소스는 원본 소스와 세부적으로 다를 수 있음) 

 

이렇게 함으로서 기존에 90초 이상 소요되던 검색 속도가 10초 내외로 단축되었다. 약 900% 속도 향상하는 효과였다. 그래서 프로젝트 전체에서 비슷한 원인으로 검색속도가 느린 페이지들을 모두 찾아서 동일한 작업을 진행했다. 그 결과 비슷한 속도 향상률을 보였다.

 

 

피드백

이 작업은 PM과 아키텍트의 가이드 메일을 따라 진행한 작업이었다. 그렇지만 스프링 트랜잭션 설정과 그에 따른 코딩시 주의사항에 대해 생각해 볼 수 있는 기회였다. 앞으로 비슷한 상황이 있을 때에 더 빨리 해결책을 찾을 수 있을 것이라고 생각한다. 아쉬웠던 점은 이와 같은 성능 이슈들을 더 자발적으로 찾아보지 못했다는 점이다. 

 

Comments