[Artillery] Artillery를 이용해 socket.io 부하테스트 해보기

김지엽·2024년 1월 31일
0
post-thumbnail

1. 개요

프로젝트의 1차 구현이 끝났고, 배포를 준비하기 앞서 성능 테스트가 필요한 시점이다. 이번 프로젝트는 실시간 socket.io 통신이 주를 이루는 서비스인데, 우리 팀은 실시간 유저 3000명에 대해서 원활하게 서비스가 돌아가도록 하는 것을 목표로 삼았다.

기존의 t2.micro인 ec2서버 한대로는 당연히 3000명 유저의 트래픽을 처리하기에는 역부족이다. 따라서 서비스를 설계할때 scale-out을 전제로 socket.io에 redis Adapter를 적용해 여러 대의 서버에서 소켓 통신을 처리할 수 있게 하였다.

따라서 다음과 같은 두가지 검증이 필요하다.

  • redis의 메모리 부하 체크
  • 동시에 여러 유저 수에 대한 ec2 서버 부하 테스트

2. K6 vs Artillery

부하테스트 도구에는 여러가지가 있지만 나에게 필요한 도구는 다음과 같은 특징을 포함해야 했다.

  • 시나리오 기반의 성능테스트
  • socket.io를 지원해야 함

부하테스트를 여러가지 알아보고 크게 k6와 Artillery 둘 중에 결정을 고민하게 되었는데, k6는 ws는 지원하지만 socket.io는 지원하지 않아 결국 Artillery를 선택하게 되었다.

Artillery는 오픈 소스의 부하 및 성능 테스트 도구로, 웹 애플리케이션 및 API의 성능을 측정하는 데 사용됩니다. YML 형식의 설정 파일을 통해 테스트 시나리오를 정의하고, 다양한 부하 패턴 및 프로토콜을 지원하여 강력한 성능 테스트를 수행할 수 있습니다. Node.js로 구현되어 있어 가볍고 확장성이 좋으며, 실시간 리포팅과 결과 분석 기능을 제공합니다.

3. Artillery 테스트 코드

Artillery는 yml 또는 json 형식의 파일을 통해 테스트 시나리오를 작성한다. 코드를 먼저 살펴보자.

config:
    target: "http://배포url/group"
    socketio:
        transports: ["websocket"]
    phases:
        - duration: 30
          arrivalCount: 1000
scenarios:
    - name: "Join Group"
      engine: "socketio"
      flow:
          - emit:
                channel: "connectWithUserId"
          - think: 1
          - emit:
                channel: "groupCreate"
                data:
                    name: "그룹 제목 입니다."
                    mode: "nomal-game"
                    tier: "challenger"
                    people: null
                    private: false
                    position: ["jg", "top", "mid", "adc", "sup"]
          - think: 2
          - loop:
                - emit:
                      channel: "positionSelect"
                      data:
                          "position": "mid"
                - think: 2
                - emit:
                      channel: "positionDeselect"
                      data:
                          "position": "mid"
                - think: 2
                - emit:
                      channel: "chat"
                      data:
                          "message": "안녕하세요 반갑습니다 환영해요"
                - think: 2
            count: 8
          - think: 10

요소들을 살펴보자.

  • target : 테스트할 서버의 url
  • duration : 테스트를 몇초동안 지속할 것인지
  • arrivalCount : 총 몇 명의 유저를 테스트할 것인지
  • arrivalRate : 1초에 몇명의 유저가 테스트할 것인지
  • emit : socket.io의 emit
  • channel : socket.io의 emit시 이벤트명
  • think : 특정 시간동안 대기
  • loop ~ count : 몇번 반복할 것인지

데이터의 형태를 알아보자.

data:
    name: "그룹 제목 입니다."
    mode: "nomal-game"
    tier: "challenger"
    people: null
    private: false
    position: ["jg", "top", "mid", "adc", "sup"]

이러한 형식의 데이터는 실제로 다음과 같은 object와 일치한다.

{
	name: "그룹 제목 입니다.",
    mode: "nomal-game",
    tier: "challenger",
    people: null,
    private: false,
    position: ["jg", "top", "mid", "adc", "sup"], 
}

4. 서버 부하테스트 결과 및 분석

- ec2 서버 1대당 처리 가능한 유저 수

다음은 ec2 서버 1대에서 감당할 수 있는 트래픽을 테스트 한 결과이다.
900이 넘어갈때부터 에러가 발생하여 서버가 다운되는 경우가 생긴다.

따라서 ec2 서버 1대의 감당 가능한 유저수는 900명으로 생각한다.

  • Success는 오류가 거의 없이 실행된 경우
  • Fail은 서버가 다운되는 경우

- ec2 서버를 scale-out 했을때 처리 가능한 유저 수

목표 유저수는 3000명이기 때문에 서버를 늘릴때마다 어느 정도의 유저수에 정상적으로 서버가 다운되는 경우 없이 실행되는지 알아야 한다.

결과로는 ec2 서버를 1대 늘릴때마다 900, 1800, 2700 이렇게 정비례하게 늘어났다. 물론 이것은 단편적인 1~2분 테스트이며 3000명을 가정했을때는 더 여유롭게 처리를 할 필요가 있다.

5. redis 메모리 사용량

약 3000명의 유저가 각각 데이터를 쓰고, 읽고 하는데 메모리 사용량은 예상외로 높지 않았다. 현재 테스트한 소켓 통신은 mysql이 아닌 redis에만 데이터를 저장하고 읽고 삭제하는데 데이터량이 적어서 그런지 약 2MB정도만 사용되었다.

6. 결론

- ec2 서버 scale-out을 어느정도 해야할까?

현재 3000명의 유저 수를 목표로 삼고있고, ec2 서버가 3대일때 2700명까지는 정상적으로 구동되었다. 하지만 이는 단편적인 테스트이며 실제에서는 더 여유로운 성능 확보가 필요한 것으로 보였다. 따라서 추후에 AWS Auto Scaling을 통해 최대 4대의 ec2 서버로 구동되게 하는 것으로 결론내렸다.

- 현재 redis labs에서 elastic cache로 바꿀 필요성은?

현재 3000명의 유저가 각각 데이터를 wrtie했음에도 불구하고(실제로는 3000명 중 10% 정도만 write 예정) 메모리 사용량이 크지 않았다. 따라서 elastic cache로 redis를 업그레이드 시키는 것은 보류한다.

참고

Artillery 부하테스트

profile
욕심 많은 개발자

0개의 댓글