서버 최초 실행 시 Open API를 통해 데이터를 조회하여 DB에 저장하는 로직을 구현했다. 하지만 두 가지의 데이터를 각각 조회해야 하는데 기존 코드의 경우 동기적으로 수행하고 있었다. 데이터 수가 적을 경우엔 성능 차이가 크지 않지만, 조회할 데이터의 양이 많기 때문에 동기적으로 수행될 경우 조회 및 저장에 소요되는 시간이 많아진다.
이를 해결하기 위해 Spring에서 제공하는 Async 기능을 이용하여 비동기 처리를 적용하여 시스템의 전체적인 수행 시간을 개선하고 리소스를 효율적으로 사용하려고 한다.
비동기란?
요청과 결과가 동시에 일어나지 않는다는 뜻이다.
즉 작업을 요청하고 해당 요청에 대한 결과를 기다리지 않아도 된다. 이를 통해 여러 작업들을 병렬적으로 처리할 수 있다.
@Async
Spring에서는 @Async 어노테이션을 제공함으로써 로직의 비동기 처리를 지원한다.
이때 유의사항으로는 다음 두 가지가 있다.
- 접근 지정자가 private인 메서드는 사용 불가능하다.
- self-invocation(자가 호출)은 불가능하다. 즉, 같은 클래스 내에 존재하거나 자기 자신을 호출할 경우 비동기로 동작하지 않는다.
1. SpringBootApplication에 @EnableAsync 어노테이션 적용
@EnableAsync
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 비동기를 적용할 메서드에 @Async 어노테이션 적용
@Component
@RequiredArgsConstructor
public class OpenApiDataLoader implements ApplicationRunner {
private final PharmacyService pharmacyService;
private final HospitalService hospitalService;
@Override
public void run(ApplicationArguments args) throws Exception {
pharmacyService.saveAllPharmacyInfo();
hospitalService.saveAllHospitalInfo();
}
}
애플리케이션 실행 시 run() 메서드가 실행된다. 메서드 내부의 saveAllPharmacyInfo()와 saveAllHospitalInfo()를 비동기적으로 수행하려고 한다. 따라서 각각의 메서드에 @Async 어노테이션을 적용한다.
@Service
@RequiredArgsConstructor
@Slf4j
public class PharmacyService {
@Async
public void saveAllPharmacyInfo() {
...
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class HospitalService {
@Async
public void saveAllHospitalInfo() {
...
}
}
비동기 방식으로 코드를 수행하게 함으로써 효율적인 자원 사용과 시간 절약이 가능해졌다. 또한 어노테이션 하나로 간단하게 구현할 수 있어서 유지보수하기 좋은 것 같다.
하지만 위 방식은 기본적으로 SimpleAsyncTaskExecutor가 사용된다. SimpleAsyncTaskExecutor는 스레드 풀을 사용하지 않고 매 요청마다 새로운 스레드를 생성해 작업을 수행하는 방식이므로 스레드를 관리하지 않는다는 문제가 있다. 따라서 스레드 풀을 관리하기 위해 별도의 TaskExecutor를 설정해야 한다.
하지만 아직도 약 7만개의 데이터를 조회하는 데 1시간 가량 시간이 소요된다. 이를 해결하기 위해 메서드 내부에서 비동기 처리가 가능한 부분을 더 살펴봐야겠다.
🔗 Reference
'Framework > Spring' 카테고리의 다른 글
[SpringBoot] 다중 DB 구성하기 (0) | 2024.05.11 |
---|---|
[SpringBoot] 외부 API 호출하기(2) (0) | 2024.04.18 |
[SpringBoot] 외부 API 호출하기(1) (2) | 2024.04.18 |
[SpringBoot] MockMvc로 Multipart() 테스트 코드 작성하기 (1) | 2024.02.15 |