nGrinder性能テスト
14801 ワード
概要
E-コマースの大型サーバープロジェクトの実際のトラフィック受信時のパフォーマンスをテストします.そこで,実際の環境を作成し,nGrinderを用いてサーバがどれだけのユーザを収容できるかをテストすることにした.
nGrinder
:Naverが開発した負荷テストツールコントローラ:WebベースのGUIシステムで、包括的なタスク管理とロードスクリプト作成機能を提供します. エージェント:コントローラの制御に基づいて実際に負荷が発生します. コントローラのインストールと実行
テスト機能カタログ クーポン を発行
1)カタログAPIの表示
1)商品リストの表示-VUser 500
2)クーポン取得-VUser 500
テスト結果の分析
1)商品リストの表示-VUser 500
VUserを500に設定し、10分間のテストを行いました.
しひょう
平均TPS:662
ピークTPS:921
CPU Usage : 100%
Errors : 2,674
2)クーポン取得-VUser 500
VUserを500に設定した後、10分間のテストを行いましたが、結果は以下の通りです.
しひょう
平均TPS:426
ピークTPS:538
CPU Usage : 100%
Errors : 0
ポスト
初めて性能テストを行いますが、nGrinderの使い方は公式文書や技術ブログに多くの資料があるので便利です.ただし、scriptでエラーが発生した場合、問題点を特定するのは難しいですが、nGrinderはログファイルを提供し、問題を参照して解決するのに役立ちます.nGrinder以外にも、JMeterなどの他の性能テストツールがありますが、次回は他のツールを使用して比較します.
📕 Reference
公式ドキュメント-インストールガイド
公式ドキュメント-ユーザーガイド
Groovyスクリプト作成方法
E-コマースの大型サーバープロジェクトの実際のトラフィック受信時のパフォーマンスをテストします.そこで,実際の環境を作成し,nGrinderを用いてサーバがどれだけのユーザを収容できるかをテストすることにした.
nGrinder
:Naverが開発した負荷テストツール
# 서버 접속 명령어
ssh root@[서버접속용IP] -p [포트번호]
# 관리자 비밀번호 입력
root@[IP]'s password:
# 서버 접속
# 자바 설치
[root@ngrinder-server ~]# yum list java*jdk-devel
[root@ngrinder-server ~]# yum install java-11-openjdk-devel.x86_64
# 설치 확인
[root@ngrinder-server ~]# which javac
/usr/bin/javac
[root@ngrinder-server ~]# java -version
openjdk version "11.0.14" 2022-01-18 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.14+9-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.14+9-LTS, mixed mode, sharing)
[root@ngrinder-server ~]# javac -version
javac 11.0.14
[root@ngrinder-server ~]# rpm -qa java*jdk-devel
java-11-openjdk-devel-11.0.14.0.9-1.el7_9.x86_64
[root@ngrinder-server ~]# readlink /etc/alternatives/javac
/usr/lib/jvm/java-11-openjdk-11.0.14.0.9-1.el7_9.x86_64/bin/javac
[root@ngrinder-server ~]# ls -l /usr/bin/javac
lrwxrwxrwx 1 root root 23 1월 30 14:06 /usr/bin/javac -> /etc/alternatives/javac
# 환경설정
[root@ngrinder-server ~]# vi /etc/profile
# 아래 코드 추가
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.14.0.9-1.el7_9.x86_64
export PATH=$JAVA_HOME/bin:$PATH
export JAVA_OPTS=Dfile.encoding=UTF-8
export CLASSPATH="."
[root@ngrinder-server ~]# source /etc/profile
# 서버 재시작
[root@ngrinder-server ~]# reboot
Connection to 106.10.50.203 closed by remote host.
Connection to 106.10.50.203 closed.
# nGrinder 다운로드
[root@ngrinder-server ~]# wget https://github.com/naver/ngrinder/releases/download/ngrinder-3.5.3-20201127/ngrinder-controller-3.5.3.war
# nGrinder 실행
java -jar ngrinder-controller-3.5.3.war
エージェントのインストールと実行[root@ngrinder-server ~]# cd /usr/local
# ngrinder 웹페이지 우측 상단에 admin 토글을 클릭하여 Download Agent를 눌러 agent tar 파일을 다운
# agent 다운로드
[root@ngrinder-server local]# wget --content-disposition http://[IP]:8080/agent/download
[root@ngrinder-server local]# ls
bin games lib libexec sbin src
etc include lib64 ngrinder-agent-3.5.3-[IP].tar share
[root@ngrinder-server local]# tar xvf ngrinder-agent-3.5.3-[IP].tar
[root@ngrinder-server local]# ls
bin include libexec sbin
etc lib ngrinder-agent share
games lib64 ngrinder-agent-3.5.3-1.[IP].tar src
[root@ngrinder-server local]# cd ngrinder-agent
[root@ngrinder-server ngrinder-agent]# ls
__agent.conf run_agent.sh run_agent_internal.sh
lib run_agent_bg.sh stop_agent.bat
run_agent.bat run_agent_internal.bat stop_agent.sh
[root@ngrinder-server ngrinder-agent]# cp __agent.conf agent.conf
[root@ngrinder-server ngrinder-agent]# ls
__agent.conf run_agent.bat run_agent_internal.bat stop_agent.sh
agent.conf run_agent.sh run_agent_internal.sh
lib run_agent_bg.sh stop_agent.bat
# agent 실행
[root@ngrinder-server ngrinder-agent]# sh run_agent.sh
テストスクリプトの作成テスト機能
1)カタログAPIの表示
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test1
public static GTest test2
public static GTest test3
public static HTTPRequest request
public static NVPair[] headers = []
public static NVPair[] params = []
public static Cookie[] cookies = []
public static MAX_RECORDS = 99800
// 프로세스가 생성될 때 동작해야하는 작업 정의
@BeforeProcess
public static void beforeProcess() {
HTTPPluginControl.getConnectionDefaults().timeout = 6000
// 각 테스트 통계를 수집할 때 사용되는 GTest인스턴스 정의
test1 = new GTest(1, "Test1")
test2 = new GTest(2, "Test2")
test3 = new GTest(3, "Test3")
request = new HTTPRequest()
grinder.logger.info("before process.");
}
// 각 쓰레드가 실행되기 전에 동작해야하는 작업 정의
@BeforeThread
public void beforeThread() {
//request 인스턴스에 대해 메소드를 호출하게 되면 테스트 별로 TPS증가시켜 기록
test1.record(this, "test1")
test2.record(this, "test2")
test3.record(this, "test3")
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
request.setHeaders(headers)
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
grinder.logger.info("before. init headers and cookies");
}
// 테스트 동작 정의
@Test
public void test1(){
String origin = "http://[public IP]:8080/products"
String deliveryType = "ROCKET"
int randomNum = Math.abs(new Random().nextInt() % MAX_RECORDS) + 1
String params = "?deliveryType="+ deliveryType +"&start="+ Integer.toString(randomNum) +"&listSize="+"100"
HTTPResponse result = request.GET(origin + params)
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode);
} else {
assertThat(result.statusCode, is(200));
}
}
@Test
public void test2(){
String origin = "http://[public IP]:8080/products"
String deliveryType = "ROCKET_FRESH"
int randomNum = Math.abs(new Random().nextInt() % MAX_RECORDS) + 1
String params = "?deliveryType="+ deliveryType +"&start="+ Integer.toString(randomNum) +"&listSize="+"100"
HTTPResponse result = request.GET(origin + params)
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode);
} else {
assertThat(result.statusCode, is(200));
}
}
@Test
public void test3(){
String origin = "http://[public IP]:8080/products"
String deliveryType = "ROCKET_GLOBAL"
int randomNum = Math.abs(new Random().nextInt() % MAX_RECORDS) + 1
String params = "?deliveryType="+ deliveryType +"&start="+ Integer.toString(randomNum) +"&listSize="+"100"
HTTPResponse result = request.GET(origin + params)
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode);
} else {
assertThat(result.statusCode, is(200));
}
}
}
2)クーポンAPI取得@RunWith(GrinderRunner)
class TestRunner {
public static GTest test
public static HTTPRequest request
public Object cookies = []
// map에서 NVPair로 convert하는 함수
def nvs(def map) {
def nvs = []
map.each {
key, value -> nvs.add(new NVPair(key, value))
}
return nvs as NVPair[]
}
// 프로세스가 생성될 때 동작해야하는 작업 정의
@BeforeProcess
public static void beforeProcess() {
HTTPPluginControl.getConnectionDefaults().timeout = 6000
// 각 테스트 통계를 수집할 때 사용되는 GTest인스턴스 정의
test = new GTest(1, "Test1")
request = new HTTPRequest()
//request 인스턴스에 대해 메소드를 호출하게 되면 테스트 별로 TPS증가시켜 기록
test.record(request);
grinder.logger.info("before process.");
}
// 각 쓰레드가 실행되기 전에 동작해야하는 작업 정의
@BeforeThread
public void beforeThread() {
// reset to the all cookies
def threadContext = HTTPPluginControl.getThreadHTTPClientContext()
cookies = CookieModule.listAllCookies(threadContext)
cookies.each {
CookieModule.removeCookie(it, threadContext)
}
// 테스트 전에 사전 작업으로 로그인 처리
int randomNum = Math.abs(new Random().nextInt() % 50000) + 1 //
String email = Integer.toString(randomNum) + "@naver.com" //
HTTPResponse result = request.POST("http://[public IP]:8080/users/login", nvs(["email":email, "password":"1234"])) //
// HTTPResponse result = request.POST("http://101.101.209.54:8080/users/login", nvs(["email":"[email protected]", "password":"1234"]))
cookies = CookieModule.listAllCookies(threadContext)
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
// set cookies for login state
def threadContext = HTTPPluginControl.getThreadHTTPClientContext()
cookies.each {
CookieModule.addCookie(it ,threadContext)
net.grinder.script.Grinder.grinder.logger.info("{}", it)
}
}
// 테스트 동작 정의
@Test
public void couponTest() {
int randomNum = Math.abs(new Random().nextInt() % 20000) + 1
String couponId = Integer.toString(randomNum)
request.POST("http://[public IP]:8080/available-coupons/" + couponId)
}
}
負荷テストの実行1)商品リストの表示-VUser 500
2)クーポン取得-VUser 500
テスト結果の分析
1)商品リストの表示-VUser 500
VUserを500に設定し、10分間のテストを行いました.
しひょう
平均TPS:662
ピークTPS:921
CPU Usage : 100%
Errors : 2,674
2)クーポン取得-VUser 500
VUserを500に設定した後、10分間のテストを行いましたが、結果は以下の通りです.
しひょう
平均TPS:426
ピークTPS:538
CPU Usage : 100%
Errors : 0
ポスト
初めて性能テストを行いますが、nGrinderの使い方は公式文書や技術ブログに多くの資料があるので便利です.ただし、scriptでエラーが発生した場合、問題点を特定するのは難しいですが、nGrinderはログファイルを提供し、問題を参照して解決するのに役立ちます.nGrinder以外にも、JMeterなどの他の性能テストツールがありますが、次回は他のツールを使用して比較します.
📕 Reference
公式ドキュメント-インストールガイド
公式ドキュメント-ユーザーガイド
Groovyスクリプト作成方法
Reference
この問題について(nGrinder性能テスト), 我々は、より多くの情報をここで見つけました https://velog.io/@sileeee/nGrinder를-이용한-성능테스트テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol