Using nGrinder to perform DB load test - songeunwoo/ngrinder GitHub Wiki
One of the superiority of nGrinder is extensibility with java library in python. Because agent will execute the python script in jython, we can directly import java library in our test script. And here is the example to use jdbc library to perfoem DB load test.
Create jdbc test script:
Open the script list page and click “Create a script”:
Enter a name and select the checkbox to create lib directory. If you didn’t select it, you can also create the lib directory yourself.
After that, you can get a script based on a simple http test template. Then you can modify the script as below:
# -*- coding:utf-8 -*-
# Database test.
#
from java.sql import DriverManager
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from cubrid.jdbc.driver import CUBRIDDriver
from java.util import Random
from java.lang import System
test1 = Test(1, "Database insert")
test2 = Test(2, "Database update")
random = Random(long(System.nanoTime()))
# Load the JDBC driver.
DriverManager.registerDriver(CUBRIDDriver())
def getConnection():
return DriverManager.getConnection("jdbc:CUBRID:localhost:33000:ngrinder_cluster:::?charset=utf-8", "user", "password")
def ensureClosed(object):
try: object.close()
except: pass
# One time initialization that cleans out old data.
connection = getConnection()
statement = connection.createStatement()
# initialize the table should want to test.
statement.execute("drop table if exists ngrinder_update_temp")
statement.execute("create table ngrinder_update_temp(testid integer, test_number integer)")
ensureClosed(statement)
ensureClosed(connection)
class TestRunner:
def __call__(self):
connection = None
updateStatement = None
insertStatement = None
try:
# in this test, we will create connection and statement in every test transaction.
connection = getConnection()
updateStatement = connection.createStatement()
insertStatement = connection.createStatement()
insertStatement = test1.wrap(insertStatement)
tmpId = random.nextInt(1024000)
insertStatement.execute("insert into ngrinder_update_temp values(%d, %d)" %
(tmpId, random.nextInt(1024000)))
updateStatement = test2.wrap(updateStatement)
updateStatement.execute("update ngrinder_update_temp set test_number=%d where testid=%d" %
(random.nextInt(1024000), tmpId))
finally:
ensureClosed(updateStatement)
ensureClosed(insertStatement)
ensureClosed(connection)
Then you can click “Validate script” button to validate the syntex of the script. Be careful that the python needs some format requirement for indentation.
NOTICE:
Don’t forget to save the script, because it will not be saved during validating.
If there is no syntex error, then you will have an error about the driver can not be found. Then we need to upload the jdbc library into the “lib” directory. Open the script list page, and go into the lib directory. Click “Upload script or resources”:
Select the jdbc driver of the DB you want to test and upload.
Then go back to your script and validate again. If you get the message as below, it means the script and library has no problem.
2013-01-05 11:06:08,622 INFO The Grinder version 3.9.1
2013-01-05 11:06:08,628 INFO Java(TM) SE Runtime Environment 1.6.0_38-b05: Java HotSpot(TM) 64-Bit Server VM (20.13-b02, mixed mode) on Linux amd64 2.6.18-238.el5
2013-01-05 11:06:08,633 INFO time zone is CST (+0800)
2013-01-05 11:06:08,749 INFO worker process 0
2013-01-05 11:06:08,916 INFO instrumentation agents: traditional Jython instrumenter; byte code transforming instrumenter for Java
2013-01-05 11:06:13,335 INFO running "jdbs-test.py" using Jython 2.2.1
2013-01-05 11:06:13,358 INFO starting, will do 1 run
2013-01-05 11:06:13,359 INFO start time is 1357355173359 ms since Epoch
2013-01-05 11:06:13,410 INFO finished 1 run
2013-01-05 11:06:13,412 INFO elapsed time is 53 ms
2013-01-05 11:06:13,412 INFO Final statistics for this process:
2013-01-05 11:06:13,423 INFO
Tests Errors Mean Test Test Time TPS
Time (ms) Standard
Deviation
(ms)
Test 1 1 0 3.00 0.00 18.87 "Database insert"
Test 2 2 0 0.50 0.50 37.74 "Database update"
Totals 3 0 1.33 1.25 56.60
Tests resulting in error only contribute to the Errors column.
Statistics for individual tests can be found in the data file, including
(possibly incomplete) statistics for erroneous tests. Composite tests
are marked with () and not included in the totals.
2013-01-05 11:06:13,347 INFO validation-0: starting threads
2013-01-05 11:06:13,423 INFO validation-0: finished
Then create a test with this script:
If you have monitor installed on that DB server, you can also set the target server. Then you can get the monitor data during the test.
When you select the script, the uploaded library should appear in resources area.
Then you can check the test running and report.
In the test above, we create connection in every transaction, so the mean time of every running is about half second.
Below is the test script and report if I get conenction at the beginning of the test and resue the connection. (I commentted some code about getting/closing connection in every transaction.)
Jython
# -*- coding:utf-8 -*-
# Database test.
#
from java.sql import DriverManager
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from cubrid.jdbc.driver import CUBRIDDriver
from java.util import Random
from java.lang import System
test1 = Test(1, "Database insert")
test2 = Test(2, "Database update")
random = Random(long(System.nanoTime()))
# Load the JDBC driver.
DriverManager.registerDriver(CUBRIDDriver())
def getConnection():
return DriverManager.getConnection("jdbc:CUBRID:localhost:33000:ngrinder_cluster:::?charset=utf-8", "user", "password")
def ensureClosed(object):
try: object.close()
except: pass
# One time initialization that cleans out old data.
connection = getConnection()
statement = connection.createStatement()
# initialize the table should want to test.
statement.execute("drop table if exists ngrinder_update_temp")
statement.execute("create table ngrinder_update_temp(testid integer, test_number integer)")
ensureClosed(statement)
#ensureClosed(connection)
class TestRunner:
def __call__(self):
#connection = None
#updateStatement = None
#insertStatement = None
try:
# in this test, we will create connection and statement in every test transaction.
# connection = getConnection()
updateStatement = connection.createStatement()
insertStatement = connection.createStatement()
test1.record(insertStatement)
tmpId = random.nextInt(1024000)
insertStatement.execute("insert into ngrinder_update_temp values(%d, %d)" %
(tmpId, random.nextInt(1024000)))
updateStatement = test2.wrap(updateStatement)
updateStatement.execute("update ngrinder_update_temp set test_number=%d where testid=%d" %
(random.nextInt(1024000), tmpId))
finally:
ensureClosed(updateStatement)
ensureClosed(insertStatement)
Groovy
package org.ngrinder;
import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import groovy.sql.Sql
/**
* A simple example using the Groovy SQL that shows the retrieval of a
* Simple query.
*/
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test
public static sql
@BeforeProcess
public static void beforeProcess() {
test = new GTest(1, "Test1")
sql = Sql.newInstance( 'connection_string', 'id', 'password', 'cubrid.jdbc.driver.CUBRIDDriver' )
test.record(sql);
grinder.logger.info("before process.");
}
@BeforeThread
public void beforeThread() {
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Test
public void test(){
sql.eachRow( 'select * from code' ) { println "$it.s_name -- ${it.f_name} --" }
}
}