Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Advanced BenchmarkDotNet: Parameters, Baselines, Diagnosers, Runtime Comparison and Catching Regressions in CI
Advanced BenchmarkDotNet means defining realistic scenarios with ParamsSource, making the old code the baseline, finding the cause of a difference with the Memory, Exception, Threading and Disassembly diagnosers, and catching regressions by relative, statistical comparison. On Bookstore's pricing code we measure that .NET 11 speeds up the LINQ version by 30-38 percent but not the loop, that 0.15.8 does not know net11.0, and that parsing with try/catch is ten times slower.
Interpreting Results: Percentiles, Coordinated Omission, the Throughput-Latency Curve and Finding the Bottleneck
Reading a load test correctly means looking at percentiles instead of the average, never averaging percentiles, using the open model to avoid coordinated omission, looking for capacity at the knee of the throughput-latency curve and finding the bottleneck with the USE method. We freeze the Bookstore API for 5 seconds and measure a closed-model p99 of 8 ms against an open-model 4.2 seconds, then trace the curve's collapse to the connection pool and SQL Server waits.
JMeter: Where It Is Still the Right Tool, Test Plans, Thread Groups, CLI Mode and the HTML Dashboard
JMeter is still the right tool for broad protocol support such as JDBC, JMS and LDAP, for existing test plans and for test teams that do not write code; for an HTTP API k6 fits better. We build the Bookstore scenario in JMeter 5.6.3 with an Open Model Thread Group, CSV Data Set, JSON Extractor and timers, run it in CLI mode, read the HTML dashboard and show traps such as timer scope, APDEX thresholds and the exit code.
Putting k6 Into the Process: Performance Gates in CI, OpenTelemetry Output, Distributed Tests and Browser Scenarios
Putting k6 into the process means running a short performance gate on PRs and a full load test every night, sending metrics next to application telemetry with OpenTelemetry, splitting large loads across pods with the k6 Operator and measuring what the user sees with the browser module. We show Bookstore's GitHub Actions workflow, the metrics arriving at the Collector, a two-runner distributed test and the trap of k6 archive freezing options, all with real runs.
Load Testing with k6: Scripts, Scenarios, Arrival-Rate Executors, Checks, Thresholds and expect()
A realistic load test with k6 2.x is built from one arrival-rate scenario per user flow, a VU count computed with Little's Law, per-endpoint thresholds, fail-fast expect() calls in setup() and a JSON summary. We run a TypeScript script against Bookstore and read the output line by line, show how abortOnFail interrupts the test when the database goes away, and how p95 grows nine times when k6 gets a single core.
Workload Modeling and Test Data: Realistic Traffic Mix, Think Time, Cache State and Faking Dependencies
A realistic load test measures the traffic mix from the access log, separates session percentages from request percentages, uses random think time and runs with production-sized and production-shaped data, a deliberately chosen cache state and stubbed dependencies. With real runs on Bookstore we show that a test always asking for the same book sent only 41 queries to the database in a minute, and that a zero-delay payment stub made orders look twenty times faster.
Types of Performance Testing and Goals: Load, Stress, Spike, Soak, Breakpoint and From SLO to Acceptance Criteria
Each performance test type answers its own question: smoke shows the script works, average load the normal day, stress the peak, spike a sudden jump, soak what happens after hours and breakpoint the capacity limit. We derive acceptance criteria from an SLO as load, duration and limits, compute virtual users with Little's Law and show with real k6 runs on Bookstore how a closed model reduces load on its own and hides the problem when the system slows down.