パフォーマンスの向上
概要
前の文章 nGrinderとPinpointを使用してボトルネックの原因を解析し、パフォーマンスを最適化する方法を検討した.次に、大型サーバープロジェクトのパフォーマンスを最適化および検証する方法について説明します.
商品リストを見てAPI性能を改善する
商品リストAPIを表示するには、ディスクI/Oを削減するためにRedisキャッシュを使用することを考慮します.
キャッシュを適用すると、ディスクI/Oのみに依存していたデータアクセスも、以下のようにRedisに分散していることがわかります.
スクリプトのテスト
@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
test1 = new GTest(1, "27.96.135.51")
test2 = new GTest(2, "27.96.135.51")
test3 = new GTest(3, "27.96.135.51")
request = new HTTPRequest()
grinder.logger.info("before process.");
}
@BeforeThread
public void beforeThread() {
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://27.96.135.51: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://27.96.135.51: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://27.96.135.51: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));
}
}
}
パフォーマンス向上後の負荷テスト結果
商品リストAPIを表示するには、ディスクI/Oを削減するためにRedisキャッシュを使用することを考慮します.
キャッシュを適用すると、ディスクI/Oのみに依存していたデータアクセスも、以下のようにRedisに分散していることがわかります.
スクリプトのテスト
@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
test1 = new GTest(1, "27.96.135.51")
test2 = new GTest(2, "27.96.135.51")
test3 = new GTest(3, "27.96.135.51")
request = new HTTPRequest()
grinder.logger.info("before process.");
}
@BeforeThread
public void beforeThread() {
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://27.96.135.51: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://27.96.135.51: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://27.96.135.51: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));
}
}
}
パフォーマンス向上後の負荷テスト結果
パフォーマンスの改善前後の比較
平均TPS:662
ピークTPS:921
平均TPS性能は70%近く向上し、1124に達した.
2,674
クーポン発行API性能改善 쿠폰 발급하기 API
のパフォーマンスを向上させるために、nginxを使用してサーバをscale-out
に構成します.これにより、nginxは負荷バランサとして機能し、1台のサーバではなく2台のサーバにトラフィックを分散させることができます.
スクリプトのテスト
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test
public static HTTPRequest request
public Object cookies = []
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
test = new GTest(1, "test : [POST] /available-coupons/1")
request = new HTTPRequest()
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://[nginxIP]:8080/users/login", nvs(["email":email, "password":"1234"]))
cookies = CookieModule.listAllCookies(threadContext)
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
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://[nginxIP]:8080/available-coupons/" + couponId)
}
}
パフォーマンス向上後の負荷テスト結果
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test
public static HTTPRequest request
public Object cookies = []
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
test = new GTest(1, "test : [POST] /available-coupons/1")
request = new HTTPRequest()
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://[nginxIP]:8080/users/login", nvs(["email":email, "password":"1234"]))
cookies = CookieModule.listAllCookies(threadContext)
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
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://[nginxIP]:8080/available-coupons/" + couponId)
}
}
-存在しないクーポンを発行したい場合
-同じクーポンを1人で複数回発行する場合
最終的には、パフォーマンスの低下ではなく、正しいサービスロジック「BAD REQUEST」を通じていると判断しました.
パフォーマンスの改善前後の比較
TPSチャート
✔TPSは約400~538の性能改善とは異なる
性能改善後、TPSは約450から667に向上した.
CPU使用量
АААААААААААААААА
ポスト
キャッシュを適用したり、サーバを横方向に拡張したりしても、実際の環境でのパフォーマンスが改善されたかどうかは判断しにくい.ただし、nGrinderおよびpinpointツールを使用すると、パフォーマンスが向上した点がわかります.
Reference
この問題について(パフォーマンスの向上), 我々は、より多くの情報をここで見つけました
https://velog.io/@sileeee/성능-개선하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(パフォーマンスの向上), 我々は、より多くの情報をここで見つけました https://velog.io/@sileeee/성능-개선하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol