단위 테스트는 '특정 메소드를 실행하는 상황'에서 발생하는 문제를 사전에 찾기 위한 작업이고, 통합 테스트는 '여러 메소드와 외부 의존 모듈이 함께할 때' 발생하는 문제를 사전에 찾기 위한 작업
그리고 성능 테스트는 '트래픽이 많은 상황'에서 발생하는 문제를 사전에 찾기 위한 작업이다
트래픽이란 1초동안 서버로 요청되는 수를 의미하며 RPS(Request Per Second)라고 표현하기도 한다
트래픽이 많은 상황에서는 서버의 처리속도가 느려진다던지, 서버의 리소스 부족으로 더 이상 사용자의 요청에 응답할 수 없거나 버그가 발견되는 등의 상황이 생길 수 있다. 이러한 문제를 성능테스트를 통해 극복이 가능하다고 한다
즉, 이러한 맥락에서 볼때 성능테스트란 1초당 요청이 가장 많은 상황을 기준으로 서비스에서 발생하는 성능, 가용성 관련 문제를 찾아내는 작업이라고 표현할 수 있다
NGrinder, JMeter, Greenlet
두번째 사진의 모습이다
Apache 재단에서 오픈소스로 만든 자바 기반의 성능 테스트 툴
JMeter 설치 및 실행 → Thread Group 생성 → Sampler 생성 → Response Assertion 설정→ Listener 설정 → 성능 테스트 실행 → Report 확인
네이버에서 성능 측정을 목적으로 Jython(JVM 위에서 파이썬이 동작) 으로 개발된 오픈 소스 프로젝트
자이썬(Jython)은 파이썬 프로그래밍 언어를 100 퍼센트 순수한 자바로 작성하여 완전하게 구현한 것
한편 nGrinder 는 Grinder 라는 내부 엔진을 사용하며 nGrinder 는 이 엔진을 controller 와 agent로 감싸 다수의 테스트를 병렬처리할 수 있도록 한다. controller 와 agent 는 nGrinder 의 주요 요소이다.
Controller
성능테스트를 위한 웹 인터페이스를 제공하는 역할을 한다. agent 를 관리하는 것이 controller 이며 테스트 통계를 보여주거나 사용자가 스크립트를 생성 또는 변경하는 것을 가능하게 한다
Agenet
스크립트를 기반으로 프로세스를 실행하고 지정한 타겟에 실제로 트래픽을 발생시켜 스레드를 동작시키게 한다. Monitoring 모드에서 타겟 시스템의 성능을 모니터링 하는 것도 agent의 역할이다
Monitor
nGrinder 설치 및 실행 → Groovy script 작성 → 성능테스트 변수 설정 → 성능 테스트 실행 → 레포트 확인
nGrinder 설치 및 실행은 도커 컴포즈를 이용한다 - localhost:8880 ( 계정정보는 admin, admin 이다)
nGrinder 는 로컬호스트나 127.0.0.1 을 인식하지 못해서 공인 IP 주소를 통해 실행이 가능하다
아래는 nGrinder 실행을 위한 docker-compose 파일이다
version: '3.7'
services:
controller:
container_name: ngrinder-controller
image: ngrinder/controller:latest
environment:
- TZ=Asia/Seoul
ports:
- "8880:80"
- "16001:16001"
- "12000-12009:12000-12009"
volumes:
- /tmp/ngrinder-controller:/opt/ngrinder-controller
sysctls:
- net.core.somaxconn=65000
agent-1:
container_name: ngrinder-agent-1
image: ngrinder/agent:latest
links:
- controller
environment:
- TZ=Asia/Seoul
sysctls:
- net.core.somaxconn=65000
ulimits:
memlock:
soft: -1
hard: -1
nproc:
soft: 1024000
hard: 1024000
nofile:
soft: 1024000
hard: 1024000
agent-2:
container_name: ngrinder-agent-2
image: ngrinder/agent:latest
links:
- controller
environment:
- TZ=Asia/Seoul
sysctls:
- net.core.somaxconn=65000
ulimits:
memlock:
soft: -1
hard: -1
nproc:
soft: 1024000
hard: 1024000
nofile:
soft: 1024000
hard: 1024000
이렇게 controller, agent의 설치 후 해당 url에 접속하면 nGrinder 의 UI를 볼 수 있다
NGrinder 를 실행하면 자동으로 테스트 스크립트를 생성해준다
작성예정
파이썬 스크립트 기반의 Load Test Framework
locust 설치 및 실행 → locustfile.py 작성 → Web UI 접속 및 성능 테스트 변수 설정 → 성능 테스트 실행 → Report 확인
docker-compose.yml
version: '3'
services:
master:
image: locustio/locust
ports:
- "8089:8089"
volumes:
- ./:/mnt/locust
command: -f /mnt/locust/locustfile.py --master -H http://master:8089
worker:
image: locustio/locust
volumes:
- ./:/mnt/locust
command: -f /mnt/locust/locustfile.py --worker --master-host master
postgres:
image: postgres
container_name: locust-db
restart: always
ports:
- "5440:5432"
environment:
- POSTGRES_DB=client
- POSTGRES_USER=testuser
- POSTGRES_PASSWORD=testpass
locustfile.py
#!/usr/bin/env python
# Copyright 2020 The klocust Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from locust import HttpUser, TaskSet, task, between, events, constant
from locust.exception import StopUser
import random
DEBUG_MODE = False
def print_log(url, response):
if not DEBUG_MODE:
return
if response.status_code in [200, 201]:
print(f'[{response.status_code}] {url}')
else:
print(f'[{response.status_code}] {url} {response.text}')
class WebsiteTasks(TaskSet):
def __init__(self, parent):
super().__init__(parent)
self.default_headers = None
# call with starting new test
@events.test_start.add_listener
def on_test_start(**kwargs):
return
# call with stopping new test
@events.test_stop.add_listener
def on_test_stop(**kwargs):
return
# get, post, put, delete helper methods
def get(self, url, headers=None, name=None):
response = self.client.get(url, headers=headers or self.default_headers, name=name or url)
print_log(url, response)
return response
# call with starting new task
def on_start(self):
# self.login("email", "password")
return
# call with stopping new task
def on_stop(self):
# self.logout()
return
######################################################################
# write your tasks ###################################################
######################################################################
@task(60)
def getUserInfo(self):
self.get("/ceres/api/userinfo/"+str(random.randrange(1,12)))
@task(40)
def getServiceName(self):
self.get("/ceres/api/serviceName")
class WebsiteUser(HttpUser):
tasks = [WebsiteTasks]
# If you want no wait time between tasks
# wait_time = constant(0)
wait_time = between(1, 2)
# default target host
host = "http://192.168.120.109:8001"
https://judo0179.tistory.com/63
성능 테스트 가이드
https://fastcampus.co.kr/courses/213924/clips/
위의 블로그와 강의를 참고하여 작성하였습니다:)