SlideShare a Scribd company logo
which you
always wanted
LOAD TESTING
by @antyadev
@antyadev
• Document size ~15Kb
• 6K sport events available for betting
• 73K markets (categories of bets)
• 500K selections (positions to win an event)
• Up to 1M incoming events per minute consumed by one
process
• 8500 outgoing events per second
• 10TB of streaming data per day
Sports Data
API
Agenda
- The real need of load testing
- Load testing basics
- Current state of load testing on 2019
- NBomber – your drug to load testing
Do you know
how many
concurrent requests
your service
can handle?
The real need of Load Testing
- Choose technology stack
- Prove architecture design (POC)
- System regression (CI/CD pipeline)
- Explore system limits
Load Testing basics
- in many cases, you don’t need a cluster
- make sure that targeting node is fully loaded (100% CPU) to
get max RPS
- make sure that you have long running tests
- make sure that you have controllability (your test
input/output should be consistent)
Current state
of
Load Testing
Load Testing
is not easy
Current state of Load Testing
- Easy to cover HTTP only systems
- Hard to cover any other Pull/Push systems
- Complicated and not flexible API
- Limited cluster support (different
workloads)
Current state of Load Testing
- Easy to cover HTTP only systems
- Hard to cover any other Pull/Push systems
- Complicated and not flexible API
- Limited cluster support
Batch Update Process 1
Batch Update Process 3
MongoDB
Batch Update Process 2
insert
read
read
Producer
KAFKA
ETL
KAFKA
No SQL
1 2
34
WebSockets
API
What about
1 Million
connections???
WebSockets
Users
API
WebSockets
Payments
API
WebSockets
Orders
API
Combine to one connection
let start = getCurrentTimer()
execFunc()
let end = getCurrentTimer()
let latency = end - start
let start = getCurrentTimer()
sendHttpReqeust()
let end = getCurrentTimer()
let latency = end - start
let start = getCurrentTimer()
queryMongoDb()
let end = getCurrentTimer()
let latency = end - start
let start = getCurrentTimer()
publishToKafka()
let end = getCurrentTimer()
let latency = end - start
let start = getCurrentTimer()
let! response = websockets.ReceivePush()
let end = getCurrentTimer()
let latency = end - start
Load test any system
https://nbomber.com
PM> Install-Package NBomber
Why another {x} framework for load testing?
The main reasons are:
- To be technology agnostic as much as possible (no dependency on any protocol:
HTTP, WebSockets, SSE etc).
- To be able to test .NET implementation of specific driver. During testing, it was
identified many times that the performance could be slightly different because of
the virtual machine(.NET, Java, PHP, Js, Erlang, different settings for GC) or just
quality of drivers. For example there were cases that drivers written in C++ and
invoked from NodeJs app worked faster than drivers written in C#/.NET. Therefore,
it does make sense to load test your app using your concrete driver and runtime.
- Technology agnostic
(no dependency on HTTP, WebSockets, SSE)
- Very simple API
(to test Pull and Push scenarios)
- CI/CD integration
Pull and Push
Scenarios
xUnit/NUnit
integration
Sequential flow
ReportingDistributed clusterPlugins
Features
type Scenario = {
ScenarioName: string
TestInit: (unit -> Task) option
TestClean: (unit -> Task) option
Steps: Step[] // these steps will be executed sequentially
Assertions: Assertion[]
ConcurrentCopies: int
WarmupDuration: TimeSpan
Duration: TimeSpan
}
type Step = {
StepName: string
Execute: Request -> Task<Response>
}
Very simple API
Very simple API
Step.Create("step", () => {...})
ScenarioBuilder
.CreateScenario("scenario", step1, step2)
.WithConcurrentCopies(10)
.WithDuration(TimeSpan.FromSeconds(60))
NBomberRunner.RegisterScenarios(scenario)
.RunInConsole();
Step.create("step", fun () -> {...})
Scenario.create("scenario", [step1; step2])
|> Scenario.withConcurrentCopies(10)
|> Scenario.withDuration(TimeSpan.FromSeconds(60))
NBomberRunner.registerScenario(scenario)
|> NBomberRunner.runInConsole
Step 1
Scenario
while true
{
}
Scenario
Step 2Step 1
}
while true
{
Scenario
Step 3Step 1 Step 2
}
while true
{
var scenario = ScenarioBuilder
.CreateScenario("Hello World from NBomber!", step)
.WithConcurrentCopies(10)
.WithDuration(TimeSpan.FromSeconds(10));
var step = Step.Create("simple step", pool, async context => {
// you can do any logic here: go to http, websocket etc
await Task.Delay(TimeSpan.FromSeconds(0.1));
return Response.Ok();
});
NBomberRunner.RegisterScenarios(scenario)
.RunInConsole();
let step = Step.create("simple step", pool, fun context -> task {
// you can do any logic here: go to http, websocket etc
do! Task.Delay(TimeSpan.FromSeconds(0.1))
return Response.Ok()
})
Scenario.create("Hello World from NBomber!", [step])
|> Scenario.withConcurrentCopies(10)
|> Scenario.withDuration(TimeSpan.FromSeconds(10.0))
|> NBomberRunner.registerScenario
|> NBomberRunner.runInConsole
Scenario withConcurrentCopies 2
Scenario withConcurrentCopies 2
Task<T>
Task<T>
Step 2Step 1
Step 2Step 1
var client = new HttpClient();
var step1 = Step.Create("GET html", ConnectionPool.None, async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://nbomber.com");
var response = await client.SendAsync(request);
return response.IsSuccessStatusCode
? Response.Ok()
: Response.Fail();
});
var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1);
NBomberRunner.RegisterScenarios(scenario)
.RunInConsole();
Http example
Assertions[Test]
public void Test()
{
var assertions = new[] {
Assertion.ForStep("simple step", stats => stats.OkCount > 2),
Assertion.ForStep("simple step", stats => stats.RPS > 8),
Assertion.ForStep("simple step", stats => stats.Min > 8),
Assertion.ForStep("simple step", stats => stats.Max > 8),
Assertion.ForStep("simple step", stats => stats.Percent95 >= 102),
Assertion.ForStep("simple step", stats => stats.DataMinKb == 1.0),
Assertion.ForStep("simple step", stats => stats.AllDataMB >= 0.01)
};
var scenario = BuildScenario()
.WithConcurrentCopies(1)
.WithWarmUpDuration(TimeSpan.FromSeconds(0))
.WithDuration(TimeSpan.FromSeconds(2))
.WithAssertions(assertions);
NBomberRunner.RegisterScenarios(scenario)
.RunTest();
}
.Http
https://nbomber.com
PM> Install-Package NBomber.Http
var client = new HttpClient();
var step1 = Step.Create("GET html", ConnectionPool.None, async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://nbomber.com");
var response = await client.SendAsync(request);
return response.IsSuccessStatusCode
? Response.Ok()
: Response.Fail();
});
var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1);
NBomberRunner.RegisterScenarios(scenario)
.RunInConsole();
Http example
var step1 = HttpStep.CreateRequest("GET", "https://nbomber.com")
.WithHeader("accept", "application/json")
.WithBody(new StringContent("{ some json }"))
.BuildStep("GET html");
var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1);
NBomberRunner.RegisterScenarios(scenario)
.RunInConsole();
Nbomber.Http
let step1 = HttpStep.createRequest("GET", "https://nbomber.com")
|> HttpStep.withHeader("accept", "application/json")
|> HttpStep.withBody(StringContent("{ some json }"))
|> HttpStep.build("GET html")
Scenario.create("test_nbomber", [step1])
|> NBomberRunner.registerScenario
|> NBomberRunner.runInConsole
Nbomber.Http
Advanced
Example
Batch Update Process 1
Batch Update Process 3
MongoDB
Batch Update Process 2
write
read
read
var insertStep = Step.Create("insert", ConnectionPool.None, async context =>
{
await mongoCollection.InsertManyAsync { ... };
});
var pause_200 = Step.Create("pause 200", ConnectionPool.None, async context =>
{
await Task.Delay(TimeSpan.FromMilliseconds(200));
});
var readStep = HttpStep.CreateRequest("GET", "https://somehost")
.BuildStep("GET TOP 100 events");
// insert scenario: batch insert per 200 ms
var insertScenario = ScenarioBuilder.CreateScenario("mongo", insertStep, pause_200);
// read scenario: in parallel, we want to read data
var readScenario = ScenarioBuilder.CreateScenario("http", readStep);
NBomberRunner.RegisterScenarios(insertScenario, readScenario)
.RunInConsole();
The Kids
want cluster
Agent
Agent
Coordinator
MongoDB
read
write
read
Test
Scenarios.fs
Compile
Test
Scenarios.EXE
Upload
Test
Scenarios.EXE
config
Test
Scenarios.EXE
config
Test
Scenarios.EXE
config
Test
Scenarios.EXE
config
Test
Scenarios.EXE
coordinator_config
Test
Scenarios.EXE
agent_config
Test
Scenarios.EXE
coordinator_config
Test
Scenarios.EXE
agent_config
Test
Scenarios.EXE
agent_config
{
"ClusterSettings": {
"Agent": {
"ClusterId": "test_cluster",
"Port": 4000
}
}
}
Agent
Agent
Agent Config
Coordinator
Config
{
"GlobalSettings": {
"ScenariosSettings": [
{
"ScenarioName": "read",
"Duration": "00:00:10",
"ConcurrentCopies": 200
}
]
},
"ClusterSettings": {
"Coordinator": {
"ClusterId": "test_cluster",
"TargetScenarios": [ "insert" ]
"Agents": [
{
"Host": "35.187.178.41",
"Port": 4000
"TargetScenarios": [ "read" ]
}
]
},
}
} Coordinator
The Kids
want PUSH
var url = "ws://localhost:53231";
var webSocketsPool = ConnectionPool.Create("webSocketsPool", openConnection: () =>
{
var ws = new ClientWebSocket();
ws.ConnectAsync(new Uri(url), CancellationToken.None).Wait();
return ws;
});
var pingStep = Step.Create("ping", webSocketsPool, async context =>
{
var msg = new WebSocketRequest
{
CorrelationId = context.CorrelationId,
RequestType = RequestType.Ping
};
await context.Connection.SendAsync(msg, WebSocketMessageType.Text);
return Response.Ok();
});
var pingStep = Step.Create("ping", webSocketsPool, async context =>
{
var msg = new WebSocketRequest
{
CorrelationId = context.CorrelationId,
RequestType = RequestType.Ping
};
await context.Connection.SendAsync(msg, WebSocketMessageType.Text);
return Response.Ok();
});
var pongStep = Step.Create("pong", webSocketsPool, async context =>
{
while (true)
{
var message = await context.Connection.ReceiveMessage();
if (msg.CorrelationId == context.CorrelationId)
{
return Response.Ok(msg);
}
}
});
Internals
NBomber
Runner
let run (dep: Dependency, context: NBomberContext) =
asyncResult {
let! ctx = Validation.validateContext(context)
let! nodeStats =
NBomberContext.tryGetClusterSettings(ctx)
|> Option.map(function
| Coordinator c -> runClusterCoordinator(dep, ctx, c)
| Agent a -> runClusterAgent(dep, ctx, a))
|> Option.orElseWith(fun _ -> runSingleNode(dep, ctx))
|> Option.get
return nodeStats
|> calcStatistics(dep, ctx)
|> saveStatistics(ctx)
|> applyAsserts(ctx)
|> buildReport(dep)
|> saveReport(dep, ctx)
}
|> AsyncResult.mapError(handleError(dep))
|> Async.RunSynchronously
|> ignore
Validation
type Result<TOk, TError> =
<!>
<*>
>>=
>=>
module ScenarioValidation =
let validate (context: NBomberContext) =
context.Scenarios
|> checkEmptyName
>>= checkDuplicateName
>>= checkEmptyStepName
>>= checkDuplicateStepName
>>= checkDuration
>>= checkConcurrentCopies
>>= fun _ -> Ok context
module GlobalSettingsValidation =
let validate (context: NBomberContext) =
context.NBomberConfig
|> Option.bind(fun x -> x.GlobalSettings)
|> Option.map(fun glSettings ->
glSettings
|> checkEmptyTarget
>>= checkAvailableTarget
>>= checkDuration
>>= checkConcurrentCopies
>>= checkEmptyReportName
>>= fun _ -> Ok context
)
|> Option.defaultValue(Ok context)
module ScenarioValidation =
let validate (context) = ...
module GlobalSettingsValidation =
let validate (context) = ...
module Validation =
let validate =
ScenarioValidation.validate >=> GlobalSettingsValidation.validate
Type Safe
Cluster
(>>=)
type IClusterCoordinator =
abstract StartNewSession: ScenarioSetting[] -> Task<Result<unit,Error>>
abstract WaitOnAllAgentsReady: unit -> Task<Result<unit,Error>>
abstract StartWarmUp: unit -> Task<Result<unit,Error>>
abstract StartBombing: unit -> Task<Result<unit,Error>>
abstract GetStatistics: unit -> Task<Result<NodeStats[],Error>>
let runCoordinator (cluster: IClusterCoordinator, localHost: IScenariosHost,
settings: ScenarioSetting[], targetScns: string[]) =
asyncResult {
do! cluster.SendStartNewSession(settings)
do! localHost.InitScenarios(settings, targetScns)
do! cluster.WaitOnAllAgentsReady()
do! cluster.SendStartWarmUp()
do! localHost.WarmUpScenarios()
do! cluster.WaitOnAllAgentsReady()
do! cluster.SendStartBombing() // Task<Result<unit,Error>>
do! localHost.StartBombing()
do! cluster.WaitOnAllAgentsReady()
let localStats = localHost.GetStatistics()
let! agentsStats = cluster.GetStatistics()
let allStats = Array.append [|localStats|] agentsStats
localHost.StopScenarios()
return allStats
}
- (2663) LOC
- (6) OOP objects
- (~160) functions
Summary
COORDINATED
OMISSION
GC pause
????
API
THANKS
@antyadev
antyadev@gmail.com
http://nbomber.com

More Related Content

What's hot

Altitude NY 2018: Programming the edge workshop
Altitude NY 2018: Programming the edge workshopAltitude NY 2018: Programming the edge workshop
Altitude NY 2018: Programming the edge workshop
Fastly
 
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, EverAltitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Fastly
 
Reactive Fault Tolerant Programming with Hystrix and RxJava
Reactive Fault Tolerant Programming with Hystrix and RxJavaReactive Fault Tolerant Programming with Hystrix and RxJava
Reactive Fault Tolerant Programming with Hystrix and RxJava
Matt Stine
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
Bartosz Sypytkowski
 
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic ContentCaching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
Fastly
 
How NOT to write in Node.js
How NOT to write in Node.jsHow NOT to write in Node.js
How NOT to write in Node.js
Piotr Pelczar
 
What's new in Ansible 2.0
What's new in Ansible 2.0What's new in Ansible 2.0
What's new in Ansible 2.0
Allan Denot
 
Run Node Run
Run Node RunRun Node Run
Run Node Run
Kevin Swiber
 
Design & Performance - Steve Souders at Fastly Altitude 2015
Design & Performance - Steve Souders at Fastly Altitude 2015Design & Performance - Steve Souders at Fastly Altitude 2015
Design & Performance - Steve Souders at Fastly Altitude 2015
Fastly
 
PyCon AU 2015 - Using benchmarks to understand how wsgi servers work
PyCon AU 2015  - Using benchmarks to understand how wsgi servers workPyCon AU 2015  - Using benchmarks to understand how wsgi servers work
PyCon AU 2015 - Using benchmarks to understand how wsgi servers work
Graham Dumpleton
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streams
Bartosz Sypytkowski
 
How to tune Kafka® for production
How to tune Kafka® for productionHow to tune Kafka® for production
How to tune Kafka® for production
confluent
 
Prometheus Everything, Observing Kubernetes in the Cloud
Prometheus Everything, Observing Kubernetes in the CloudPrometheus Everything, Observing Kubernetes in the Cloud
Prometheus Everything, Observing Kubernetes in the Cloud
Sneha Inguva
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
 
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
Big Data Spain
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
Paweł Kowalczuk
 
Trisha gee concurrentprogrammingusingthedisruptor
Trisha gee concurrentprogrammingusingthedisruptorTrisha gee concurrentprogrammingusingthedisruptor
Trisha gee concurrentprogrammingusingthedisruptorEthanTu
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
Fastly
 
Leveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack SwiftLeveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack Swift
Dmitry Sotnikov
 
Consul - service discovery and others
Consul - service discovery and othersConsul - service discovery and others
Consul - service discovery and others
Walter Liu
 

What's hot (20)

Altitude NY 2018: Programming the edge workshop
Altitude NY 2018: Programming the edge workshopAltitude NY 2018: Programming the edge workshop
Altitude NY 2018: Programming the edge workshop
 
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, EverAltitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
 
Reactive Fault Tolerant Programming with Hystrix and RxJava
Reactive Fault Tolerant Programming with Hystrix and RxJavaReactive Fault Tolerant Programming with Hystrix and RxJava
Reactive Fault Tolerant Programming with Hystrix and RxJava
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
 
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic ContentCaching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
Caching the Uncacheable: Leveraging Your CDN to Cache Dynamic Content
 
How NOT to write in Node.js
How NOT to write in Node.jsHow NOT to write in Node.js
How NOT to write in Node.js
 
What's new in Ansible 2.0
What's new in Ansible 2.0What's new in Ansible 2.0
What's new in Ansible 2.0
 
Run Node Run
Run Node RunRun Node Run
Run Node Run
 
Design & Performance - Steve Souders at Fastly Altitude 2015
Design & Performance - Steve Souders at Fastly Altitude 2015Design & Performance - Steve Souders at Fastly Altitude 2015
Design & Performance - Steve Souders at Fastly Altitude 2015
 
PyCon AU 2015 - Using benchmarks to understand how wsgi servers work
PyCon AU 2015  - Using benchmarks to understand how wsgi servers workPyCon AU 2015  - Using benchmarks to understand how wsgi servers work
PyCon AU 2015 - Using benchmarks to understand how wsgi servers work
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streams
 
How to tune Kafka® for production
How to tune Kafka® for productionHow to tune Kafka® for production
How to tune Kafka® for production
 
Prometheus Everything, Observing Kubernetes in the Cloud
Prometheus Everything, Observing Kubernetes in the CloudPrometheus Everything, Observing Kubernetes in the Cloud
Prometheus Everything, Observing Kubernetes in the Cloud
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
Apache MXNet Distributed Training Explained In Depth by Viacheslav Kovalevsky...
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Trisha gee concurrentprogrammingusingthedisruptor
Trisha gee concurrentprogrammingusingthedisruptorTrisha gee concurrentprogrammingusingthedisruptor
Trisha gee concurrentprogrammingusingthedisruptor
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
Leveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack SwiftLeveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack Swift
 
Consul - service discovery and others
Consul - service discovery and othersConsul - service discovery and others
Consul - service discovery and others
 

Similar to Anton Moldovan "Load testing which you always wanted"

"Load Testing Distributed Systems with NBomber 4.0", Anton Moldovan
"Load Testing Distributed Systems with NBomber 4.0",  Anton Moldovan"Load Testing Distributed Systems with NBomber 4.0",  Anton Moldovan
"Load Testing Distributed Systems with NBomber 4.0", Anton Moldovan
Fwdays
 
Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19
confluent
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
Oleg Podsechin
 
Azure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best PracticesAzure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best Practices
Jose Manuel Jurado Diaz
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
Gianluca Carucci
 
Tdd iPhone For Dummies
Tdd iPhone For DummiesTdd iPhone For Dummies
Tdd iPhone For Dummies
Giordano Scalzo
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
Frank Lyaruu
 
What the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startupWhat the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startup
Gerrit Grunwald
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
Aravindharamanan S
 
MongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-es
MongoDB
 
Load Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systemsLoad Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systems
Jason Lotito
 
RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message Queue
Gleicon Moraes
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
Mike Hagedorn
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
Vadym Khondar
 
Introduction of server sent events (sse)
Introduction of server sent events (sse)Introduction of server sent events (sse)
Introduction of server sent events (sse)
Yuji KONDO
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio
 
Async programming on NET
Async programming on NETAsync programming on NET
Async programming on NET
yuyijq
 
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
tamtam180
 

Similar to Anton Moldovan "Load testing which you always wanted" (20)

"Load Testing Distributed Systems with NBomber 4.0", Anton Moldovan
"Load Testing Distributed Systems with NBomber 4.0",  Anton Moldovan"Load Testing Distributed Systems with NBomber 4.0",  Anton Moldovan
"Load Testing Distributed Systems with NBomber 4.0", Anton Moldovan
 
Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
 
Azure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best PracticesAzure SQL Database - Connectivity Best Practices
Azure SQL Database - Connectivity Best Practices
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Tdd iPhone For Dummies
Tdd iPhone For DummiesTdd iPhone For Dummies
Tdd iPhone For Dummies
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
 
What the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startupWhat the CRaC - Superfast JVM startup
What the CRaC - Superfast JVM startup
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
MongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-es
 
Load Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systemsLoad Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systems
 
RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message Queue
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Introduction of server sent events (sse)
Introduction of server sent events (sse)Introduction of server sent events (sse)
Introduction of server sent events (sse)
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
 
Async programming on NET
Async programming on NETAsync programming on NET
Async programming on NET
 
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
 

More from Fwdays

"What I learned through reverse engineering", Yuri Artiukh
"What I learned through reverse engineering", Yuri Artiukh"What I learned through reverse engineering", Yuri Artiukh
"What I learned through reverse engineering", Yuri Artiukh
Fwdays
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
Fwdays
 
"Micro frontends: Unbelievably true life story", Dmytro Pavlov
"Micro frontends: Unbelievably true life story", Dmytro Pavlov"Micro frontends: Unbelievably true life story", Dmytro Pavlov
"Micro frontends: Unbelievably true life story", Dmytro Pavlov
Fwdays
 
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
Fwdays
 
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
Fwdays
 
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
Fwdays
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
Fwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
Fwdays
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
Fwdays
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets
Fwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
Fwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
Fwdays
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
Fwdays
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
Fwdays
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...
Fwdays
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
Fwdays
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
Fwdays
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
Fwdays
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
Fwdays
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
Fwdays
 

More from Fwdays (20)

"What I learned through reverse engineering", Yuri Artiukh
"What I learned through reverse engineering", Yuri Artiukh"What I learned through reverse engineering", Yuri Artiukh
"What I learned through reverse engineering", Yuri Artiukh
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
"Micro frontends: Unbelievably true life story", Dmytro Pavlov
"Micro frontends: Unbelievably true life story", Dmytro Pavlov"Micro frontends: Unbelievably true life story", Dmytro Pavlov
"Micro frontends: Unbelievably true life story", Dmytro Pavlov
 
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
"Objects validation and comparison using runtime types (io-ts)", Oleksandr Suhak
 
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
"JavaScript. Standard evolution, when nobody cares", Roman Savitskyi
 
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
 

Recently uploaded

LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 

Recently uploaded (20)

LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 

Anton Moldovan "Load testing which you always wanted"

  • 1. which you always wanted LOAD TESTING by @antyadev
  • 3.
  • 4.
  • 5. • Document size ~15Kb • 6K sport events available for betting • 73K markets (categories of bets) • 500K selections (positions to win an event) • Up to 1M incoming events per minute consumed by one process • 8500 outgoing events per second • 10TB of streaming data per day
  • 7. Agenda - The real need of load testing - Load testing basics - Current state of load testing on 2019 - NBomber – your drug to load testing
  • 8. Do you know how many concurrent requests your service can handle?
  • 9. The real need of Load Testing - Choose technology stack - Prove architecture design (POC) - System regression (CI/CD pipeline) - Explore system limits
  • 10. Load Testing basics - in many cases, you don’t need a cluster - make sure that targeting node is fully loaded (100% CPU) to get max RPS - make sure that you have long running tests - make sure that you have controllability (your test input/output should be consistent)
  • 13. Current state of Load Testing - Easy to cover HTTP only systems - Hard to cover any other Pull/Push systems - Complicated and not flexible API - Limited cluster support (different workloads)
  • 14. Current state of Load Testing - Easy to cover HTTP only systems - Hard to cover any other Pull/Push systems - Complicated and not flexible API - Limited cluster support
  • 15. Batch Update Process 1 Batch Update Process 3 MongoDB Batch Update Process 2 insert read read
  • 18.
  • 21. let start = getCurrentTimer() execFunc() let end = getCurrentTimer() let latency = end - start
  • 22. let start = getCurrentTimer() sendHttpReqeust() let end = getCurrentTimer() let latency = end - start
  • 23. let start = getCurrentTimer() queryMongoDb() let end = getCurrentTimer() let latency = end - start
  • 24. let start = getCurrentTimer() publishToKafka() let end = getCurrentTimer() let latency = end - start
  • 25. let start = getCurrentTimer() let! response = websockets.ReceivePush() let end = getCurrentTimer() let latency = end - start
  • 26. Load test any system https://nbomber.com PM> Install-Package NBomber
  • 27. Why another {x} framework for load testing? The main reasons are: - To be technology agnostic as much as possible (no dependency on any protocol: HTTP, WebSockets, SSE etc). - To be able to test .NET implementation of specific driver. During testing, it was identified many times that the performance could be slightly different because of the virtual machine(.NET, Java, PHP, Js, Erlang, different settings for GC) or just quality of drivers. For example there were cases that drivers written in C++ and invoked from NodeJs app worked faster than drivers written in C#/.NET. Therefore, it does make sense to load test your app using your concrete driver and runtime.
  • 28. - Technology agnostic (no dependency on HTTP, WebSockets, SSE) - Very simple API (to test Pull and Push scenarios) - CI/CD integration
  • 29. Pull and Push Scenarios xUnit/NUnit integration Sequential flow ReportingDistributed clusterPlugins Features
  • 30. type Scenario = { ScenarioName: string TestInit: (unit -> Task) option TestClean: (unit -> Task) option Steps: Step[] // these steps will be executed sequentially Assertions: Assertion[] ConcurrentCopies: int WarmupDuration: TimeSpan Duration: TimeSpan } type Step = { StepName: string Execute: Request -> Task<Response> } Very simple API
  • 31. Very simple API Step.Create("step", () => {...}) ScenarioBuilder .CreateScenario("scenario", step1, step2) .WithConcurrentCopies(10) .WithDuration(TimeSpan.FromSeconds(60)) NBomberRunner.RegisterScenarios(scenario) .RunInConsole(); Step.create("step", fun () -> {...}) Scenario.create("scenario", [step1; step2]) |> Scenario.withConcurrentCopies(10) |> Scenario.withDuration(TimeSpan.FromSeconds(60)) NBomberRunner.registerScenario(scenario) |> NBomberRunner.runInConsole
  • 34. Scenario Step 3Step 1 Step 2 } while true {
  • 35. var scenario = ScenarioBuilder .CreateScenario("Hello World from NBomber!", step) .WithConcurrentCopies(10) .WithDuration(TimeSpan.FromSeconds(10)); var step = Step.Create("simple step", pool, async context => { // you can do any logic here: go to http, websocket etc await Task.Delay(TimeSpan.FromSeconds(0.1)); return Response.Ok(); }); NBomberRunner.RegisterScenarios(scenario) .RunInConsole();
  • 36. let step = Step.create("simple step", pool, fun context -> task { // you can do any logic here: go to http, websocket etc do! Task.Delay(TimeSpan.FromSeconds(0.1)) return Response.Ok() }) Scenario.create("Hello World from NBomber!", [step]) |> Scenario.withConcurrentCopies(10) |> Scenario.withDuration(TimeSpan.FromSeconds(10.0)) |> NBomberRunner.registerScenario |> NBomberRunner.runInConsole
  • 39. var client = new HttpClient(); var step1 = Step.Create("GET html", ConnectionPool.None, async context => { var request = new HttpRequestMessage(HttpMethod.Get, "https://nbomber.com"); var response = await client.SendAsync(request); return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail(); }); var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1); NBomberRunner.RegisterScenarios(scenario) .RunInConsole(); Http example
  • 40. Assertions[Test] public void Test() { var assertions = new[] { Assertion.ForStep("simple step", stats => stats.OkCount > 2), Assertion.ForStep("simple step", stats => stats.RPS > 8), Assertion.ForStep("simple step", stats => stats.Min > 8), Assertion.ForStep("simple step", stats => stats.Max > 8), Assertion.ForStep("simple step", stats => stats.Percent95 >= 102), Assertion.ForStep("simple step", stats => stats.DataMinKb == 1.0), Assertion.ForStep("simple step", stats => stats.AllDataMB >= 0.01) }; var scenario = BuildScenario() .WithConcurrentCopies(1) .WithWarmUpDuration(TimeSpan.FromSeconds(0)) .WithDuration(TimeSpan.FromSeconds(2)) .WithAssertions(assertions); NBomberRunner.RegisterScenarios(scenario) .RunTest(); }
  • 42. var client = new HttpClient(); var step1 = Step.Create("GET html", ConnectionPool.None, async context => { var request = new HttpRequestMessage(HttpMethod.Get, "https://nbomber.com"); var response = await client.SendAsync(request); return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail(); }); var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1); NBomberRunner.RegisterScenarios(scenario) .RunInConsole(); Http example
  • 43. var step1 = HttpStep.CreateRequest("GET", "https://nbomber.com") .WithHeader("accept", "application/json") .WithBody(new StringContent("{ some json }")) .BuildStep("GET html"); var scenario = ScenarioBuilder.CreateScenario("test_nbomber", step1); NBomberRunner.RegisterScenarios(scenario) .RunInConsole(); Nbomber.Http
  • 44. let step1 = HttpStep.createRequest("GET", "https://nbomber.com") |> HttpStep.withHeader("accept", "application/json") |> HttpStep.withBody(StringContent("{ some json }")) |> HttpStep.build("GET html") Scenario.create("test_nbomber", [step1]) |> NBomberRunner.registerScenario |> NBomberRunner.runInConsole Nbomber.Http
  • 45.
  • 47. Batch Update Process 1 Batch Update Process 3 MongoDB Batch Update Process 2 write read read
  • 48. var insertStep = Step.Create("insert", ConnectionPool.None, async context => { await mongoCollection.InsertManyAsync { ... }; }); var pause_200 = Step.Create("pause 200", ConnectionPool.None, async context => { await Task.Delay(TimeSpan.FromMilliseconds(200)); }); var readStep = HttpStep.CreateRequest("GET", "https://somehost") .BuildStep("GET TOP 100 events"); // insert scenario: batch insert per 200 ms var insertScenario = ScenarioBuilder.CreateScenario("mongo", insertStep, pause_200); // read scenario: in parallel, we want to read data var readScenario = ScenarioBuilder.CreateScenario("http", readStep); NBomberRunner.RegisterScenarios(insertScenario, readScenario) .RunInConsole();
  • 55. { "ClusterSettings": { "Agent": { "ClusterId": "test_cluster", "Port": 4000 } } } Agent Agent Agent Config
  • 56. Coordinator Config { "GlobalSettings": { "ScenariosSettings": [ { "ScenarioName": "read", "Duration": "00:00:10", "ConcurrentCopies": 200 } ] }, "ClusterSettings": { "Coordinator": { "ClusterId": "test_cluster", "TargetScenarios": [ "insert" ] "Agents": [ { "Host": "35.187.178.41", "Port": 4000 "TargetScenarios": [ "read" ] } ] }, } } Coordinator
  • 58. var url = "ws://localhost:53231"; var webSocketsPool = ConnectionPool.Create("webSocketsPool", openConnection: () => { var ws = new ClientWebSocket(); ws.ConnectAsync(new Uri(url), CancellationToken.None).Wait(); return ws; }); var pingStep = Step.Create("ping", webSocketsPool, async context => { var msg = new WebSocketRequest { CorrelationId = context.CorrelationId, RequestType = RequestType.Ping }; await context.Connection.SendAsync(msg, WebSocketMessageType.Text); return Response.Ok(); });
  • 59. var pingStep = Step.Create("ping", webSocketsPool, async context => { var msg = new WebSocketRequest { CorrelationId = context.CorrelationId, RequestType = RequestType.Ping }; await context.Connection.SendAsync(msg, WebSocketMessageType.Text); return Response.Ok(); }); var pongStep = Step.Create("pong", webSocketsPool, async context => { while (true) { var message = await context.Connection.ReceiveMessage(); if (msg.CorrelationId == context.CorrelationId) { return Response.Ok(msg); } } });
  • 62. let run (dep: Dependency, context: NBomberContext) = asyncResult { let! ctx = Validation.validateContext(context) let! nodeStats = NBomberContext.tryGetClusterSettings(ctx) |> Option.map(function | Coordinator c -> runClusterCoordinator(dep, ctx, c) | Agent a -> runClusterAgent(dep, ctx, a)) |> Option.orElseWith(fun _ -> runSingleNode(dep, ctx)) |> Option.get return nodeStats |> calcStatistics(dep, ctx) |> saveStatistics(ctx) |> applyAsserts(ctx) |> buildReport(dep) |> saveReport(dep, ctx) } |> AsyncResult.mapError(handleError(dep)) |> Async.RunSynchronously |> ignore
  • 64. type Result<TOk, TError> = <!> <*> >>= >=>
  • 65. module ScenarioValidation = let validate (context: NBomberContext) = context.Scenarios |> checkEmptyName >>= checkDuplicateName >>= checkEmptyStepName >>= checkDuplicateStepName >>= checkDuration >>= checkConcurrentCopies >>= fun _ -> Ok context
  • 66. module GlobalSettingsValidation = let validate (context: NBomberContext) = context.NBomberConfig |> Option.bind(fun x -> x.GlobalSettings) |> Option.map(fun glSettings -> glSettings |> checkEmptyTarget >>= checkAvailableTarget >>= checkDuration >>= checkConcurrentCopies >>= checkEmptyReportName >>= fun _ -> Ok context ) |> Option.defaultValue(Ok context)
  • 67. module ScenarioValidation = let validate (context) = ... module GlobalSettingsValidation = let validate (context) = ... module Validation = let validate = ScenarioValidation.validate >=> GlobalSettingsValidation.validate
  • 69. type IClusterCoordinator = abstract StartNewSession: ScenarioSetting[] -> Task<Result<unit,Error>> abstract WaitOnAllAgentsReady: unit -> Task<Result<unit,Error>> abstract StartWarmUp: unit -> Task<Result<unit,Error>> abstract StartBombing: unit -> Task<Result<unit,Error>> abstract GetStatistics: unit -> Task<Result<NodeStats[],Error>>
  • 70. let runCoordinator (cluster: IClusterCoordinator, localHost: IScenariosHost, settings: ScenarioSetting[], targetScns: string[]) = asyncResult { do! cluster.SendStartNewSession(settings) do! localHost.InitScenarios(settings, targetScns) do! cluster.WaitOnAllAgentsReady() do! cluster.SendStartWarmUp() do! localHost.WarmUpScenarios() do! cluster.WaitOnAllAgentsReady() do! cluster.SendStartBombing() // Task<Result<unit,Error>> do! localHost.StartBombing() do! cluster.WaitOnAllAgentsReady() let localStats = localHost.GetStatistics() let! agentsStats = cluster.GetStatistics() let allStats = Array.append [|localStats|] agentsStats localHost.StopScenarios() return allStats }
  • 71. - (2663) LOC - (6) OOP objects - (~160) functions Summary
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 79.