在Gatling场景中生成多个进一步操作的操作

时间:2017-02-23 12:08:23

标签: gatling stress-testing

背景

我目前正在研究一套能力测试工具,我正在使用gatling。

部分原因是使用滚动查询加载弹性搜索,然后更新API调用。

我想要实现的目标

第1步:运行滚动启动器,并通过进一步滚动查询保存_scroll_id可以使用的位置

第2步:重复运行滚动查询,每个滚动查询的一部分对返回的每个匹配进行修改并将其索引回弹性搜索,从一个卷轴有效地生成最多1000个动作查询操作,并对结果进行抽样。

第1步很简单。第二步不是那么多。

我尝试了什么

我目前正在尝试通过一个解析JSON格式结果的ResponseTransformer来实现这一目的,对每个结果进行修改,然后为每个尝试另一个exec(http(...).post(...) etc)索引更改的线程触发一个线程。 elasticsearch。

基本上,我认为我会以错误的方式解决这个问题。索引线程永远不会运行,更不用说通过gatling进行采样。

这是我的滚动查询操作的主体:

  ...

  val pool = Executors.newFixedThreadPool(parallelism)

  val query = exec(http("Scroll Query")
    .get(s"/_search/scroll")
    .body(ElFileBody("queries/scrollquery.json")).asJSON // Do the scroll query
    .check(jsonPath("$._scroll_id").saveAs("scroll_id")) // Get the scroll ID from the response
    .transformResponse { case response if response.isReceived =>
      new ResponseWrapper(response) {
        val responseJson = JSON.parseFull(response.body.string)
        // Get the hits and
        val hits = responseJson.get.asInstanceOf[Map[String, Any]]("hits").asInstanceOf[Map[String,Any]]("hits").asInstanceOf[List[Map[String, Any]]]
        for (hit <- hits) {
          val id = hit.get("_id").get.asInstanceOf[String]
          val immutableSource = hit.get("_source").get.asInstanceOf[Map[String, Any]]
          val source = collection.mutable.Map(immutableSource.toSeq: _*) // Make the map mutable
          source("newfield") = "testvalue" // Make a modification
          Thread.sleep(pause) // Pause to simulate topology throughput
          pool.execute(new DocumentIndexer(index, doctype, id, source)) // Create a new thread that executes the index request
        }
      }
    }) // Make some mods and re-index into elasticsearch

  ...

DocumentIndexer看起来像这样:

class DocumentIndexer(index: String, doctype: String, id: String, source: scala.collection.mutable.Map[String, Any]) extends Runnable {

  ...

  val httpConf = http
    .baseURL(s"http://$host:$port/${index}/${doctype}/${id}")
    .acceptHeader("application/json")
    .doNotTrackHeader("1")
    .disableWarmUp

  override def run() {

    val json = new ObjectMapper().writeValueAsString(source)

    exec(http(s"Index ${id}")
      .post("/_update")
      .body(StringBody(json)).asJSON)

  }

}

问题

  1. 这是否可以使用gatling?
  2. 我如何实现我想要达到的目标?
  3. 感谢您的任何帮助/建议!

1 个答案:

答案 0 :(得分:1)

可以通过使用jsonPath提取JSON命中数组并将元素保存到会话中,然后使用操作链中的foreach和exec中的索引任务来实现此目的。你可以相应地执行索引的循环。

即:
ScrollQuery

...
  val query = exec(http("Scroll Query")
    .get(s"/_search/scroll")
    .body(ElFileBody("queries/scrollquery.json")).asJSON // Do the scroll query
    .check(jsonPath("$._scroll_id").saveAs("scroll_id")) // Get the scroll ID from the response
    .check(jsonPath("$.hits.hits[*]").ofType[Map[String,Any]].findAll.saveAs("hitsJson")) // Save a List of hit Maps into the session
  )
...

<强>模拟

...
    val scrollQueries = scenario("Enrichment Topologies").exec(ScrollQueryInitiator.query, repeat(numberOfPagesToScrollThrough, "scrollQueryCounter"){
        exec(ScrollQuery.query, pause(10 seconds).foreach("${hitsJson}", "hit"){ exec(HitProcessor.query) })
    })
...

<强> HitProcessor

...
  def getBody(session: Session): String = {
    val hit = session("hit").as[Map[String,Any]]
    val id = hit("_id").asInstanceOf[String]
    val source = mapAsScalaMap(hit("_source").asInstanceOf[java.util.LinkedHashMap[String,Any]])
    source.put("newfield", "testvalue")
    val sourceJson = new ObjectMapper().writeValueAsString(mapAsJavaMap(source))
    val json = s"""{"doc":${sourceJson}}"""
    json
  }

  def getId(session: Session): String = {
    val hit = session("hit").as[Map[String,Any]]
    val id = URLEncoder.encode(hit("_id").asInstanceOf[String], "UTF-8")
    val uri = s"/${index}/${doctype}/${id}/_update"
    uri
  }

  val query = exec(http(s"Index Item")
    .post(session => getId(session))
    .body(StringBody(session => getBody(session))).asJSON)
...

免责声明:此代码仍需优化!而且我还没有学到很多scala。随意使用更好的解决方案发表评论

完成此操作后,我现在真正想要实现的是并行化一定数量的索引任务。即:我得到1000次点击,我想为每个单独的命中执行一个索引任务,但不是仅仅迭代它们并且一个接一个地执行它们,我想同时做10个。

但是,我认为这是一个单独的问题,所以我会这样提出。