gatling系列教程(翻譯)-(附加二)feeders

Feeder是Iterator [Map [String,T]]的類型別名,這意味着由feed方法建立的組件將輪詢Map [String,T]記錄並注入其內容。html

創建一個定製的很是簡單。 例如,下面是如何構建一個隨機的電子郵件發生器:java

import scala.util.Random
val feeder = Iterator.continually(Map("email" -> (Random.alphanumeric.take(20).mkString + "@foo.com")))

這定義了一個工做流步驟,每一個虛擬用戶都在同一個Feeder上提供。redis

每次虛擬用戶達到此步驟時,它將從Feeder中彈出一條記錄,該記錄將被注入到用戶的Session中,從而產生一個新的Session實例。sql

若是Feeder沒法生成足夠的記錄,Gatling會抱怨它,您的模擬將中止。數據庫

您也能夠一次提供多條記錄。 若是是,屬性名稱將被後綴。 例如,若是列是名稱「foo」和「bar」,而且您一次提供2條記錄,您將得到「foo1」,「bar1」,「foo2」和「bar2」會話屬性json

feed(feeder, 2)

RecordSeqFeederBuilder
Array [Map [String,T]]或IndexedSeq [Map [String,T]]能夠隱式地變成Feeder。 此外,這種隱式轉換還提供了一些額外的方法來定義Seq迭代的方式:數組

.queue    // default behavior: use an Iterator on the underlying sequence
.random   // randomly pick an entry in the sequence
.shuffle  // shuffle entries, then behave live queue
.circular // go back to the top of the sequence once the end is reached

For example:session

val feeder = Array(
  Map("foo" -> "foo1", "bar" -> "bar1"),
  Map("foo" -> "foo2", "bar" -> "bar2"),
  Map("foo" -> "foo3", "bar" -> "bar3")).random

CSV feeder
Gatling提供了幾個用於讀取字符分隔值文件的內置函數。dom

文件預計將放置在Gatling發行版的數據目錄中。 該位置能夠被覆蓋,請參閱配置。函數

默認狀況下,咱們的解析器遵循RFC4180,所以不要期望不遵照此規範的行爲。

惟一的區別是標題字段修剪包裝空白。

val csvFeeder = csv("foo.csv") // use a comma separator
val tsvFeeder = tsv("foo.tsv") // //使用製表分隔符
val ssvFeeder = ssv("foo.ssv") // 使用分號分隔符
val customSeparatorFeeder = separatedValues("foo.txt", '#') // use your own separator

這些內置函數返回RecordSeqFeederBuilder實例,這意味着整個文件被加載到內存中並進行解析,所以在仿真運行期間,生成的引導程序不會在磁盤上讀取。

警告

在內存中加載進feeder文件使用大量的堆,指望文件大小爲5到10倍。 這是因爲JVM的內部UTF-16字符編碼和對象標頭開銷。 若是內存是一個問題,您可能須要從文件系統中即時讀取並構建您本身的Feeder。

除了在RFC中描述的引用功能以外,還能夠指定轉義字符,所以某些內容字符不會被分隔符或引用字符混淆。

val csvFeeder = csv(「foo.csv」,escapeChar ='\\')

JSON feeders

Some might want to use data in JSON format instead of CSV:

val jsonFileFeeder = jsonFile("foo.json")
val jsonUrlFeeder = jsonUrl("http://me.com/foo.json")

For example, the following JSON:

[
  {
    "id":19434,
    "foo":1
  },
  {
    "id":19435,
    "foo":2
  }
]

will be turned into:

record1: Map("id" -> 19434, "foo" -> 1)
record2: Map("id" -> 19435, "foo" -> 2)

Note that the root element has of course to be an array.

請注意,根元素固然是一個數組。

JDBC feeder
Gatling還提供從JDBC鏈接讀取的內置函數。

// beware: you need to import the jdbc module
import io.gatling.jdbc.Predef._

jdbcFeeder("databaseUrl", "username", "password", "SELECT * FROM users")

就像File parser的內置函數同樣,這返回一個RecordSeqFeederBuilder實例。

databaseURL必須是JDBC URL(例如jdbc:postgresql:gatling),
用戶名和密碼是訪問數據庫的憑據,
sql是將獲取所需值的查詢。
僅支持JDBC4驅動程序,以便它們自動註冊到DriverManager。

Sitemap Feeder

Gatling supports a feeder that reads data from a Sitemap file.

// beware: you need to import the http module
import io.gatling.http.Predef._

val feeder = sitemap("/path/to/sitemap/file")

The following Sitemap file:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.example.com/</loc>
    <lastmod>2005-01-01</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>

  <url>
    <loc>http://www.example.com/catalog?item=12&amp;desc=vacation_hawaii</loc>
    <changefreq>weekly</changefreq>
  </url>

  <url>
    <loc>http://www.example.com/catalog?item=73&amp;desc=vacation_new_zealand</loc>
    <lastmod>2004-12-23</lastmod>
    <changefreq>weekly</changefreq>
  </url>
</urlset>

will be turned into:

record1: Map(
           "loc" -> "http://www.example.com/",
           "lastmod" -> "2005-01-01",
           "changefreq" -> "monthly",
           "priority" -> "0.8")

record2: Map(
           "loc" -> "http://www.example.com/catalog?item=12&amp;desc=vacation_hawaii",
           "changefreq" -> "weekly")

record3: Map(
           "loc" -> "http://www.example.com/catalog?item=73&amp;desc=vacation_new_zealand",
           "lastmod" -> "2004-12-23",
           "changefreq" -> "weekly")

Redis feeder
這個功能最初由Krishnen Chedambarum提供。

Gatling能夠使用如下Redis命令之一從Redis讀取數據。

LPOP - 刪除並返回列表的第一個元素
SPOP - 從集合中刪除並返回一個隨機元素
SRANDMEMBER - 從集合中返回一個隨機元素
默認狀況下RedisFeeder使用LPOP命令:

import com.redis._
import io.gatling.redis.feeder.RedisFeeder

val redisPool = new RedisClientPool("localhost", 6379)

// use a list, so there's one single value per record, which is here named "foo"
val feeder = RedisFeeder(redisPool, "foo")

可選的第三個參數用於指定所需的Redis命令:

// read data using SPOP command from a set named "foo"
val feeder = RedisFeeder(clientPool, "foo", RedisFeeder.SPOP)

請注意,自v2.1.14起,Redis支持從文件中大量插入數據。 Redis能夠在幾秒鐘內加載數百萬個密鑰,Gatling將直接將內存從內存中讀取。

例如:一個簡單的Scala函數,用於生成一個具備100萬個不一樣URL的文件,能夠在名爲URLS的Redis列表中加載:

import java.io.{ File, PrintWriter }
import io.gatling.redis.util.RedisHelper._

def generateOneMillionUrls(): Unit = {
  val writer = new PrintWriter(new File("/tmp/loadtest.txt"))
  try {
    for (i <- 0 to 1000000) {
      val url = "test?id=" + i
      // note the list name "URLS" here
      writer.write(generateRedisProtocol("LPUSH", "URLS", url))
    }
  } finally {
    writer.close()
  }
}

The urls can then be loaded in Redis using the following command:

`cat /tmp/loadtest.txt | redis-cli --pipe`

轉換
有時候,您可能須要轉換您的進紙器的原始數據。

例如,一個csv進紙器只會給你一個字符串,但你可能但願將一個屬性轉換成一個Int。

convert(convert:PartialFunction [(String,T),Any])須要:

一個PartialFunction,這意味着您只須要爲要轉換的範圍定義它,則不匹配的屬性將保持不變
其輸入是(String,T)對,其中第一個元素是屬性名稱,第二個元素是屬性值
而且其輸出爲Any,不管您想要什麼
例如:

csv("myFile.csv").convert {
  case ("attributeThatShouldBeAnInt", string) => string.toInt
}

有時,您可能但願全部虛擬用戶都能播放文件中的全部記錄,而Feeder與此行爲不匹配。

不過,它很容易構建,感謝flattenMapIntoAttributes,例如:

val records = csv("foo.csv").records

foreach(records, "record") {
  exec(flattenMapIntoAttributes("${record}"))
}

用戶依賴數據
有時,您可能須要根據會話中的某些信息過濾注入的數據。

饋線不能實現這一點,由於它只是一個迭代器,因此它不知道上下文。

而後,您必須編寫本身的注入邏輯,但您固然能夠重用Gatling解析器。

請考慮如下示例,其中有2個文件,而且要從第二個文件注入數據,具體取決於從第一個注入的內容。

In userProject.csv:

user, project
bob, aProject
sue, bProject

In projectIssue.csv:

project,issue
aProject,1
aProject,12
aProject,14
aProject,15
aProject,17
aProject,5
aProject,7
bProject,1
bProject,2
bProject,6
bProject,64

Here’s how you can randomly inject an issue, depending on the project:

import io.gatling.core.feeder._
import java.util.concurrent.ThreadLocalRandom

// index records by project
val recordsByProject: Map[String, IndexedSeq[Record[String]]] =
  csv("projectIssue.csv").records.groupBy{ record => record("project") }

// convert the Map values to get only the issues instead of the full records
val issuesByProject: Map[String, IndexedSeq[String]] =
  recordsByProject.mapValues{ records => records.map {record => record("issue")} }

// inject project
feed(csv("userProject.csv"))

  .exec { session =>
  // fetch project from  session
  session("project").validate[String].map { project =>

    // fetch project's issues
    val issues = issuesByProject(project)

    // randomly select an issue
    val selectedIssue = issues(ThreadLocalRandom.current.nextInt(issues.length))

    // inject the issue in the session
    session.set("issue", selectedIssue)
  }
}
相關文章
相關標籤/搜索