Spring 기초/Spring 기초 지식
[Spring] 스프링과 자바의 동시성과 병렬 처리
Stark97
2023. 10. 31. 18:29
반응형
Java의 동시성과 병렬 처리에 대해 알아보자.
📌 서론
백엔드 개발을 하다보면 동시성 문제에 직면하게 되는 경우가 있다.
그러나 동시성이 무엇인지 모르면 문제가 발생하는 원인조차 모를수 있기 때문에 간단하게라도 지식을 얻어두면 좋다고 생각한다.
이 글을 통해 정말 간단하게 자바의 동시성이 무엇이고 병렬 처리 기능은 어떤것이 있는지 알아보자!
1. 간단하게 알아보는 동시성 문제
동시성이 뭔데?
- 동시성이란 것은 여러 스레드가 동시에 같은 api를 호출한다고 생각하면 이해하기 쉽다.
- 예를 들면 스프링은 멀티 스레드로 동작하는 프레임워크이기 때문에 100개의 같은 요청이 1개의 api에 동일한 시간에 발생할 수도 있다. 이 상황에는 스레드의 경쟁이 발생할 것이고 "동시성 제어"가 되지 않는다면 서버에 문제가 발생할 것이다.
- 선착순 쿠폰발급 시스템 같은 것을 생각해 보자 "동시성 제어"가 되지 않아서 쿠폰발급이 이상하게 된다면 시스템에 대한 신뢰도부터 하락하고 그 서비스를 사용하려 하지 않을 것이다.
자바의 동시성 제어
- 자바에서는 이미 동시성 제어가 가능한 List, HashMap 클래스를 만들어 두었다.
- 스프링에서는 필드에 상태값을 가지는 클래스를 선언하지 않는 것이 권장된다.
- 그러나 만약 사용해야 하는 상황이 있다면 아래의 글을 참고해 보도록 하자 (동시성을 이해하기 위해 보는 것도 좋다.)
2. 스프링에서의 병렬성(Parallelism)
병렬성은 스프링 애플리케이션에서 데이터 처리와 계산 작업의 성능을 향상하는 데 중요한 역할을 한다.
병렬 데이터 처리
- 스프링의 ForkJoinPool을 활용하여 복잡한 데이터 처리 작업을 병렬로 수행할 수 있다.
- 이는 CPU 바운드 작업의 성능을 극대화하는 데 도움이 된다.
배치 처리
- 스프링 배치(Spring Batch)는 대량의 데이터를 효율적으로 처리하기 위한 병렬 처리 기능을 제공한다.
- 이를 통해, 대규모 데이터셋을 더 빠르게 처리할 수 있다.
3. @Async 어노테이션을 사용한 비동기 처리
웹 애플리케이션에서의 비동기 요청 처리
- 웹 애플리케이션에서는 동시에 많은 사용자의 요청을 처리해야 한다.
- @Async 어노테이션을 사용하여 요청 처리를 비동기적으로 실행함으로써, 메인 스레드가 막히는 것을 방지하고 사용자 요청에 더 빠르게 응답할 수 있다.
@Service
public class AsyncRequestService {
@Async
public CompletableFuture<String> processRequest(String requestData) {
// 비동기적으로 요청 처리 로직을 구현
return CompletableFuture.completedFuture("Processed " + requestData);
}
}
2. 데이터 처리 작업의 스케줄링
- 대량의 데이터 처리 작업이 필요한 경우, @Scheduled 어노테이션을 사용하여 주기적으로 작업을 실행할 수 있다.
- 이를 통해 시스템 리소스를 효율적으로 관리하고, 작업의 부하를 분산시킬 수 있다.
@Service
public class DataProcessingService {
@Scheduled(fixedRate = 60000)
public void periodicDataProcessing() {
// 데이터 처리 로직을 구현
}
}
3. REST API 호출의 병렬 처리
- 외부 서비스와의 REST API 호출은 때때로 시간이 많이 소요될 수 있다.
- 이러한 경우, CompletableFuture를 사용하여 병렬적으로 여러 API 호출을 처리할 수 있다. 이렇게 하면 전체 응답 시간이 단축된다.
@Service
public class ParallelApiService {
private RestTemplate restTemplate = new RestTemplate();
public void callExternalApisInParallel() {
CompletableFuture<String> apiResponse1 = CompletableFuture.supplyAsync(
() -> restTemplate.getForObject("http://api1.com/data", String.class)
);
CompletableFuture<String> apiResponse2 = CompletableFuture.supplyAsync(
() -> restTemplate.getForObject("http://api2.com/data", String.class)
);
// 두 API 응답을 병렬적으로 처리
CompletableFuture.allOf(apiResponse1, apiResponse2).join();
}
}
반응형