ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Grinder : 로드(성능, 부하) 테스팅 도구
    웹개발 2014. 3. 27. 09:00
    반응형

    여러대의 장비를 이용해서 서버의 로드를 테스팅할수 있는 도구.
    http://grinder.sourceforge.net/

    기본 구조.
    Console, Agent, Worker로 구성되어 있음.
    Console이 메인 서버로 Agent들에 명령을 내리고
    각 Agent들이 개별 장비에 설치되어 실행되고 있다가 Console로 부터 명령을 받아서 테스트를 실행함.
    Agent가 Worker를 생성해서 테스트를 수행함.
    테스트 방법은 지정된 Jython 스크립트를 이용해서 수행.
    여러개의 테스트를 수행할때 각 테스트 케이스에 가중치를 줄 수 있음.







    Grinder Console실행

    java -cp ./grinder-3.11/lib/grinder.jar net.grinder.Console
    


    Grinder Agent 실행
    ava -cp ./grinder-3.11/lib/grinder.jar net.grinder.Grinder
    


    Agent가 Console에서 명령을 받아서 Grinder Script를 실행해서 테스트를 진행함. 
    Console에 연결할 수 없으면 Agent가 로컬에 있는 테스트 설정을 이용해서 테스트 수행


    스크립트
    1. 스크립트는 TestRunner 클래스를 정의해야 함.
    2. TestRunner 인스턴스는 호출가능해야 함.
       __call__ 메소드를 정의해야 함.
    3. 테스트 스크립트는 grinder 객체를 통해 서비스에 접근할 수 있어야 함.
    4. 스크립트 파일의 이름은 마지막이 .py로 끝나야 함.

    기본 스크립트 구조.

    from net.grinder.script import Test
    from net.grinder.script.Grinder import grinder
     
    test1 = Test(1, "Log method")
     
    # Instrument the info() method with our Test.
    test1.record(grinder.logger.info)
     
    class TestRunner:
        def __call__(self):
            grinder.logger.info("Hello World")
    


    URL 테스트용 스크립트(sampletest.py). 테스트 케이스별로 가중치를 줄 수 있음.

    #coding=UTF-8
    import string
    import random
    from java.lang import String
    from java.net import URLEncoder
    
    import java.lang.System, java.util.Random
    
    from net.grinder.script import Test
    from net.grinder.script.Grinder import grinder
    from net.grinder.plugin.http import HTTPRequest
    from HTTPClient import NVPair
    from net.grinder.common import GrinderException
    
    from random import choice
    
    
    test01 = 'CREATE'
    test02 = 'READ'
    test03 = 'UPDATE'
    test04 = 'DELETE'
    
    tests = {
        test01: Test(1, "Test " + test01),
        test02: Test(2, "Test " + test02),
        test03: Test(3, "Test " + test03),
        test04: Test(4, "Test " + test04),
    }
    
    #가중치 주려는 비율. 합이 100이 되도록 하면 됨.
    g_Weights = {
        test01: 20,
        test02: 40,
        test03: 30,
        test04: 10,
    }
    
    SERVER     = "http://127.0.0.1:8080"
    
    #랜덤 문자열 생성.
    def randomString(strSize):
        return (''.join(random.choice(string.ascii_lowercase) for i in range(strSize)))
    
    
    #URL에 요청 보내고 결과치 서버에 보고하기
    def send_request(TESTID, SERVER, URI, HEADERS):
        #Send the request to the server
        requestString = "%s%s" % (SERVER, URI)
        grinder.statistics.delayReports = 1
        request = HTTPRequest()
        tests[TESTID].record(request)
        request.setHeaders(HEADERS)
        result = request.GET(requestString)
        if result.getStatusCode() == 200:
            #log("StatusCode : %s " % result.getStatusCode())
            grinder.statistics.forLastTest.setSuccess(1)
        else:
            #log("StatusCode : %s " % result.getStatusCode())
            grinder.statistics.forLastTest.setSuccess(0)
    
    
    #테스트를 진행하는 함수들
    def doTest01():
        send_request(test01, SERVER, '/test01’, [NVPair("", "")])
    def doTest02():
        send_request(test02, SERVER, '/test02’, [NVPair("", "")]) 
    def doTest03():
        send_request(test03, SERVER, '/test03', [NVPair("", "")]) 
    def doTest04():
        send_request(test04, SERVER, '/test04', [NVPair("", "")]) 
    
    
    # 지정된 가중치 생성
    def weightAccumulator(i_dict):
        keyList = i_dict.keys()
        keyList.sort()  # sorting is optional - order coming-in doesn't matter, but determinism is kinda cool
        listAcc = []
        weightAcc = 0
        for key in keyList:
            weightAcc += i_dict[key]
            listAcc.append((key, weightAcc))
        return (listAcc, weightAcc)  # order going-out does matter - hence "listAcc" instead of "dictAcc"
    
    g_WeightsAcc, g_WeightsAccMax = weightAccumulator(g_Weights)
    g_WeightsAccLen, g_WeightsAccMax_1 = len(g_WeightsAcc), g_WeightsAccMax-1
    g_rng = java.util.Random(java.lang.System.currentTimeMillis())
    
    #주어진 min, max 사이에서 random 숫자 만들기
    def randNum(i_min, i_max):
        assert i_min <= i_max
        range = i_max - i_min + 1  # re-purposing "range" is legal in Python
        assert range <= 0x7fffffff  # because we're using java.util.Random
        randnum = i_min + g_rng.nextInt(range)
        assert i_min <= randnum <= i_max
        return randnum
    
    
    
    log = grinder.logger.info
    # out = grinder.logger.TERMINAL
    
    class TestRunner:
        def __call__(self):
            opNum = randNum(0, g_WeightsAccMax_1)
            opType = None
    
            for i in range(g_WeightsAccLen):
                if opNum < g_WeightsAcc[i][1]:
                    opType = g_WeightsAcc[i][0]
                    break
            assert opType in g_Weights.keys()
    
            if opType==test01:   doTest01()
            elif opType==test02: doTest02()
            elif opType==test03: doTest03()
            elif opType==test04: doTest04()
            else:
                assert False
    


    Grinder 결과 그래프로 보기
    Grinder Analyzer 이용
    http://track.sourceforge.net/

    jython을 이용하고 jython버전은 2.2.1, 2.5.0, 2.5.1, 2.5.2을 지원함.

    실행

    jython ./analyzer.py  ""  [number of agents]
    



    grinderReport에 결과 파일 생성됨.



    반응형

    '웹개발' 카테고리의 다른 글

    nginx에 basic auth 설정  (0) 2014.02.19
    yeoman 설치 및 실행  (0) 2014.02.12
    OSX에 Nginx 설치  (0) 2013.12.23

    댓글

Designed by Tistory.