scala - Gatling stomp 发布/订阅负载测试
问题描述
我通过 WS 有 Web 服务器 Spring boot + STOMP。很快这个微服务将投入生产,我想测量 websocket 在负载下的性能。我想知道我的服务将处理多少用户(并基于该配置自动缩放)
服务是 REST API + STOMP 主题发布者。我想写一个场景:
- 在第一次迭代中产生 1 个用户,通过 websocket 连接,订阅一个主题,然后发布一条消息并验证用户通过 WS 接收到它,关闭连接。
- 在第二次迭代中产生 10 个用户,通过 websocket 连接,订阅一个主题,然后发布一条消息并验证 10 个用户通过 WS 收到它,关闭连接;
- 在第三次迭代中产生 100 个用户,通过 websocket 连接,订阅一个主题,然后发布一条消息并验证 100 个用户通过 WS 接收到它,关闭连接;
- 等等。
然后,根据统计数据,我会发现有多少用户可以处理我的服务。目前我可以生成用户,通过 WS 进行连接,仅此而已。如何创建一定数量的用户并创建单个 http 请求,该请求将触发所有用户订阅的 STOMP 主题上的事件发布?
这是我当前的测试场景。
package computerdatabase
import java.util.concurrent.TimeUnit
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.core.check.Check
import io.gatling.http.Predef._
import io.gatling.http.check.ws.WsTextCheck
import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.util.Random
class TickerSimulation extends Simulation {
val baseUrl = "https://myserverurl.com"
val httpProtocol = http
.baseUrl(baseUrl)
.inferHtmlResources(BlackList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.woff2""", """.*\.(t|o)tf""", """.*\.png""", """.*detectportal\.firefox\.com.*"""))
.acceptHeader("*/*")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("de,en-US;q=0.7,en;q=0.3")
.userAgentHeader("Mozilla/5.0 (X11; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0")
def randomServerId(): String = {
val rand = new Random()
(1 to 3).map { _ => rand.nextInt(10).toString }.mkString
}
def randomSessionId(): String = {
Random.alphanumeric.take(8).mkString
}
val feeder = Iterator.continually(Map(
"serverId" -> randomServerId(),
"sessionId" -> randomSessionId()
))
val headers_0 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"DNT" -> "1",
"Pragma" -> "no-cache",
"Content-Type" -> "application/json",
"Upgrade-Insecure-Requests" -> "1",
"Authorization" -> "Basic somebasicauth=")
val answerCheck = ws.checkTextMessage("Connection acknowledge answer")
.check(regex("^a.*"))
val answerEventCheck = ws.checkTextMessage("Game event received")
.check(regex(".*gameEvent.*"))
val scn = scenario("WidgetTicker")
.feed(feeder)
.exec(http("Get game info ")
.get("/api/game/35384")
.headers(headers_0))
.pause(Random.nextInt(10))
.exec(ws("WS connection").connect("ws://myserverurl.com/api/sock/${serverId}/${sessionId}/websocket"))
.pause(1)
.exec(ws("Connect via STOMP")
.sendText("[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]")
.await(60 seconds)(answerCheck)
).pause(3)
.exec(ws("Subscribe")
.sendText("""["SUBSCRIBE\nid:sub-0\ndestination:/topic/game/35384\n\n\u0000"]""")
.await(60 seconds)(answerEventCheck)
)
.pause(3)
.exec(ws("WS close").close)
setUp(scn.inject(
atOnceUsers(1000)
)).protocols(httpProtocol)
}
解决方案
我创建了一个主题,服务器每隔几秒就会写入一次。然后我在模拟期间验证用户是否收到此消息。并以这种方式测试 pub/sub WebSocket 连接
这是我想出的:
val answerEventCheck = ws.checkTextMessage("Game event received")
.check(regex("""^a.*topic\/game\/123.*"""))
val scn = scenario("WidgetTicker")
.feed(feeder)
.exec(ws("WS connection").connect("ws://${baseUrl}/api/sock/${serverId}/${sessionId}/websocket"))
.pause(1)
.exec(ws("Connect via STOMP")
.sendText("[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]")
.await(3 seconds)(answerCheck)
).pause(3)
.exec(ws("Subscribe")
.sendText("[\"SUBSCRIBE\\nid:sub-0\\ndestination:/topic/game/123\\n\\n\\u0000\"]")
.await(5 seconds)(answerEventCheck)
)
.pause(5)
.exec(ws("WS close").close)
推荐阅读
- php - 尽管第一个 elseif 语句首先为真,但所有 else if 都会被触发
- go - 在开发过程中如何构建一个包?
- python - Setting Foreign Keys with SQLAlchemy for FastAPI
- laravel - mdi 图标未显示/工作 Laravel 8/Vue 2/Vuetify
- sql - 获取每个唯一 id 列的最后更改值的第一次出现
- python-3.x - 从熊猫数据框中提取数据
- python - Python 类型感知文档字符串标准
- javascript - 我如何将我的图像对齐页面上的所有其他内容?
- sql - Oracle SQL 检查日期是否在今天和另一个日期之间
- ruby - 在 ruby 1.8.6 中将具有任意时区的 Datetime 转换为相应的 Time 对象,保持该区域