blob: 7cb33b6e4d513c475f53115a752d53a0e3a8d212 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
const EXAMPLES: &str = r"EXAMPLES:
Start iggy-server separately. The benchmark connects to a running server.
Global options precede the kind, kind options precede the transport, and
transport options precede the optional output subcommand.
Default producer and consumer counts are six. Pinned workloads default to six streams.
1) All benchmark kinds and aliases:
Pinned producer (pp), consumer (pc), and producer/consumer (ppc):
$ cargo r -r --bin iggy-bench -- pinned-producer --streams 10 --producers 10 tcp
$ cargo r -r --bin iggy-bench -- pinned-consumer --streams 10 --consumers 10 tcp
$ cargo r -r --bin iggy-bench -- pinned-producer-and-consumer --streams 10 --producers 10 --consumers 10 tcp
Balanced producer (bp), consumer group (bcg), and producer/consumer group (bpcg):
$ cargo r -r --bin iggy-bench -- balanced-producer --partitions 24 --producers 6 tcp
$ cargo r -r --bin iggy-bench -- balanced-consumer-group --consumers 6 tcp
$ cargo r -r --bin iggy-bench -- balanced-producer-and-consumer-group --partitions 24 --producers 6 --consumers 6 tcp
$ cargo r -r --bin iggy-bench -- --total-data 10GiB bpcg tcp
End-to-end producing consumer (e2e) and producing consumer group (e2ecg):
$ cargo r -r --bin iggy-bench -- end-to-end-producing-consumer --producing-consumers 12 --streams 12 tcp
$ cargo r -r --bin iggy-bench -- end-to-end-producing-consumer-group --partitions 24 --producers 6 --consumers 6 tcp
2) All transports:
$ cargo r -r --bin iggy-bench -- pinned-producer tcp --server-address 127.0.0.1:8090
$ cargo r -r --bin iggy-bench -- pinned-producer quic --server-address 127.0.0.1:8080
$ cargo r -r --bin iggy-bench -- pinned-producer http --server-address 127.0.0.1:3000
$ cargo r -r --bin iggy-bench -- pinned-producer websocket --server-address 127.0.0.1:8092
3) Topic durability:
--durability controls message completion.
--consumer-offset-durability controls explicit offset-store/delete completion.
Both independently default to replicated. Neither inherits the other.
Both policies normally write to disk. Persisted additionally waits for
recoverable stable storage on the required VSR quorum, or the single replica.
Both replicated (the default):
$ cargo r -r --bin iggy-bench -- balanced-producer-and-consumer-group tcp
Persisted messages, replicated offsets:
$ cargo r -r --bin iggy-bench -- --durability persisted balanced-producer-and-consumer-group tcp
Replicated messages, persisted offsets:
$ cargo r -r --bin iggy-bench -- --consumer-offset-durability persisted balanced-producer-and-consumer-group tcp
Both persisted:
$ cargo r -r --bin iggy-bench -- --durability persisted --consumer-offset-durability persisted balanced-producer-and-consumer-group tcp
These options apply when topics are created. They do not modify topics
with --reuse-streams. Consumer polling with auto-commit remains asynchronous.
Its poll latency is not an acknowledged offset-store latency measurement.
In replicated groups, either persisted policy enables a WAL that also retains
message predecessors, even when message durability is replicated.
4) Topic flush cadence and retention:
--messages-required-to-save is a global create-time topic option.
It controls segment flush cadence, not the acknowledgment guarantee.
--max-topic-size and --message-expiry are kind-specific topic options.
These flags do not change existing topics with --reuse-streams.
Persisted messages without forcing a segment flush for every message:
$ cargo r -r --bin iggy-bench -- --durability persisted --messages-required-to-save 1024 balanced-producer --partitions 1 --producers 8 tcp
Replicated acknowledgments with eager segment flushing:
$ cargo r -r --bin iggy-bench -- --messages-required-to-save 1 balanced-producer tcp
Retention can delete data during a long run. Use matching policies when comparing:
$ cargo r -r --bin iggy-bench -- balanced-producer --max-topic-size 10GiB --message-expiry 1h tcp
5) Workload configuration:
--messages-per-batch (-P): Messages per batch, or a range such as 100..1000.
--message-batches (-b): Batches per actor, mutually exclusive with --total-data.
--total-data (-T): Total message bytes across actors, such as 10GiB.
--message-size (-m): Message bytes, or a range such as 100..1000.
--rate-limit (-r): Aggregate throughput limit across actors, such as 100MB.
--warmup-time (-w): Warmup duration, such as 10s.
--sampling-time (-t): Metrics sampling interval.
--moving-average-window (-W): Moving-average window size.
Fixed message and batch sizes:
$ cargo r -r --bin iggy-bench -- --message-size 1000 --messages-per-batch 100 --message-batches 1000 --rate-limit 100MB balanced-producer --streams 5 --producers 5 tcp
Random message sizes:
$ cargo r -r --bin iggy-bench -- --message-size 100..1000 --messages-per-batch 100 --total-data 1GiB balanced-producer --streams 5 --producers 5 tcp
Random batch sizes:
$ cargo r -r --bin iggy-bench -- --message-size 1000 --messages-per-batch 10..100 --total-data 500MiB balanced-producer tcp
Random message and batch sizes with a warmup and aggregate rate limit:
$ cargo r -r --bin iggy-bench -- --message-size 500..2000 --messages-per-batch 50..200 --total-data 2GiB --warmup-time 10s --rate-limit 50MB balanced-producer tcp
6) Remote server and output:
$ cargo r -r --bin iggy-bench -- pinned-producer --streams 5 --producers 5 tcp --server-address localhost:8090
$ cargo r -r --bin iggy-bench -- --username admin --password secret pinned-producer tcp --server-address 192.168.1.100:8090
$ cargo r -r --bin iggy-bench -- pinned-producer tcp output
$ cargo r -r --bin iggy-bench -- --durability persisted balanced-producer tcp output --identifier dedicated-host --remark persisted-messages --gitref abc123
$ cargo r -r --bin iggy-bench -- end-to-end-producing-consumer tcp output --open-charts
Output options include --output-dir (-o), --identifier, --remark, --gitref,
--gitref-date, --extra-info, and --open-charts (-c).
Record both durability policies, CPU allocation, host tuning, and storage.
See core/bench/README.md and https://iggy.apache.org/docs/server/linux-tuning.
7) Help:
$ cargo r -r --bin iggy-bench -- --help
$ cargo r -r --bin iggy-bench -- pinned-producer --help
$ cargo r -r --bin iggy-bench -- pinned-producer tcp --help
$ cargo r -r --bin iggy-bench -- pinned-producer tcp output --help
";
pub fn print_examples() {
println!("{EXAMPLES}");
}
#[cfg(test)]
mod tests {
use super::EXAMPLES;
use crate::args::common::IggyBenchArgs;
use clap::{CommandFactory, FromArgMatches, Parser, error::ErrorKind};
use iggy::prelude::Durability;
use std::collections::BTreeSet;
#[test]
fn published_examples_parse_and_cover_every_kind_and_transport() {
let mut kinds = BTreeSet::new();
let mut transports = BTreeSet::new();
for command in EXAMPLES.lines().filter_map(|line| {
line.trim()
.strip_prefix("$ cargo r -r --bin iggy-bench -- ")
}) {
let arguments = std::iter::once("iggy-bench").chain(command.split_ascii_whitespace());
match IggyBenchArgs::command().try_get_matches_from(arguments) {
Ok(matches) => {
let (kind, options) = matches.subcommand().unwrap();
kinds.insert(kind.to_owned());
transports.insert(options.subcommand_name().unwrap().to_owned());
IggyBenchArgs::from_arg_matches(&matches)
.unwrap()
.validate();
}
Err(error) => {
assert_eq!(error.kind(), ErrorKind::DisplayHelp, "{command}: {error}");
}
}
}
let command = IggyBenchArgs::command();
for kind in command
.get_subcommands()
.filter(|kind| kind.get_name() != "examples")
{
assert!(
kinds.contains(kind.get_name()),
"missing kind {}",
kind.get_name()
);
}
let producer = command.find_subcommand("pinned-producer").unwrap();
for transport in producer.get_subcommands() {
assert!(
transports.contains(transport.get_name()),
"missing transport {}",
transport.get_name()
);
}
}
#[test]
fn websocket_and_its_alias_use_the_same_canonical_name() {
for name in ["websocket", "ws"] {
let parsed =
IggyBenchArgs::try_parse_from(["iggy-bench", "pinned-producer", name]).unwrap();
assert_eq!(parsed.transport_command().as_str(), "websocket");
}
}
#[test]
fn durability_defaults_are_independent() {
for (flags, messages, offsets) in [
(vec![], Durability::Replicated, Durability::Replicated),
(
vec!["--durability", "persisted"],
Durability::Persisted,
Durability::Replicated,
),
(
vec!["--consumer-offset-durability", "persisted"],
Durability::Replicated,
Durability::Persisted,
),
(
vec![
"--durability",
"persisted",
"--consumer-offset-durability",
"persisted",
],
Durability::Persisted,
Durability::Persisted,
),
] {
let arguments = std::iter::once("iggy-bench")
.chain(flags)
.chain(["balanced-producer-and-consumer-group", "tcp"]);
let parsed = IggyBenchArgs::try_parse_from(arguments).unwrap();
assert_eq!(parsed.durability, messages);
assert_eq!(parsed.consumer_offset_durability, offsets);
}
}
}