O
OpenLog
Search
Log in
Back to Suggestions
New Suggest
Suggest edit for "CPU Bound 작업에서 워커의 Concurrency를 늘려도 성능 개선이 거의 없었던 이유"
Suggestion title
Description
</>
Edit
Preview
## Summary ## Reason
</>
Edit
Preview
```ts @Processor('embedding-queue', { concurrency: 3 }) export class EmbeddingWorker extends WorkerHost { private readonly logger = new Logger(EmbeddingWorker.name); constructor( private readonly mlEngine: MLEngine, private readonly campaignCacheRepository: CampaignCacheRepository ) { super(); } ``` 벡터 임베딩을 담당하는 NodeJS 워커에 `concurrency: 3`을 부여했는데 성능 개선이 전혀 발생하지 않았다. 나는 당연히 동시성을 늘리는 옵션이라 개선이 생길거라고 생각했었는데.. 그럼 이 옵션은 정확히 어떤 일을 하는걸까? bullMQ의 `concurrency`옵션은 CPU나 스레드를 늘리는 옵션이 아니라 '동시에 진행 중인 job 수'를 늘리는 옵션이다. 다시말하면, 이 worker가 job을 몇 개까지 active 상태로 동시에 들고 있을 수 있냐를 설정하는 것이라고 볼 수 있다. 예를 들어 `concurrency: 5`면 워커 하나가 - job1 시작 - job2 시작 - job3 시작 - job4 시작 - job5 시작 까지 가능하다. 여기서 '시작'은 job 하나가 완전히 끝날 때까지 다음 잡을 안가져오는 것이 아니라, Promise가 resolve되기 전에 다른 job도 같이 진행 상태로 올릴 수 있다는 뜻이다. (`concurrency`옵션을 안주면 디폴트 값이 1이라, 하나의 요청이 처리되어야 다음 요청을 보낸다.) 그래서 `concurrency`는 별로 쓸데가 없는 옵션인가? 아니다. I/O 작업에서 아주 효과적이다. 만약 job이 이런형태라면 ```ts async process(job) { const a = await redis.get(...); const b = await db.query(...); await httpCall(...); } ``` 이 작업을 처리하는데 걸리는 시간은 CPU 계산이 아닌 비동기 응답을 대기하는 시간이 대부분이다. 그래서 `concurrency: 1`이면 job1이 Redis응답을 기다리는 동안 worker는 다음 잡을 안들고 그냥 기다린다. 반면에 `concurrency: 5`이면 job1 요청을 보내고 기다리는 동안 job2 요청을 보내고, 그동안 또 job3을 보내서 여러 잡의 대기 시간을 겹처 쓸 수가 있다. CPU 바운드 작업은 기다림이 없고 메인스레드가 계속 계산을 붙잡고 있는 형태이므로 `concurrency: 5`라도 실제로는 - job1 계산 중 - 이벤트루프 막힘 - job2~job5를 건드릴 시간이 없음 concurrency가 있어도 겹칠 비동기 대기 시간이 없어 효과가 작거나 오히려 더 나빠질 수가 있다. 그래서 BullMQ 공식문서도 CPU 집약적인 잡은 sandboxed processors를 사용하는걸 권장한다고 한다.
Files changed
No changes yet.
Cancel
Submit suggestion