비동기 처리 시 기본적으로 @Async를 사용한다.
JavaConfig기준 Spring 설정파일에서 @EnableAsync을 붙이기만 하면 바로 사용이 가능해진다.
하지만, 위 설정만으로 사용하게 되면, 기본적으로 단일 쓰레드로 동작을 하게 된다.
(ThreadPool설정을 보니 Default값이 1로 되어 있다.)
log를 @Async를 이용해서 보내게 되는 경우,
확실히 대규모 접속 서비스 같은 경우 단일쓰레드만으로는 사용이 어렵다.
로드러너를 이용한 성능 테스트에서도 목표 성능에 미치지 못했었던 적이 있다.
위 문제를 해결하기 위해, ThreadPooling을 해야 될 것 같아서,
스프링 사이트를 뒤져봤다.
AsyncConfigurer interface를 구현하겠다고 선언하면, 아래와 같이 두 가지 메소드에 대해서 구현을 하라고 나오는데,
getAsyncExecutor()가 내가 원하던 ThreadPooling역할을 해줄 것이다.
getAsyncUncaughtExceptionHandler()를 구현해서 이용할 수 있는 에러 핸들링은 필요에 따라 사용하는걸로...
@Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); // 최초에 생성할 Pool 개수 executor.setMaxPoolSize(50); // 몇개까지 Pool을 생성할 것인지 executor.setQueueCapacity(100); // Async 처리 시 Queue Size // (설정하지 않으면 Integer.MAX이기 때문에 성능에 문제가 발생함) executor.setThreadNamePrefix("LogAsync-"); // Thread 생성 시 가장 앞에 붙는 이름을 뭘로 할 것인지 executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { }
참고로 위 설정에서 사용하는, ThreadPoolTaskExecutor가 생각보다 목표 성능에 미치지 않고 불안정하다면,
ConcurrentTaskExecutor를 이용해서 동시성에 대한 처리를 개선할 수 있다고 한다.
참조 : http://blog.outsider.ne.kr/1066
전에 단일쓰레드 사용으로 문제가 있었으니,
쓰레드풀링으로 다시 이용해보고 결과는 다시 포스팅해야 겠다.
[테스트 결과]
위 처럼 QueueCapacity를 100으로 잡고, 부하를 줘봤더니 일반적인 부하에서는 문제가 없었지만,
임계치까지 부하를 준 경우에 담아둘 수 있는 Queue Capacity가 작아서 Exception을 떨구며, 처리를 못하는 것들이 꽤 생겼다.
그래서, QueueCapacity를 CorePoolSize * MaxPoolSize * 2 = 1000 수치로 잡고 테스트를 해보았더니
임계치까지 부하를 줘도 모두 처리가 가능했고, CPU 사용률도 양호했다.
실무에서는, 로그를 DB에 insert하는 부분에서 사용하고 있다.
'개발 > Spring Framework' 카테고리의 다른 글
[Spring MVC] 404 Error Handling (0) | 2016.06.10 |
---|---|
[Spring MVC] MappingJackson2HttpMessageConverter prettyPrinting 적용하기 (0) | 2016.06.10 |
[Spring Boot] 로그 파일 경로 지정 (0) | 2016.06.10 |
[Spring Boot] webMvc + freemarker configuration (0) | 2016.06.10 |
[Spring 4.x.x] RestController와 Controller 차이 (0) | 2016.06.10 |