[SpringBoot] 대규모 데이터 처리 (1) - mysql insert

2024. 12. 22. 16:12Lang/JAVA


Big Data

회사가 AI 회사다 보니 대규모 데이터 셋을 다룰 때가 종종 있다.

이번엔 문서의 본문 내용이 포함된 대략 6만건의 데이터 셋을 insert 해야되는 mission 을 받았다.

 

한번에 insert 할 경우 여러 문제가 발생할 가능성이 있고 이 데이터를 처리하다가 다른 본 서비스에 지장을 줄 우려가 있었기에 local 환경에서 여러 시도를 해보고 그 결과를 남긴다.

 


1. Batch Insert

대규모 데이터 셋을 넣어야할 프로젝트는 Mybatis를 사용중이었다.

mySql은 foreach를 통해 다량의 row를 한번에 insert 할 수 있도록 지원하고 있기에 이것을 먼저 시도해봤다.

 

부하를 얼마나 버틸지 몰라 부분부분 나눠 테스트를 진행했다.

처음은 100건을 요청했다 -> Success!!

다음은 500건을 요청했다 -> Success!!

그다음으로 1000건을 요청했다 -> Fail

 

sqlSessionFactory에서 conection Time Out을 내뱉었다...

 

스프링과 mySQL 사이에 커넥션을 잇고 있는 jdbc에서 mySQL이 데이터 insert에 시간을 쓰는 것을 못 기다리고 에러를 내뱉은 것!

 

Setting 값 변경으로 Connection Time Limit 설정이 가능하겠지만 무턱대고 설정을 변경할 경우 다른 사이드 이펙트가 생기거나 오히려 DB에 부하를 줄 수 있어 다른 방법을 찾기로 했다.

 


2. Batch Insert를 데이터를 소분해서 여러번 요청 보내기

위의 방법을 활용해서 100건씩 데이터를 쪼개서 반복 요청을 보내게 해봤다.

 

100건... 300..건 800..건 .... 데이터가 잘들어가는 듯했지만

 

한 8000천건 정도가 되었을 때 hikari pool leak 이떴다.

 

내 Local에서 실행한 스프링 서버에 설정된 Hikari의 pool 의 개수가 모자란 것!

 

알아보니 pool이 데이터 처리를 할때 할당되는데 할당하고 회수하기 까지의 시간보다 할당하는 시간이 더빨라서 결국 pool leak이 뜨게 된것이다

 

하지만 이것도 세팅 값을 바꾸는 것은 좋지 못하다고 판단했고 다른 방법을 시도했다.

 


3. 2번 방법에 Thread.sleep 추가

2번 방법을 썼을 때 가장 쉬운 해결 방법은 sleep을 걸어서 물리적 요청시간간격을 늘리는 거였다.

 

이 방법을 했을 때 6만건의 데이터는 모두 들어가게 되었지만 데이터 insert까지 시간이 무척 오래걸리게 되버리면서

일시적으로 쓸 정도일 뿐 결국 개선을 해야했다.

( sleep은 테스트 결과 적어도 3초는 줘야했다... 아마 데이터 LongText라 다른 데이터셋이면 결과가 다를 수도 있겠다.)  

 


4. 멀티 스레드 활용

그동안은 반복문으로 data를 쪼개서 넣고 있었는데 이를 반복 할게 아니라 스레드 다중 할당해서 시도해 봤다.

 

Connection Time Out이 나오지 않을 정도의 데이터 셋을 크기를 조절해서(안전하게 500건으로 설정) 10개의 스레드에 나눠  bulk insert를 시도했다.

 

결과는...  Success!! 

 

하지만 이 경우도 사용자가 많을 시간에 이뤄지면 서비스에 제약이 생길 가능성이 있어서 Spring Batch로 user가 거의 없을 새벽시간에 해당 insert를 수행하도록 설정했다. 

 

(소스 코드를 보여주고 싶은데 회사 정책상 소스코드 반출이 불가하다...)