test-suites: add a saturated 11-hot-key MSET overwrite spec - #562
fcostaoliveira wants to merge 2 commits into
Conversation
Adds memtier_benchmark-11keys-mset-overwrite-11-pairs-12B-pipeline-10-50_conns: MSET with 11 key/value pairs per command, pipeline 10, 50 connections (-c 25 -t 2), overwriting a hot keyspace of 11 short-named STRING keys with 12-byte EMBSTR values. The existing memtier_benchmark-100keys-mset-overwrite-10B-pipeline-1 covers the same subsystem but cannot measure a per-command cost difference: at -c 1 -t 1 --pipeline 1 the round-trip dominates the throughput, and its p50 lands at 0.031 ms where memtier's three-decimal output makes the smallest expressible step ~3.2% relative. At pipeline 10 over 50 connections p50 is near 1.0 ms, so 0.001 ms is ~0.1% and a few-percent effect is resolvable. Key-name lengths are matched to the report this scopes (redis/redis#15320, a dictFind key-length fast path) rather than normalized: test_MSET1..11 yields nine 10-byte and two 11-byte names. The -c 1 sibling is left in place for history continuity.
|
🤖 Automated first-pass review — a human maintainer's review is still required before merge. This is a single read-only pass over the PR description, the diff, and the sibling specs already in the repo; nothing here was run against memtier or the fleet. The preload's This also quietly breaks the key-length argument, which the description says is load-bearing: at
Separately, not a blocker: the
Thanks for writing the "why, when a sibling already exists" section — the quantization argument is the right framing and I'd like to see this land. Mainly it's the |
… pattern Review follow-up: - Client sizing. -c 25 -t 2 / cpus 3 concentrated ~430k ops/sec on two memtier threads, and every other _conns spec in the suite spreads across 8-10 threads with cpus equal to the thread count. If the load generator clips first, a server-side delta is masked on both sides -- the same false-negative failure mode as -c 1, reached from the client side. Now -c 5 -t 10 / cpus 10, which keeps 50 connections exactly. - Key pattern R -> P. The report writes all 11 distinct keys per command. With R drawing with replacement from 11 keys, expected distinct per command is ~7.1, so the per-command key-length mix only holds in expectation and the varying distinct-lookup count adds spread to the p50 this spec exists to resolve finely. - Documented why --key-maximum equals the key count rather than N+1: the N+1 preloads elsewhere use -n allkeys, where the count is derived and stops one short. With an explicit -n the bound is inclusive, as the merged bitop spec (--key-maximum 10, -n 10, keyspacelen 10) demonstrates on the fleet. - Softened the p50 claim: at 500 outstanding requests p50 is largely queueing delay, so it tracks throughput rather than per-command service time and is not interchangeable with the -c 1 p50.
|
Thanks — the client-thread point was the important one and I've applied it here, plus to the already-merged sibling in #564. Client sizing: agreed, changed. Now |
|
On the two 562-specific points: Key pattern
The empirical check you asked for already exists, on the merged On the p50 framing: fair, and softened. You're right that at 500 outstanding requests p50 is largely queueing delay against a single-threaded server, so it tracks throughput more than per-command service time. The spec now says so explicitly and warns against reading it as interchangeable with the |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2ed4713. Configure here.
| clientconfig: | ||
| run_image: redislabs/memtier_benchmark:edge | ||
| tool: memtier_benchmark | ||
| arguments: --command="MSET __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__ __key__ __data__" --command-key-pattern=P --key-prefix "test_MSET" --key-minimum 1 --key-maximum 11 --data-size 12 --hide-histogram --test-time 180 --pipeline 10 -c 5 -t 10 |
There was a problem hiding this comment.
P pattern partitions hot keyspace
High Severity
The benchmark uses --command-key-pattern=P with 50 clients over keys 1–11. Memtier’s P pattern splits that range across clients, so most connections generate keys outside the preloaded set and each MSET repeats a single key. The dict grows, the L1/L2-hot 11-key overwrite path is lost, and p50 no longer measures the dictFind workload this spec claims to capture. The 100-key sibling uses R on the benchmark phase for this reason.
Reviewed by Cursor Bugbot for commit 2ed4713. Configure here.
| resources: | ||
| requests: | ||
| cpus: '10' | ||
| memory: 2g |
There was a problem hiding this comment.
Client topology mismatches documented design
Medium Severity
clientconfig runs -c 5 -t 10 with cpus: '10', while the spec text states -c 25 -t 2 and the saturation-trap rationale calls for cpus: '3'. The fleet will record p50 under a 10-thread load-generator shape, not the 2-thread topology this spec documents and was designed around to avoid the #485/#486/#487 client-bound trap.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 2ed4713. Configure here.


Adds
memtier_benchmark-11keys-mset-overwrite-11-pairs-12B-pipeline-10-50_conns.What it runs
MSETwith 11 key/value pairs per command,--pipeline 10over 50 client connections(
-c 25 -t 2), repeatedly overwriting a hot keyspace of 11 short-named STRING keys holding12-byte EMBSTR values. Metric of interest is p50 latency (lower is better).
Why, when a 100-key MSET overwrite spec already exists
memtier_benchmark-100keys-mset-overwrite-10B-pipeline-1covers the same subsystem, but it is-c 1 -t 1 --pipeline 1with 3 pairs per command, and it cannot answer a per-command-costquestion. Two independent reasons, both of which I hit in practice:
round-trip time sets the throughput and a few-percent change in the command path is diluted
below run-to-run noise.
decimals, so the next representable value is 0.032 — roughly a 3.2% step. An effect smaller
than one step cannot be expressed at all, and "p50 identical on both sides" is then
quantization, not evidence of no change. At pipeline 10 over 50 connections p50 sits near
1.0 ms, where 0.001 ms is about 0.1%.
I ran the
-c 1spec against a reported MSET p50 regression and read its flat result as "noregression." That was the wrong conclusion from a measurement that could not have shown one.
Key length is deliberate
This scopes redis/redis#15320, which concerns a
dictFindkey-length fast path, so key-namelengths are matched to the report rather than normalized:
test_MSET1..test_MSET11gives nine10-byte names and two 11-byte names, against the report's ten 10-byte and one 11-byte. Using a
uniform-length prefix here would risk tuning out the very path under test.
The 11-key keyspace keeps the main dict and every key object resident in L1/L2 with no
rehashing and effectively no collisions, so
dictFindis cache-latency dominated — unlike the1M–10M distinct-key MSET load specs, which are DRAM-latency dominated and cannot show a
key-comparison difference.
cpus: '3'for-t 2keeps the client clear of the saturation trap seen in #485/#486/#487.The
-c 1sibling is left in place for history continuity.Not yet run on the fleet
This spec has not run on the fleet yet — the preload block follows the same
--key-prefix/--key-minimum/--key-maximumpattern as the merged 100-key sibling, andcheck: keyspacelen: 11will fail the run rather than report a wrong number if it lands short.Note
Low Risk
Adds only a new benchmark YAML definition; no runtime, auth, or application logic changes.
Overview
Adds a new Redis benchmark suite
memtier_benchmark-11keys-mset-overwrite-11-pairs-12B-pipeline-10-50_connsso fleet runs can measure MSET per-command cost on a saturated, 11-key hot overwrite workload with p50 latency as the primary metric.Compared to the existing low-concurrency
100keys-mset-overwrite-10B-pipeline-1spec, this one uses pipeline 10 and 50 client connections so the server stays busy and p50 sits around ~1 ms (finer memtier quantization than ~0.031 ms). The preload and workload usetest_MSET1..11with a deliberate mix of 10- and 11-byte key names to align with redis/redis#15320 (dictFindkey-length fast path), andkeyspacelen: 11guards dataset shape. Standalone OSS, gcc bookworm amd64/arm64, and dockerhub build variants are included at priority 69.Reviewed by Cursor Bugbot for commit 2ed4713. Bugbot is set up for automated code reviews on this repo. Configure here.