Gatling Dubbo Load Testing Plugin: Architecture, DSL, and Implementation Guide
The Gatling‑Dubbo plugin extends Gatling’s high‑performance, event‑driven load‑testing framework with a Dubbo protocol layer, providing protocol, action, and JsonPath‑based check components plus a HTTP‑like DSL, enabling asynchronous generic calls, response validation, throttling, and full example simulations for distributed Dubbo service testing.
Gatling is an open‑source, high‑performance load‑testing framework built on Scala, Akka and Netty. Compared with thread‑based tools, Gatling uses an event‑driven model that consumes fewer resources, allowing a single load‑generator to simulate many virtual users. Youzan extended Gatling with a distributed load‑testing engine (MAXIM) and added a Dubbo load‑testing plugin (gatling‑dubbo) to measure the capacity of Dubbo services.
Plugin Main Structure
The plugin consists of four parts:
Protocol & ProtocolBuild : defines Dubbo client configuration (protocol, generic call flag, service URL, registry protocol and address) and provides a DSL builder.
Action & ActionBuild : sends Dubbo requests asynchronously, validates responses, logs results and forwards to the next action.
Check & CheckBuild : uses JsonPath to verify the response content.
DSL : a domain‑specific language that mirrors Gatling’s HTTP DSL for writing Dubbo scenarios.
Protocol Definition
The protocol is represented by five fields. Example Scala code:
object DubboProtocol {
val DubboProtocolKey = new ProtocolKey {
type Protocol = DubboProtocol
type Components = DubboComponents
}
def protocolClass: Class[io.gatling.core.protocol.Protocol] = classOf[DubboProtocol].asInstanceOf[Class[io.gatling.core.protocol.Protocol]]
def defaultProtocolValue(configuration: GatlingConfiguration): DubboProtocol =
throw new IllegalStateException("Can't provide a default value for DubboProtocol")
def newComponents(system: ActorSystem, coreComponents: CoreComponents): DubboProtocol => DubboComponents = {
dubboProtocol => DubboComponents(dubboProtocol)
}
}
case class DubboProtocol(
protocol: String, // "dubbo"
generic: String, // "true" or "result_no_change"
url: String, // e.g. "dubbo://IP:port"
registryProtocol: String, // e.g. "ETCD3"
registryAddress: String) extends Protocol {
type Components = DubboComponents
}If url is empty, the plugin will use the registry (currently only ETCD3) and perform client‑side load balancing.
Action Implementation
DubboAction extends ExitableAction and executes the request asynchronously so that a virtual user can fire the next request without waiting for the previous response. The response is converted to JSON, checked with the defined Check s, and the result is logged. Throttling is applied when the scenario is marked as throttled.
override def execute(session: Session): Unit = recover(session) {
argTypes(session) flatMap { argTypesArray =>
argValues(session) map { argValuesArray =>
val startTime = System.currentTimeMillis()
val f = Future {
try {
genericService.$invoke(method, argTypes(session).get, argValues(session).get)
} finally {}
}
f.onComplete {
case Success(result) =>
val endTime = System.currentTimeMillis()
val resultMap = result.asInstanceOf[JMap[String, Any]]
val resultJson = objectMapper.writeValueAsString(resultMap)
val (newSession, error) = Check.check(resultJson, session, checks)
error match {
case None =>
statsEngine.logResponse(session, interface + "." + method,
ResponseTimings(startTime, endTime), Status("OK"), None, None)
throttle(newSession(session))
case Some(Failure(errorMessage)) =>
statsEngine.logResponse(session, interface + "." + method,
ResponseTimings(startTime, endTime), Status("KO"), None, Some(errorMessage))
throttle(newSession(session).markAsFailed)
}
case FuFailure(e) =>
val endTime = System.currentTimeMillis()
statsEngine.logResponse(session, interface + "." + method,
ResponseTimings(startTime, endTime), Status("KO"), None, Some(e.getMessage))
throttle(session.markAsFailed)
}
}
}
}Check Using JsonPath
The plugin provides a DubboCheck that works with Gatling’s Check API. It defines a string extender and a preparer that parses the response with either Jackson or Boon depending on size.
type DubboCheck = Check[String]
val DubboStringExtender: Extender[DubboCheck, String] = (check: DubboCheck) => check
val DubboStringPreparer: Preparer[String, String] = (result: String) => Success(result)The DSL offers a jsonPath method to create a DubboJsonPathCheckBuilder which can be further refined with ofType , find , findAll , etc.
def jsonPath(path: Expression[String])(implicit extractorFactory: JsonPathExtractorFactory, jsonParsers: JsonParsers) =
new DubboJsonPathCheckBuilder[String](path, jsonParsers) with DubboJsonPathOfTypeDSL for Building Scenarios
The top‑level trait DubboDsl exposes a Dubbo protocol builder and a dubbo(interface, method) shortcut that returns a DubboProcessBuilder . Implicit conversions turn the builder into a DubboProtocol and an ActionBuilder . Additionally, transformJsonDubboData converts JSON arrays from a feeder into Java JList objects required by the Dubbo generic call.
def transformJsonDubboData(argTypeName: String, argValueName: String, session: Session): Session = {
session
.set(argTypeName, toArray(session(argTypeName).asInstanceOf[JList[String]]))
.set(argValueName, toArray(session(argValueName).asInstanceOf[JList[Any]]))
}Example Load‑Test Script
A complete Gatling simulation using the Dubbo plugin:
import io.gatling.core.Predef._
import io.gatling.dubbo.Predef._
import scala.concurrent.duration._
class DubboTest extends Simulation {
val dubboConfig = Dubbo
.protocol("dubbo")
.generic("true")
.url("dubbo://IP:port") // or use registryProtocol/registryAddress for cluster testing
val jsonFileFeeder = jsonFile("data.json").circular
val dubboScenario = scenario("load test dubbo")
.forever("repeated") {
feed(jsonFileFeeder)
.exec(session => transformJsonDubboData("args_types1", "args_values1", session))
.exec(dubbo("com.xxx.xxxService", "methodName")
.argTypes("${args_types1}")
.argValues("${args_values1}")
.check(jsonPath("$.code").is("200")))
}
setUp(
dubboScenario.inject(atOnceUsers(10))
.throttle(
reachRps(10) in (1 seconds),
holdFor(30 seconds))
).protocols(dubboConfig)
}The accompanying data.json feeder provides argument type and value arrays for the generic Dubbo call.
[
{
"args_types1": ["com.xxx.xxxDTO"],
"args_values1": [{
"field1": "111",
"field2": "222",
"field3": "333"
}]
}
]Recruitment Notice
Youzan’s testing team is hiring. Interested engineers can send their resumes to [email protected] .
Further Reading
Chaos Engineering – The Path to High Availability and Resilience
Two Testing Methods for Asynchronous Systems
Youzan Full‑Link Load Testing Practice
— The End —
Youzan Coder
Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.