Я познакомился с инструментом тестирования производительности с открытым исходным кодом Gatling несколько месяцев назад от Дастина Барнса и влюбился в него. Он имеет простой в использовании DSL, и хотя я не знаю, что такое Scala , я смог понять, как его использовать. Он создает довольно классную графику и выполняет за вас большую работу за кулисами. У них есть отличная документация и довольно активная группа Google, где приветствуются новички и вопросы.
Он поставляется вместе со Scala, поэтому все, что вам нужно сделать, это создать свои тесты и использовать командную строку для их выполнения. Я покажу вам, как сделать несколько основных вещей, например, проверить, что у вас все работает, затем мы создадим узлы и отношения и затем запросим эти узлы.
Мы начнем с операторов импорта:
import com.excilys.ebi.gatling.core.Predef._ import com.excilys.ebi.gatling.http.Predef._ import akka.util.duration._ import bootstrap._
Тогда мы начнем сразу с нашей симуляции. Для этого первого теста мы просто собираемся получить корневой узел через API REST. Мы указываем наш сервер Neo4j, в этом случае я тестирую на локальном хосте (вы захотите запустить тестовый код и сервер Neo4j на разных серверах, когда делаете это по-настоящему). Далее мы указываем, что мы принимаем JSON для возврата. В нашем тестовом сценарии в течение 10 секунд мы получим «/ db / data / node / 0» и проверим, что Neo4j возвращает код состояния http 200 (все будет в порядке). Мы сделаем паузу между 0 и 5 миллисекундами между вызовами, чтобы симулировать реальных пользователей, и в нашей настройке мы укажем, что нам нужно 100 пользователей.
class GetRoot extends Simulation {
val httpConf = httpConfig
.baseURL("http://localhost:7474")
.acceptHeader("application/json")
val scn = scenario("Get Root")
.during(10) {
exec(
http("get root node")
.get("/db/data/node/0")
.check(status.is(200)))
.pause(0 milliseconds, 5 milliseconds)
}
setUp(
scn.users(100).protocolConfig(httpConf)
)
}
Мы назовем этот файл «GetRoot.scala» и поместим его в user-files / simulations / neo4j.
gatling-charts-highcharts-1.4.0/user-files/simulations/neo4j/
Мы можем запустить наш код с:
~$ bin/gatling.sh
Мы получим подсказку с вопросом, какой тест мы хотим запустить:
GATLING_HOME is set to /Users/maxdemarzi/Projects/gatling-charts-highcharts-1.4.0
Choose a simulation number:
[0] GetRoot
[1] advanced.AdvancedExampleSimulation
[2] basic.BasicExampleSimulation
Выберите номер рядом с GetRoot и нажмите ввод.
Затем вам будет предложено ввести идентификатор, или вы можете просто перейти по умолчанию, нажав клавишу ввода еще раз:
Select simulation id (default is 'getroot'). Accepted characters are a-z, A-Z, 0-9, - and _
Если вы хотите добавить описание, вы можете:
Select run description (optional)
Наконец это начинается по-настоящему:
================================================================================
2013-02-14 17:18:03 10s elapsed
---- Get Root ------------------------------------------------------------------
Users : [#################################################################]100%
waiting:0 / running:0 / done:100
---- Requests ------------------------------------------------------------------
> get root node OK=58457 KO=0
================================================================================
Simulation finished.
Simulation successful.
Generating reports...
Reports generated in 0s.
Please open the following file : /Users/maxdemarzi/Projects/gatling-charts-highcharts-1.4.0/results/getroot-20130214171753/index.html
Индикатор выполнения — это показатель общего числа пользователей, выполнивших свою задачу, а не показатель выполненного моделирования, поэтому не беспокойтесь, если он долгое время остается на нуле, а затем быстро переходит на 100%. Вы также можете увидеть номера OK (тест пройден) и KO (тест не пройден). Наконец, он создает отличный отчет на основе HTML для нас. Давайте взглянем:
Здесь вы можете увидеть статистику о времени ответа, а также количество запросов в секунду. Это здорово, мы можем получить корневой узел, но это не очень интересно, давайте создадим несколько узлов:
class CreateNodes extends Simulation {
val httpConf = httpConfig
.baseURL("http://localhost:7474")
.acceptHeader("application/json")
val createNode = """{"query": "create me"}"""
val scn = scenario("Create Nodes")
.repeat(1000) {
exec(
http("create node")
.post("/db/data/cypher")
.body(createNode)
.asJSON
.check(status.is(200)))
.pause(0 milliseconds, 5 milliseconds)
}
setUp(
scn.users(100).ramp(10).protocolConfig(httpConf)
)
}
В этом случае мы устанавливаем 100 пользователей для создания 1000 узлов каждый со временем линейного изменения 10 секунд. Мы запустим эту симуляцию, как и раньше, но выберите «Создать узлы». Как только это будет сделано, взгляните на отчет и немного прокрутите вниз, чтобы увидеть график количества запросов в секунду:
Вы можете видеть количество пользователей, увеличивающихся за первые 10 секунд и исчезающих в конце. Давайте продолжим и соединим некоторые из этих узлов вместе:
Мы добавим JSONObject в операторы импорта, и, поскольку я хочу увидеть, какие узлы мы связываем с какими узлами вместе, мы распечатаем детали для запроса. Я случайно выбираю два идентификатора и передаю их в запрос на шифрование для создания отношений:
import com.excilys.ebi.gatling.core.Predef._
import com.excilys.ebi.gatling.http.Predef._
import akka.util.duration._
import bootstrap._
import util.parsing.json.JSONObject
class CreateRelationships extends Simulation {
val httpConf = httpConfig
.baseURL("http://localhost:7474")
.acceptHeader("application/json")
.requestInfoExtractor(request => {
println(request.getStringData)
Nil
})
val rnd = new scala.util.Random
val chooseRandomNodes = exec((session) => {
session.setAttribute("params", JSONObject(Map("id1" -> rnd.nextInt(100000),
"id2" -> rnd.nextInt(100000))).toString())
})
val createRelationship = """START node1=node({id1}), node2=node({id2}) CREATE UNIQUE node1-[:KNOWS]->node2"""
val cypherQuery = """{"query": "%s", "params": %s }""".format(createRelationship, "${params}")
val scn = scenario("Create Relationships")
.during(30) {
exec(chooseRandomNodes)
.exec(
http("create relationships")
.post("/db/data/cypher")
.header("X-Stream", "true")
.body(cypherQuery)
.asJSON
.check(status.is(200)))
.pause(0 milliseconds, 5 milliseconds)
}
setUp(
scn.users(100).ramp(10).protocolConfig(httpConf)
)
}
Когда вы запустите это, вы увидите поток параметров, которые мы отправили на наш почтовый запрос:
{"query": "START node1=node({id1}), node2=node({id2}) CREATE UNIQUE node1-[:KNOWS]->node2", "params": {"id1" : 98468, "id2" : 20147} }
{"query": "START node1=node({id1}), node2=node({id2}) CREATE UNIQUE node1-[:KNOWS]->node2", "params": {"id1" : 83557, "id2" : 26633} }
{"query": "START node1=node({id1}), node2=node({id2}) CREATE UNIQUE node1-[:KNOWS]->node2", "params": {"id1" : 22386, "id2" : 99139} }
Вы можете отключить это, но я просто хотел убедиться, что идентификаторы были случайными, и это помогает при отладке. Теперь мы можем запросить график. Для этого следующего моделирования я хочу увидеть ответы, возвращенные из Neo4j, и я хочу видеть узлы, связанные с 10 случайными узлами, переданными в виде массива JSON. Обратите внимание, что это немного отличается от предыдущего, и мы также проверяем, получили ли мы «данные» обратно в нашем запросе.
import com.excilys.ebi.gatling.core.Predef._
import com.excilys.ebi.gatling.http.Predef._
import akka.util.duration._
import bootstrap._
import util.parsing.json.JSONArray
class QueryGraph extends Simulation {
val httpConf = httpConfig
.baseURL("http://localhost:7474")
.acceptHeader("application/json")
.responseInfoExtractor(response => {
println(response.getResponseBody)
Nil
})
.disableResponseChunksDiscarding
val rnd = new scala.util.Random
val nodeRange = 1 to 100000
val chooseRandomNodes = exec((session) => {
session.setAttribute("node_ids", JSONArray.apply(List.fill(10)(nodeRange(rnd.nextInt(nodeRange length)))).toString())
})
val getNodes = """START nodes=node({ids}) MATCH nodes -[:KNOWS]-> other_nodes RETURN ID(other_nodes)"""
val cypherQuery = """{"query": "%s", "params": {"ids": %s}}""".format(getNodes, "${node_ids}")
val scn = scenario("Query Graph")
.during(30) {
exec(chooseRandomNodes)
.exec(
http("query graph")
.post("/db/data/cypher")
.header("X-Stream", "true")
.body(cypherQuery)
.asJSON
.check(status.is(200))
.check(jsonPath("data")))
.pause(0 milliseconds, 5 milliseconds)
}
setUp(
scn.users(100).ramp(10).protocolConfig(httpConf)
)
}
Если мы посмотрим на вкладку сведений для этого моделирования, мы увидим небольшой всплеск в середине:
Это контрольный знак того, что сборка мусора в JVM происходит, и мы можем захотеть разобраться в этом. Отредактируйте файл neo4j / conf / neo4j-wrapper.conf и раскомментируйте ведение журнала сбора мусора, а также добавьте метки времени, чтобы улучшить видимость проблемы:
# Uncomment the following line to enable garbage collection logging wrapper.java.additional.4=-Xloggc:data/log/neo4j-gc.log wrapper.java.additional.5=-XX:+PrintGCDateStamps
Настройка производительности Neo4j заслуживает отдельного поста в блоге, но, по крайней мере, теперь у вас есть отличный способ проверить свою производительность, настроив JVM, кеш, оборудование, балансировку нагрузки и другие параметры. Не забывайте, что тестирование Neo4j напрямую — это круто, вы можете использовать Gatling для тестирования всего веб-приложения и измерения производительности от начала до конца.



