동기처리(Synchoronous Programming)
여러작업을 순차적으로 실행하도록 개발하는 방법. 동기 처리는 한 작업이 끝나야 다음 작업을 시작할 수 있는 방식입니다. 순차적인 작업을 위해서 현재 진행중인 작업의 완료를 기다리며 대기하는 구조입니다.
비동기처리(ASynchoronous Programming)
여러 작업을 동시에 실행하는 프로그래밍 방법론. 비동기 처리는 한 작업이 끝나기를 기다리지 않고, 다른 작업을 수행할 수 있는 방식입니다.
비동기처리방식은 두가지 종류가 존재하며 멀티스레드 방식과 Non-Blocking I/O 방식이 있다. 멀티스레드 방식은 작업의 세트를 여러 스레드별로 나누어 가지어 동시에 실행하는 방식. 논블럭킹 방식은 하나의 스레드가 여러가지 작업을 담당하는데, I/O작업 실행시킬때 blocking이 되지 않은 상태에서 다른 작업을 진행하는 방식.
비동기와 동기화 방식의 유불리
비동기화 사용시 고려점
리소스 사용관점 :
비동기 처리는 스레드 풀을 통해 여러 스레드를 관리하며 작업을 비동기로 실행합니다. 비동기 작업은 스레드 풀이나 메모리 자원을 추가로 사용하게 되며, 비동기 작업이 많아질수록 리소스 소모가 커질 수 있습니다.
- CPU자원소모 : 스레드 수가 많아지면, 컨텍스트 스위칭이 빈번하게 발생해 성능에 부정적인 영향을 미칠 수 있습니다. 일반적으로 스레드 간 전환 비용은 수십~수백 나노초 수준이지만, 자주 발생할 경우 CPU가 실질적인 작업보다는 스위칭에 더 많은 자원을 소비하게 됩니다. 때문에 대기 시간이 수십~수백 나노초 이상이면서 반복적인 작업이라면 비동기 처리나 최적화를 고려할 가치가 충분히 있습니다.
- 메모리 : 각 스레드는 스택 영역을 별도로 할당받습니다. 스택 영역은 함수 호출 시 로컬 변수와 함수 호출 정보를 저장하는 공간으로, 스레드마다 독립적으로 관리됩니다. 특히 많은 CompletableFuture나 비동기 요청이 메모리에 대기 상태로 존재하면, 메모리 사용량이 급격히 증가하여 오히려 성능 저하를 유발할 수 있습니다.
데이터의 일관성관점 :
- 데이터 일관성 : 금융 거래나 중요 데이터를 다루는 시스템에서는 트랜잭션 일관성이 매우 중요합니다. 비동기화 처리는 여러 작업이 동시에 수행되면서 일관성을 보장하기가 어려워질 수 있습니다. 공유 자원이나 동일한 데이터에 접근하는 경우, 비동기 작업 간의 경합 조건이나 순서 문제로 인해 데이터가 예상치 못한 상태로 변경될 가능성이 있습니다.
- 작업 간 강한 의존 관계가 있는 경우
- 특징: 하나의 작업이 완료되어야만 다음 작업이 실행될 수 있는 경우가 있습니다. 이런 경우에는 후속 작업이 이전 작업의 결과에 의존하기 때문에 순차적 실행이 필요합니다.
상황에 맞지 않는 비동기 처리 사용
- 단순하고 빠른 작업에 비동기 처리 적용: 단순한 계산 작업이나 짧은 시간 안에 완료되는 작업에 비동기 처리를 적용하면, 오히려 스레드 관리 오버헤드가 추가되어 성능이 저하될 수 있습니다.
- 동기적 흐름이 필요한 경우에 비동기 적용: 트랜잭션의 일관성이 중요한 작업이나, 순차적으로 실행되어야 하는 작업에서 비동기를 사용하면, 오히려 데이터 무결성과 비즈니스 로직의 안정성이 저하될 수 있습니다. 문제점: 비동기 작업에서 여러 작업이 동시에 수행되면 작업 간의 의존 관계가 충돌을 일으킬 수 있으며, 비동기 처리 시점에 따라 결과가 예기치 않게 변경될 수 있습니다.
- 과도하게 많은 비동기작업을 짧은 시간내 처리할떄 : 비동기 작업이 병렬로 너무 많이 실행되면 스레드 풀의 모든 스레드가 점유되면서 새로운 작업이 큐에 쌓이고, 스레드 전환과 관리 비용이 증가해 성능 저하가 발생할 수 있습니다.
비동기 호출 후 처리 방식에 따른 프로그래밍 패턴
비동기 처리에서는 콜백이나 프로미스(Promise, Java에서는 CompletableFuture 등)를 활용하여, 백그라운드에서 작업이 완료될 때 후속 작업을 비동기적으로 처리합니다.
단일 작업 내 비동기처리
- CompletableFuture is best suited for intra-task asynchrony, where you manage multiple steps of a single workflow. 퓨처는 callable 작업을 정의 및 입력하고 쓰레드풀에서의 쓰레드를 가져와 작업을 처리시키고 get으로 작업결과를 받아옴.
- @Async is typically used for intra-task asynchrony, as it is designed to offload a specific part of a workflow (a method or task) to a separate thread. 작업을 정의하고 쓰레드풀에서의 쓰레드를 가져와 작업을 처리시키고 Fire and Forget에 적합하다.
다중 작업(다중 요청) 간의 비동기 처리
- Message queues (Kafka, RabbitMQ) for decoupled workflows.
- No Immediate Response is Required:
- Avoiding Additional Threads:
- Reactive streams for handling large-scale, event-driven systems.
- Thread pools for concurrent independent tasks within the same application.
https://www.youtube.com/watch?si=38UrGcPFMGXR4Hh6&v=EJNBLD3X2yg&feature=youtu.be
'개발기술 > 설계|디자인패턴' 카테고리의 다른 글
JavaScript, Node JS, Event-Driven Programming 그리고 Java, Spring, MultiThreading (0) | 2025.04.05 |
---|---|
Code Structuring Technique (0) | 2025.03.17 |
클래스 다이어그램 (1) | 2024.09.10 |
프로젝트 설계 및 문서화 (0) | 2024.08.14 |
디자인패턴 (0) | 2024.08.10 |