성능 개선하기
개요
이전 글에서는 nGrinder와 pinpoint를 사용하여 병목 원인을 분석하였고, 성능을 최적화할 수 있는 방안을 생각해보았습니다. 이제 실제로 대용량 서버 프로젝트의 성능을 최적화하고 확인하는 과정을 기록해보려고 합니다.
상품 목록 보기 API 성능 개선
상품 목록 보기 API는 Disk I/O를 줄이기 위한 방법으로  Redis 캐시를 생각하였습니다.
캐시를 적용하여 위와 같이 기존에 Disk I/O에만 의존하던 Data Access가 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));
		}
	}
}
성능 개선 후 부하테스트 결과
- nGrinder report
 - 지표
- TPS : 1,124
 - Peak TPS : 1,547
 - CPU Usage : 100%
 - Errors : 0
 
 
성능개선 전/후 비교하기
- TPS 개선 [전]
평균 TPS : 662
피크 TPS : 921
 
- Error 개선 [전]
2,674
 
쿠폰 발급하기 API 성능 개선
쿠폰 발급하기 API의 성능을 개선하기 위해, nginx를 활용하여 scale-out으로 서버를 구성하였습니다. nginx가 로드밸런서 역할을 하도록 만들어 트래픽을 하나의 서버가 아닌 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)
	}
}
성능 개선 후 부하테스트 결과
- nGrinder report  
 
성능개선 전/후 비교하기
- 
TPS 그래프
✔️ TPS가 대략 400에서 538까지인 성능 개선 전과 달리 성능 개선 후엔 TPS가 대략 450에서 667까지 도달하였습니다. - 
CPU 사용량
✔️ 스케일 아웃으로 서버를 확장한 결과, CPU사용률이 절반으로 줄어든 것을 확인할 수 있습니다. 
 
후기
캐싱을 적용하거나 스케일아웃으로 서버를 확장하였다고 해도 실제 환경에서 정말 성능이 개선된 것인지 확인하기 어렵습니다. 하지만 이렇게 nGrinder, pinpoint툴을 사용하여 어떤 부분에서 성능이 얼마나 개선되었는지 눈으로 볼 수 있었습니다.
Author And Source
이 문제에 관하여(성능 개선하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sileeee/성능-개선하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)