본문 바로가기

글또

[글또] 애플리케이션 성능 테스트

안녕하세요

이번에는 면접때도 느꼈었지만 기존 제가 했던 백엔드 어플리케이션 성능 테스트의 문제점을 인식하고 어떻게 테스트를 했어야할까? 라는 고민을 하며 글을 써보려고 합니다.

 

면접때 백엔드 핵심 서비스의 성능 개선 을 어떻게 했는지 여쭤보시던 경우가 있었습니다. 

 

제가 했던 작업은 필터 요건 추가에 따라 기존에는 필터 1개당 Roop 1번으로 3중 루프로 되어있던 로직을 go의 내장 sort로 풀어내고 코어 서버에 여러번 GRPC 호출을 이루던 작업을 하나로 통일하였습니다. 

 

그 결과로, 추가 개선 요구사항에 따라 조회 개수가 1000개 이상 건으로 많아진다고 가정하고 테스트를 진행해야 했는데 기존 7~8초 걸리던 작업을 2초 이내로 줄일 수 있었습니다.

 


 

면접관님 : 테스트는 어떤 툴을 가지고 어떤 기준으로 하신거에요?

 

나 : 자신있게 Postman으로 필요 더미데이터를 DB에 Insert하고 코어 서버와의 연동을 이루는 작업은 코어 팀에 부탁하여 데이터를 연동하여 1000건 이상의 데이터가 있다고 존재 시를 가정하여 앱 메인 화면에 표시되는 작업이었기에 성능 응답 시간 기준으로 테스트 하였습니다. 

 

면접관님 : 1000건이라는 기준은 왜 세우신거에요? 10000건으로도 해보셨나요? 예상치 못한 이슈는 없었나요? 트래픽을 어떻게 만들어내셨어요?

나 : 어.. 1000건이라는 기준은 비즈니스 상 자동차라는 도메인 상 그정도 예측을 했던 것이었습니다. 10000건으로 해도 시간복잡도 상 큰 오류가 생기지 않을 것이라고 생각합니다.

부하 테스트, 스트레스 테스트는 진행하지 못했습니다. (그거까지 해야하는지 잘 몰랐음)

 

이후 해당 내용에 대해 공부하다가 인프런에 좋은 강의가 있는 것 같아 한번 들어봤다.

아래는 백엔드 애플리케이션 성능 테스트

 

강의를 듣고 스터디한 내용을 작성하였습니다.


 

대답할 당시에는 Postman을 사용해서 테스트를 했다는 것 자체가 스스로 부끄럽다고 생각했었다. 스스로도 Postman을 성능 테스트 도구로 사용하는게 맞나 싶기도 했고 왜? 어떻게 하는게 내 상황에서 맞았을까? 를 생각하지 않고 수치로 증명하자만 생각했기 때문이다.

 

클라이언트의 요청이 많아진 경우 서버를 무한적으로 Scale - Up 할 수 있다면 좋겠지만 갑자기 사용자가 폭증하는 경우 인덱스가 걸리지 못하는 상황을 식별해야 할 수도 있고 데드락, 캐시 도입 , 동기적인 API를 비동기적으로 바꿔야 될수도 있습니다.

 

  1. 지연시간(Latency)와 처리량(Throughput)
    - 성능을 측정할 때는 이 2가지를 모두 측정하여 지표를 낼 수 있다. 
    TPS (Transaction Per Second) 초당 요청 건 처리 개수와 지연시간 
    -> 초당 3000개의 요청이 들어올 때 99%의 요청이 1000ms 미만으로 처리되어야 한다

 

왜 그럴까? 

요청을 1개의 클라이언트 통해서 서버에서 1개 처리하면 지연시간이 아주 낮게 나오기 때문에 처리량을 늘려 얼마나 견고한 서버인지를 처리해야 한다.

 


  • OS 측면

OS는 서버의 물리적인 자원을 관리하며 프로세스 단위로 애플리케이션을 실행 시킨다.

서버에 백엔드 애플리케이션을 배포하여 실행 시키면 프로세스로 관리하게 된다. 

 

CPU, 램 , 디스크를 할당받아 프로세스를 처리하게되는데 특정 자원이 튈때, 우리는 해당 자원의 사용률을 낮추기 위해 어떤 작업을 해야 한다 라고 문제 인식이 가능하게 된다.

 

프로그램 = Jar 파일 프로그램 = 디스크  (파일 입출력, 로그, 데이터베이스 대량 입출력)

프로세스 = 프로그램을 메모리에 올려서 (Stack, Heap + 코드) 자주 사용하는 작업, 자주 사용하지 않는 작업을 나눠 가상메모리, 페이징을 통해 상호작용 (램은 객체 생성, 캐싱, 컬렉션 CPU를 많이 쓰는 경우 함께 쓰임)

CPU = 프로세스 특정 작업 실행 (계산 작업, 암호화, 이미지, 인코딩)

 

실제로 컴퓨터 내부에서는 처리량이 증가하게 되면 서버 자원 사용량이 증가하게 되고 프로세스, 스레드 간 대기 시간이 길어지게 되고 자원을 서로 가지고 있으려는 경쟁 상태가 되어 버리면서 처리량이 기대이상으로 낮아지게 된다. 따라서 처리지되지 못한 요청이 쌓이면서 요청 중 일부 작업은 실패하여 100%의 요청중 특정 작업은 실패하게 된다.


  • 네트워크 측면

클라이언트는 서버 내부 자원을 사용하여 요청이 오고 서버는 데이터베이스나 다른 서버를 통해 API를 호출하게 됩니다.

이때 네트워크를 이용하는 작업(클라이언트 요청, DB 호출, 외부서버 호출)들은 매우 코스트가 크다. 

 

따라서 극적인 개선은 이러한 작업들을 개선해야 한다. 

 

HOW? 

 

1. 캐시 이용 (HazelCast, Redis)

 

  • 자주 요청되는 데이터는 캐시에 저장하여 불필요한 DB 호출을 줄인다.

2. 비동기 & 메시지 큐 활용 (Kafka, RabbitMQ, 레디슨, SQS)

  • 클라이언트 요청이 즉시 응답이 필요하지 않은 경우, 비동기 처리로 전환하여 네트워크 부하를 줄인다.
  • 메시지 큐(Kafka, RabbitMQ, AWS SQS)를 사용하여 처리해야 할 작업을 큐에 넣고, 백그라운드에서 별도의 프로세스가 처리하도록 한다.
  • 서버가 과부하를 받지 않도록 비동기 이벤트 기반 아키텍처로 전환하는 것이 효과적이다.

 

지구를 빛이 한바퀴 도는데는 133.3ms가 걸리게 됨 

우리나라와 정반대 서버에 있는 광랜으로 즉시 연결되어 있는 사이트를 호출 시 약 133.3ms가 걸릴 것. 하지만 실제로는 라우터, 스위치 복잡하게 동작하므로 훨씬 오래 걸리게 된다.

 

대역폭은 100mb/s 인데 다른 클라이언트와 동일 대역폭 사용시에 보내려는 데이터가 150mb/s면 처리되지 못한 데이터는 큐에 쌓여 늦게 전송되고 지연시간이 길어 지게 된다.


  • 데이터베이스 측면

데이터베이스의 지연시간이 길어지는 상황

1. 많은 요청이 들어올때 데이터베이스와 커넥션을 맺어야함 

2. 많은 데이터 중 필요한 데이터를 찾아야 할 때 1억 건 중 특정 데이터 Select

3. 한번에 많은 데이터를 서버에게 응답으로 줘야 할때 

4. 락이 너무 자주 걸리는 경우 (트랜잭선을 위해, 락이 걸리는 만큼 대기시간이 발생), 데드락으로 응답이 처리되지 않는 경우도 발생

5. 데이터베이스를 이중화 할때 서로다른 IDC에 위치할때는 전용 회선을 사용하지 않을 경우 대역폭 Delay 발생


강의를 듣고 학습하면서 실무에서는 갖추어져 있는 성능 테스트 도구 (nGrinder, Artillery, Jmeter) 중 어떤 걸 사용하고 왜 사용하는지를 생각해보게 되었고 제대로 성능 테스트를 하려면 지연시간과 처리량을 고려한 성능 테스트를 진행해 지연시간이 치솟는 지점을 발견하여 서버 자원을 모니터링 후 빠르게 병목지점을 탐색하여 문제를 식별해내고 성능을 점차 개선시켜나가는 것이 백엔드 개발자가 기여할 수 있는 한 부분이 아닐까 생각이 들었습니다. 🫠

 

성능 테스트에 대해 무지했는데 실제 서비스기업에서 왜, 어떻게 하는지 조금이라도 알게되어 강사님께 감사하네요 ㅎㅎ

 

다음주에는 Artillery 도구를 활용하여 직접 트래픽을 발생시켜 간단하게 성능 테스트 및 결과 해석, 성능 개선을 통해 실제로 해당 도구를 어떻게 활용해야할지 구체적으로 글을 작성해보겠습니다.