Project

단일 스레드로 순차 처리 vs 비동기 vs 멀티스레드 성능 테스트 - Java

yerinpark 2024. 11. 7. 02:04

 

비동기와 멀티스레드를 적용한 전투력 측정 프로젝트

 

 

오늘은 비동기와 멀티스레드 모두 활용할 수 있는 로그 파일 분석 & 알림 시스템을 만들어 보았다.

(한 줄 요약 : 십만 건의 로그 데이터를 1. 그냥 2. 비동기 3. 멀티스레드 4. 비동기 + 멀티스레드 네 가지 케이스로 나누어 비교)

 

우선 이 프로젝트를 하게 된 이유는,,

실무에서는 대용량 데이터를 처리할 때 어떻게 효율성을 높이고 성능을 높이는지 궁금했다.

 

1. 기술 블로그를 통해 실무에서의 비동기, 멀티스레드 적용 사례 알아보기

2. 비동기, 멀티스레드의 개념과 어떤 경우에 적용하는지 알아보기

3. 프로젝트 기획하기

4. 로그 더미 데이터 만들기

5. Java로 처리 시간 확인하기

 

 

https://11st-tech.github.io/2024/01/04/completablefuture/

 

Java CompletableFuture로 비동기 적용하기 | 11번가 TechBlog — 11번가 기술블로그

안녕하세요. 11번가 클레임개발팀 박지훈입니다. 중앙 집중식 데이터베이스를 영역별로 분리하는 탈중앙화를 대비하여 분리 대상 테이블을 참조하고 있는 쿼리를 분리하고, 이관하는 작업을 진

11st-tech.github.io

11번가 기술 블로그에서 비동기 처리를 실무에 적용하기까지의 고민을 접할 수 있었다.

 

기존 결과 비교를 위해 이관 전/후 로직을 실행하는 부분이 순차적으로 실행되다 보니 전체적인 실행시간이 두 배로 증가하는 문제를 마주하였고, 1초 차이로 조회 결과가 달라지는 경우 이관 전 로직 실행이 완료된 이후 이관 후 로직이 실행되면서 정상 케이스임에도 결과 비교가 실패하는 문제를 발견하게 되었습니다.

 

요약하자면 as-is와 to-be 작업을 순차적으로 실행하여 실행 시간도 길어지고 1초 차이로 조회 결과가 달라지는 문제가 발생한 사례였다. 이를 해결하기 위해 비동기 처리를 도입하여 전체 처리 시간과 데이터 결과 비교 실패율을 줄였다.

 

비동기란 송신, 수신측 간에 시간 관계를 동시적으로(또는, 송수 동일하게) 유지할 필요가 없는 전송방식이다.

비동기 프로그래밍은 주로 사용자의 요청을 비동기로 처리해서 빠른 시간 내로 응답하거나 대용량 데이터 처리 작업 수행할 때 사용한다.

Java에서는 CompletableFuture를 사용하면 하나의 스레드가 작업을 비동기로 처리할 수 있다.

 

 

멀티스레드는 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것을 의미한다.

(멀티 프로세스는 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행하는 것을 의미한다.)

 

멀슈타트 붕괴로 인해 지난 강의자료 및 필기본을 찾아보았다.

Python의 특징이 가미된 설명이긴 하지만 범용적인 개념 내에서 설명해보자면

 

- 멀티스레딩 : 하나의 코어 내에서 여러 스레드 사이의 컨텍스트를 빠르게 바꾼다. 한 명의 작업자가 시간을 쪼개어 여러 작업을 진행하는 멀티태스커.

- 멀티프로세싱 : CPU가 많이 필요한 작업(CPU bound job)에서는 멀티스레드보다 유용하다. 한 프로세스의 비정상적인 종료가 전체 프로그램을 중단시키지는 않는다. 공유 상태가 많지 않다는 것은 코드에서 내부 경합 조건에 신경을 쓰지 않아도 된다는 의미와 같다.

 

그렇기 때문에 멀티스레드는 주로 게임 서버나 실시간 데이터 처리와 같이 리소스를 효율적으로 사용해야 하는 경우에 사용된다.

 

 

이러한 특성을 고려하여 비동기와 멀티스레드를 적용한 시나리오를 생각해봤다.

데이터는 캐글이나 공공데이터포털에서 찾다가 뾰족한 수가 없어서 직접 더미 데이터를 만들어서 활용하기로 했다.

보통 실시간 모니터링할 때 알림을 전송하던데 이상 탐지 로직을 구현하기엔 배보다 배꼽이 더 커질 것 같았다.

이벤트 발생을 뭘할까 고민하다가 대용량 시스템의 로그 데이터를 분석하고 에러가 n회 이상 발생 시 알림을 출력하는 것으로 결정했다.

로그 더미 데이터는 현실성을 부여하기 위해 로그 예시를 찾던 도중 우아한형제들 기술 블로그가 제일 상단에 떠서 배달 플랫폼 주문 과정을 예시로 만들었다.

 

            // 로그 레벨별 이벤트
            String[] infoEvents = {"주문 완료", "결제 요청", "결제 성공"};
            String[] warnEvents = {"결제 처리 지연", "외부 API 응답 지연"};
            String[] errorEvents = {"결제 실패"};
            String[] logLevels = {"INFO", "WARN", "ERROR"};
            String[] errorCodes = {"PAYMENT_TIMEOUT", "INSUFFICIENT_BALANCE", "NETWORK_ERROR"}; // 결제 실패 시 오류 코드

 

100,000건 로그 더미 데이터 생성

 

이 로그 파일을 CHUNK 단위로 분할해서 병렬로 처리하고(멀티스레드 적용) 이벤트가 감지되면 알림(비동기 처리)을 보내는 시스템이다.

 

네 가지 케이스로 구분해서 Java, JMeter로 성능 측정을 할 것이다.

 

1. 최적화 전(단일 스레드로 순차 처리)
2. 비동기(단일 스레드로 순차 처리, 비동기 알림 전송)
3. 멀티스레드(멀티스레드로 병렬 처리)
4. 멀티스레드 + 비동기(멀티스레드로 병렬 처리, 비동기 알림)

 

 

오늘은 날이 너무 늦었기 때문에 Java로만 시간 측정을 해봤다.

 

1. 최적화 전(단일 스레드로 순차 처리) 결과 : 86ms

2. 비동기 적용(단일 스레드로 순차 처리, 비동기 알림 전송) 결과 : 82ms

3. 멀티스레드 적용(병렬 처리) 결과 : 73ms

4. 멀티스레드 + 비동기 적용 결과 : 71ms

 

1. 최적화 전(단일 스레드로 순차 처리) 결과 : 86ms
2. 비동기 적용(단일 스레드로 순차 처리, 비동기 알림 전송) 결과 : 82ms
3. 멀티스레드 적용(병렬 처리) 결과 : 73ms
4. 멀티스레드 + 비동기 적용 결과 : 71ms

 

 

다음 포스팅에서는 JMeter를 활용한 성능 측정 결과를 작성할 예정이다.

비동기의 장점으로 인해 네트워크 입출력 대기 시간이 얼마나 줄어드는지, 처리량이 얼마나 늘어날지 궁금하다.

처리 시간 결과로 봤을 때 최적화 전보다 멀티스레드 적용 시 성능 개선 효과가 가장 좋았는데 구체적인 지표를 확인해보고 싶다!