동기 처리
- 요청을 보낸 사람이 작업이 끝날 때까지 기다리는 방식
- 사용자는 처리 상태를 알 수 없어서 기다리다가 '왜 안 되지?' 생각하고 재요청하면 중복 작업이 발생할 수 있음
비동기 처리
- 요청을 받은 서버가 작업 완료를 기다리지 않고 먼저 응답하는 방식
- 클라이언트 입장에서는 ai 작업과 http 요청이 분리됨
사용자 AI 요청
→ jobId 17번 발급
→ 사용자에게 즉시 반환
별도 Worker가 AI 처리
사용자가 17번 상태 조회
→ PROCESSING
→ 나중에 DONE + 결과
<비유>
| 주문 | AI 요청 |
| 주문번호 | jobId |
| 주문서 | AiJob DB 데이터 |
| 주방 직원 | ai-worker Thread |
| 조리 대기열 | Executor Queue |
| 조리 중 | PROCESSING |
| 조리 완료 | DONE |
| 조리 실패 | FAILED |
| 전광판 확인 | Polling |
!!! 비동기는 처리 속도를 높이는 기술이 아님
즉, 전체 ai 연산 시간보다 최초 http 응답 시간을 줄이는 구조

1. 사용자가 ai 작업을 요청
- 이 이미지들을 ai로 처리해주세요
2. 백엔드가 작업을 DB에 저장
id: 17
status: PENDING (접수 완료 처리 미 시작)
requestJson: 사용자의 요청 내용
resultJson: null
errorMessage: null
3. 사용자의 요청을 JSON 문자열로 보관
- WORKER가 나중에 다시 사용할 수 있도록 JSON 문자열로 바꿔 DB에 저장
4. @Async Worker에게 작업을 맡긴다
- @Async가 있으면 SPRING이 작업을 EXECUTOR에게 넘김
5. 사용자에게 jobId를 먼저 반환
- 202 Accepted : 요청 정상 접수, 처리 미완료
6. Worker가 AI 작업을 실행한다
- 별도 ai-worker 스레드가 17번 Job을 처리합니다.
- PENDING → PROCESSING
- 실제 ai 파이프라인 실행
7. 성공 또는 실패 상태를 저장한다
8. 프론트엔드가 상태를 반복해서 확인한다
- 일정 간격으로 반복 조회하는 것을 polling이라고 함
Thread
- 서버 안에서 코드를 실행하는 작업자
Spring Boot 서버
├── HTTP 요청 처리 직원
├── HTTP 요청 처리 직원
├── ai-worker-1
├── ai-worker-2
└── 기타 직원
<동기>
HTTP 요청 담당 직원이 AI 처리까지 전부 합니다.
<비동기>
HTTP 직원:
“주문을 접수하고 jobId만 반환”
AI Worker:
“실제 Qwen, DeepSeek, GPT 처리”
Executor
- ai 작업자와 작업 대기열을 관리하는 관리자
Core Pool Size: 2
Max Pool Size: 4
Queue Capacity: 50
- 기본 직원 2명, 바쁠 때 최대 4명까지 늘릴 수 있음
- 아직 처리하지 못한 주문 최대 50개까지 대기
ai-worker-1 → 1번 처리
ai-worker-2 → 2번 처리
Queue → 3번 대기
Queue → 4번 대기
Queue → 5번 대기
=> 정확한 Java Thread Pool 동작에서는 먼저 core 2개 실행하고 이후 작업은 queue에 들어감
queue가 가득 찼을 때 max 4개까지 worker가 추가 됨.
=> max가 4개라고 해서 처음부터 4개를 동시에 실행하는건 아님
Spring Proxy
- spring이 원래 객체 앞에 세워두는 중간 관리자
요청자 -> 비서 -> 실제 직원
AiJobService -> Spring이 만든 Proxy -> AiJobWorker
AiJobService
↓
Spring Proxy
↓ @Async 확인
Executor에 작업 전달
↓
별도 Worker Thread
↓
AiJobWorker.process() 실행
1. proxy는 spring이 원래 객체 앞에 만들어 두는 중간 관리자다.
2. proxy는 @Async를 확인하고 작업을 executor에 전달한다.
!!! Spring Proxy는 @Async 호출을 가로채 별도 작업 스레드로 넘기는 중간 관리자이고, 그 관리자를 반드시 거치기 위해 비동기 작업 클래스를 별도로 분리했습니다.
DB에 저장하는데 왜 서버 재시작 시 작업이 유실되나?
- DB
jobId: 17
status: PROCESSING
requestJson: {...}
- 실제로 17번을 실행하라는 명령은 EXECUTOR의 메모리 QUEUE에 있다
=> 즉, 서버가 꺼지면 DB의 JOB 데이터는 남으나
실행중인 THREAD와 QUEUE는 사라짐
'프로젝트 develop' 카테고리의 다른 글
| 비동기 처리 구조와 @Async (0) | 2026.07.19 |
|---|---|
| Presigned URL (0) | 2026.07.13 |
| [develop]develop plan (0) | 2026.07.02 |