Repository navigation
Releases
v0.7.0
Теперь LeetTest сам говорит, когда числа в отчёте отражают опоздание самого генератора, а не цель, и показывает размер ответа и трафик. English · Deutsch · 简体中文
Новое
- Недействительный прогон, если хвост p99 решил генератор —
generator_late: когда опоздание самого генератора определило хвост, прогон завершается с кодом 2, а отчёт называет методы и советует дать генератору больше CPU, снизить частоту или разделить её между машинами; поиск точки отказа это не затрагивает. - Предупреждение посреди прогона — если больше 1% вызовов за последние 5 секунд стартовали позже порога ожидания (от 1 мс), в stderr уходит одна строка
warning:, не дожидаясь конца прогона. - Размер ответа, трафик и прогрев в отчёте — под методом
response: N B per call, в шапкеtraffic:(отправлено и получено, только тела сообщений), под методом с прогревомwarm-up:с его p50 и p99. - Строка про расписание — если генератор не мог ждать момента каждого вызова точно (на Windows и macOS всегда, на Linux при грубых часах или одном ядре), в шапке появляется
schedule: not exactс причинами. - Опоздание генератора в Prometheus — серия
leettest_start_lag_secondsрядом сleettest_planned_rps: провал нагрузки вместе с её ростом — вина генератора, не цели.
Ещё: расписание, трафик, размер ответа и прогрев есть и в JSON-отчёте, а leettest compare называет разницу расписаний.
При обновлении
- Прогон, у которого хвост p99 решило опоздание генератора, раньше заканчивался с пометкой в отчёте, теперь он недействителен (код 2): дайте генератору больше CPU или снизьте частоту.
Справочник · Что дальше · Сообщить о проблеме
English
LeetTest now says by itself when the numbers in a report reflect the generator's own lateness rather than the target, and shows reply size and traffic.
New
- An invalid run when the generator decided the p99 tail —
generator_late: when the generator's own lateness decided the tail, the run ends with code 2, and the report names the methods and advises giving the generator more CPU, lowering the rate or splitting it across machines; the breaking-point search is not affected. - A warning in the middle of a run — if more than 1% of the calls in the last 5 seconds started later than the wait threshold (1 ms or more), one
warning:line goes to stderr without waiting for the run to end. - Reply size, traffic and warm-up in the report —
response: N B per callunder a method,traffic:in the header (sent and received, message bodies only), and under a method with a warm-up awarm-up:line with its p50 and p99. - A schedule line — if the generator could not wait for each call's moment exactly (always on Windows and macOS, on Linux with a coarse clock or a single core), the header gets
schedule: not exactwith the reasons. - The generator's lateness in Prometheus — the
leettest_start_lag_secondsseries next toleettest_planned_rps: a dip in the load together with this series rising is the generator's fault, not the target's.
Also: the schedule, traffic, reply size and warm-up are in the JSON report too, and leettest compare names a difference in schedules.
Upgrading
- A run whose p99 tail was decided by the generator's lateness used to end with a note in the report; it is now invalid (code 2): give the generator more CPU or lower the rate.
Reference · What comes next · Report a problem
Deutsch
LeetTest sagt jetzt selbst, wenn die Zahlen im Bericht die Verspätung des Generators statt des Ziels abbilden, und zeigt Antwortgröße und Traffic.
Neu
- Ungültiger Lauf, wenn der Generator den p99-Schwanz bestimmt hat —
generator_late: Hat die eigene Verspätung des Generators den Schwanz bestimmt, endet der Lauf mit Code 2; der Bericht nennt die Methoden und rät, dem Generator mehr CPU zu geben, die Rate zu senken oder sie auf mehrere Maschinen zu verteilen; die Suche nach dem Bruchpunkt bleibt davon unberührt. - Eine Warnung mitten im Lauf — starteten in den letzten 5 Sekunden mehr als 1 % der Aufrufe später als die Wartegrenze (ab 1 ms), geht eine
warning:-Zeile nach stderr, ohne das Ende des Laufs abzuwarten. - Antwortgröße, Traffic und Warm-up im Bericht —
response: N B per callunter einer Methode,traffic:im Kopf (gesendet und empfangen, nur Nachrichtenkörper) und unter einer Methode mit Warm-up eine Zeilewarm-up:mit ihrem p50 und p99. - Eine Zeile zum Zeitplan — konnte der Generator nicht exakt auf den Zeitpunkt jedes Aufrufs warten (unter Windows und macOS immer, unter Linux bei grober Uhr oder einem einzigen Kern), steht im Kopf
schedule: not exactmit den Gründen. - Die Verspätung des Generators in Prometheus — die Serie
leettest_start_lag_secondsnebenleettest_planned_rps: ein Einbruch der Last bei gleichzeitigem Anstieg dieser Serie geht auf das Konto des Generators, nicht des Ziels.
Außerdem: Zeitplan, Traffic, Antwortgröße und Warm-up stehen auch im JSON-Bericht, und leettest compare benennt einen Unterschied der Zeitpläne.
Beim Update
- Ein Lauf, dessen p99-Schwanz von der Verspätung des Generators bestimmt wurde, endete früher mit einem Hinweis im Bericht; jetzt ist er ungültig (Code 2): Geben Sie dem Generator mehr CPU oder senken Sie die Rate.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
现在 LeetTest 会自己指出:报告里的数字反映的是生成器自身的延迟而不是目标,并且会显示响应大小和流量。
新功能
- 生成器决定了 p99 尾部时,运行无效 —
generator_late:当生成器自身的延迟决定了尾部,运行以退出码 2 结束,报告会列出相关方法,并建议给生成器更多 CPU、降低速率或把速率分摊到多台机器;崩溃点搜索不受影响。 - 运行中途的警告 — 如果最近 5 秒内超过 1% 的调用晚于等待阈值(至少 1 毫秒)才开始,stderr 会输出一行
warning:,不必等到运行结束。 - 报告中的响应大小、流量和预热 — 方法下方有
response: N B per call,头部有traffic:(发送和接收,仅消息体),有预热的方法下方有一行warm-up:,含预热的 p50 和 p99。 - 关于调度的一行 — 如果生成器无法精确等到每个调用的时刻(Windows 和 macOS 上总是如此,Linux 上是时钟粗糙或只有一个核心时),头部会出现
schedule: not exact,列出原因。 - Prometheus 中的生成器延迟 — 序列
leettest_start_lag_seconds与leettest_planned_rps放在一起看:负载下陷同时这个序列上升,是生成器的问题,不是目标的问题。
另外:调度、流量、响应大小和预热也在 JSON 报告中,leettest compare 会指出调度的差异。
升级须知
- p99 尾部由生成器延迟决定的运行,以前只在报告里留一条说明,现在运行无效(退出码 2):给生成器更多 CPU,或降低速率。
v0.6.0
Теперь прогон можно смотреть в Grafana, а отчёт показывает, как менялась латенси по ходу нагрузки; в запросах появляются уникальные поля. English · Deutsch · 简体中文
Новое
- Метрики в Prometheus —
export.prometheus.listen(или флаг-metrics-listen) отдаёт/metrics, пока идёт нагрузка; адрес по умолчанию не задан, а выход после прогона задерживается на 15 с (linger), чтобы Prometheus успел снять итог. - Латенси по времени — под таблицей каждого метода блок
over time: темп, доля отказов, p50 и p99 по окнам прогона, не больше 12 строк; видно, когда p99 пошёл вверх, а не только чем всё кончилось. - Уникальные поля в запросах —
templates: trueподставляет вdata{{uuid}}(новый на каждый запрос) и{{seq}}(номер запроса с 1).
Ещё: план, который не помещается в 32-битное поле с {{seq}}, отклоняется до первого запроса.
Справочник · Что дальше · Сообщить о проблеме
English
You can now watch a run in Grafana, the report shows how latency changed over the load, and requests can carry unique fields.
New
- Prometheus metrics —
export.prometheus.listen(or the-metrics-listenflag) serves/metricswhile the load runs; there is no default address, and the exit after a run is held for 15 s (linger) so Prometheus can scrape the final numbers. - Latency over time — under each method's table an
over timeblock: rate, failure share, p50 and p99 per window of the run, at most 12 rows; you see when p99 started to climb, not only how it ended. - Unique fields in requests —
templates: truefills{{uuid}}(new for every request) and{{seq}}(the request number from 1) intodata.
Also: a plan that does not fit a 32-bit field holding {{seq}} is refused before the first request.
Reference · What comes next · Report a problem
Deutsch
Ein Lauf lässt sich jetzt in Grafana beobachten, der Bericht zeigt, wie sich die Latenz während der Last verändert hat, und Anfragen können eindeutige Felder tragen.
Neu
- Prometheus-Metriken —
export.prometheus.listen(oder das Flag-metrics-listen) liefert/metrics, solange die Last läuft; es gibt keine Standardadresse, und der Ausstieg nach dem Lauf wird um 15 s (linger) verzögert, damit Prometheus das Endergebnis abholen kann. - Latenz über die Zeit — unter der Tabelle jeder Methode ein Block
over time: Rate, Fehleranteil, p50 und p99 je Zeitfenster des Laufs, höchstens 12 Zeilen; man sieht, wann p99 gestiegen ist, nicht nur, wie alles endete. - Eindeutige Felder in Anfragen —
templates: truesetzt indata{{uuid}}(neu für jede Anfrage) und{{seq}}(die Anfragenummer ab 1) ein.
Außerdem: ein Plan, der nicht in ein 32-Bit-Feld mit {{seq}} passt, wird vor der ersten Anfrage abgelehnt.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
现在可以在 Grafana 里观察一次运行,报告会显示延迟在加压过程中如何变化,请求里也可以带上唯一的字段。
新功能
- Prometheus 指标 —
export.prometheus.listen(或标志-metrics-listen)在加压期间提供/metrics;没有默认地址,运行结束后的退出会延迟 15 秒(linger),让 Prometheus 来得及取走最终数字。 - 延迟随时间的变化 — 每个方法的表格下方有一个
over time块:各时间窗口的速率、失败占比、p50 和 p99,最多 12 行;可以看到 p99 是何时开始上升的,而不只是最后的结果。 - 请求中的唯一字段 —
templates: true在data中填入{{uuid}}(每个请求都是新的)和{{seq}}(从 1 开始的请求编号)。
另外:放不进带 {{seq}} 的 32 位字段的计划,会在第一个请求之前被拒绝。
v0.5.0
Теперь LeetTest можно направить на систему, которой пользуются люди: он спросит перед стартом, разгонится плавно и сам остановится при всплеске ошибок. English · Deutsch · 简体中文
Новое
- Прогон по живой системе —
app.mode: realтребует разгон и предел ошибок, печатает план (цель, пик, длительность) и спрашиваетStart? [y/N]до первого запроса; без терминала нужен-yes. - Остановка при всплеске ошибок —
load.stop_on_errorsмягко останавливает прогон, когда доля упавших вызовов одного метода за последние 5 секунд выше предела; отчёт называет метод и числа.
Справочник · Что дальше · Сообщить о проблеме
English
LeetTest can now be pointed at a system people use: it asks before the start, ramps up smoothly and stops by itself on an error spike.
New
- Run against a live system —
app.mode: realrequires a ramp and an error limit, prints the plan (target, peak, duration) and asksStart? [y/N]before the first request; outside a terminal it needs-yes. - Stop on an error spike —
load.stop_on_errorsstops the run softly when one method's share of failed calls over the last 5 seconds is above the limit; the report names the method and the numbers.
Reference · What comes next · Report a problem
Deutsch
LeetTest lässt sich jetzt auf ein System richten, das Menschen nutzen: Es fragt vor dem Start, fährt die Last gleichmäßig hoch und stoppt bei einer Fehlerspitze von selbst.
Neu
- Lauf gegen ein Live-System —
app.mode: realverlangt ein Hochfahren und eine Fehlergrenze, gibt den Plan aus (Ziel, Spitze, Dauer) und fragt vor der ersten AnfrageStart? [y/N]; ohne Terminal braucht es-yes. - Stopp bei einer Fehlerspitze —
load.stop_on_errorsstoppt den Lauf weich, wenn der Anteil fehlgeschlagener Aufrufe einer Methode in den letzten 5 Sekunden über der Grenze liegt; der Bericht nennt die Methode und die Zahlen.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
LeetTest 现在可以指向有人在使用的系统:启动前先询问,平稳爬升,并在错误激增时自行停止。
新功能
- 对线上系统运行 —
app.mode: real要求爬升和错误上限,打印计划(目标、峰值、时长),并在第一个请求之前询问Start? [y/N];没有终端时需要-yes。 - 错误激增时停止 — 当某个方法在最近 5 秒内失败调用的占比高于上限时,
load.stop_on_errors软停止运行;报告写出方法名和数字。
v0.4.0
Теперь LeetTest проверяет конфиг одним запросом до нагрузки и плавно разгоняется до целевого RPS. English · Deutsch · 简体中文
Новое
- Проверка перед нагрузкой —
-dry-runшлёт по одному запросу на каждый вызов из конфига и показывает запрос, статус и ответ; без нагрузки и отчёта, код выхода 1, если хоть один вызов не прошёл. - Разгон —
load.rampподнимает нагрузку с нуля доrpsлинейно перед основной частью прогона; вызовы разгона не входят в статистику и в порогиpass.
Справочник · Что дальше · Сообщить о проблеме
English
LeetTest now checks a config with one request before the load and ramps up smoothly to the target RPS.
New
- Check before the load —
-dry-runsends one request per call in the config and shows the request, the status and the reply; no load, no report, exit code 1 if any call did not succeed. - Ramp-up —
load.rampraises the load linearly from zero torpsbefore the main part of the run; the ramp's calls stay out of the stats and thepasslimits.
Reference · What comes next · Report a problem
Deutsch
LeetTest prüft eine Konfiguration jetzt mit einer Anfrage vor der Last und fährt die Last gleichmäßig bis zur Ziel-RPS hoch.
Neu
- Prüfung vor der Last —
-dry-runsendet eine Anfrage pro Aufruf der Konfiguration und zeigt Anfrage, Status und Antwort; keine Last, kein Bericht, Exit-Code 1, wenn ein Aufruf nicht erfolgreich war. - Hochfahren —
load.rampsteigert die Last vor dem Hauptteil des Laufs linear von null aufrps; die Aufrufe des Hochfahrens zählen weder in der Statistik noch in denpass-Grenzen.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
LeetTest 现在可以在加压前用一个请求检查配置,并平稳地爬升到目标 RPS。
新功能
- 加压前检查 —
-dry-run为配置中的每个调用发送一个请求,并显示请求、状态和响应;不加压、不生成报告,任一调用未成功时退出码为 1。 - 爬升 —
load.ramp在运行主体之前把负载从零线性提升到rps;爬升期间的调用不计入统计,也不计入pass阈值。
v0.3.1
Два исправления в отчёте. English · Deutsch · 简体中文
Исправлено
- Файл
-json-fileбольше не становится доступен всем на чтение: права, которые у него были (например,0600), сохраняются. - Файл конфига
.yamlбезname:и с вызовами к нескольким сервисам больше не даёт отчёт с пустым названием прогона.
Справочник · Что дальше · Сообщить о проблеме
English
Two fixes in the report.
Fixed
- The
-json-filefile no longer becomes readable by everyone: the permissions it had (for example0600) are kept. - A config file named
.yaml, withoutname:and with calls to more than one service, no longer gives a report with an empty run name.
Reference · What comes next · Report a problem
Deutsch
Zwei Korrekturen im Bericht.
Behoben
- Die Datei von
-json-filewird nicht mehr für alle lesbar: ihre bisherigen Rechte (zum Beispiel0600) bleiben erhalten. - Eine Konfigurationsdatei namens
.yamlohnename:und mit Aufrufen an mehrere Services ergibt keinen Bericht mit leerem Laufnamen mehr.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
报告中的两处修复。
修复
-json-file写出的文件不再变成所有人可读:文件原有的权限(例如0600)会保留。- 名为
.yaml、未设置name:且调用多个服务的配置文件,不再生成运行名称为空的报告。
v0.3.0
Теперь LeetTest работает с сервисами без reflection, сам проверяет пороги и сравнивает два прогона. English · Deutsch · 简体中文
Новое
- Сервисы без reflection — схема методов берётся из файлов
.protoили protoset. - Пороги — секция
passзадаёт пределы латентности и ошибок; прогон, который в них не уложился, завершается с отдельным кодом выхода — готово для CI. - Сравнение прогонов —
leettest compare before.json after.jsonпоказывает, насколько упала ёмкость или вырос p99. - Паспорт прогона — отчёт хранит, на какой машине и с каким конфигом он сделан;
-json-fileпишет отчёт в файл. - Случайный порядок данных — запросы из файла идут в случайном порядке, который можно повторить, или без повторов.
Ещё: p99.9 по методу, сжатие gzip, свой лимит ошибок в поиске точки отказа, предупреждение, когда CPU не хватает самому генератору, установка одной командой на Linux и macOS.
Исправлено
- На машине с одним ядром генератор больше не добавляет к латентности свою задержку при 500 rps и выше.
- Ответ на unary-вызов без сообщения или с лишним сообщением теперь
bad response, а не ошибка цели. - Ошибка о не заданной
${ENV}говорит, как её задать.
При обновлении
- Одно имя якоря YAML (
&a), заданное дважды, теперь ошибка конфига: раньше поле могло молча получить чужое значение. Переименуйте один из якорей. - Служебные заголовки (
content-type,te,connectionи подобные) в метаданных теперь отклоняются до старта.
Справочник · Что дальше · Сообщить о проблеме
English
LeetTest now works with services without reflection, checks thresholds itself and compares two runs.
New
- Services without reflection — the schema of the methods is taken from
.protofiles or a protoset. - Thresholds — the
passsection sets limits on latency and errors; a run that does not stay within them ends with its own exit code — ready for CI. - Run comparison —
leettest compare before.json after.jsonshows how much the capacity fell or p99 rose. - Run passport — the report keeps which machine and which config it was made with;
-json-filewrites the report to a file. - Random order of data — requests from the file go in a random order that can be repeated, or without repeats.
Also: p99.9 per method, gzip compression, your own error limit in the breaking-point search, a warning when the generator itself runs short of CPU, one-command install on Linux and macOS.
Fixed
- On a one-core machine the generator no longer adds its own delay to latency at 500 rps and above.
- A reply to a unary call with no message or with an extra message is now
bad response, not a target error. - The error about an unset
${ENV}says how to set it.
Upgrading
- A single YAML anchor name (
&a) defined twice is now a config error: before, a field could silently get another anchor's value. Rename one of the anchors. - Reserved headers (
content-type,te,connectionand the like) in metadata are now rejected before the start.
Reference · What comes next · Report a problem
Deutsch
LeetTest arbeitet jetzt mit Diensten ohne Reflection, prüft Schwellen selbst und vergleicht zwei Läufe.
Neu
- Dienste ohne Reflection — das Schema der Methoden kommt aus
.proto-Dateien oder einem Protoset. - Schwellen — der Abschnitt
passsetzt Grenzen für Latenz und Fehler; ein Lauf, der sie nicht einhält, endet mit einem eigenen Exit-Code — bereit für CI. - Läufe vergleichen —
leettest compare before.json after.jsonzeigt, wie stark die Kapazität gefallen oder der p99 gestiegen ist. - Pass des Laufs — der Bericht hält fest, auf welcher Maschine und mit welcher Konfiguration er entstand;
-json-fileschreibt den Bericht in eine Datei. - Zufällige Reihenfolge der Daten — Anfragen aus der Datei gehen in zufälliger, wiederholbarer Reihenfolge oder ohne Wiederholungen.
Außerdem: p99.9 je Methode, gzip-Kompression, eigene Fehlergrenze bei der Suche nach dem Bruchpunkt, eine Warnung, wenn dem Generator selbst die CPU fehlt, Installation mit einem Befehl unter Linux und macOS.
Behoben
- Auf einer Maschine mit einem Kern fügt der Generator der Latenz ab 500 rps keine eigene Verzögerung mehr hinzu.
- Eine Antwort auf einen unären Aufruf ohne Nachricht oder mit einer zusätzlichen Nachricht ist jetzt
bad response, kein Fehler des Ziels. - Der Fehler zu einer nicht gesetzten
${ENV}sagt, wie man sie setzt.
Beim Update
- Ein YAML-Anker-Name (
&a), der zweimal vergeben wird, ist jetzt ein Konfigurationsfehler: Früher konnte ein Feld stillschweigend den Wert eines fremden Ankers bekommen. Benennen Sie einen der Anker um. - Reservierte Header (
content-type,te,connectionund ähnliche) in den Metadaten werden jetzt vor dem Start abgelehnt.
Referenz · Was als Nächstes kommt · Problem melden
简体中文
LeetTest 现在支持没有 reflection 的服务,能自己检查阈值,并比较两次运行。
新功能
- 没有 reflection 的服务 —— 方法的结构取自
.proto文件或 protoset。 - 阈值 ——
pass段设置延迟和错误的限值;未达标的运行会以单独的退出码结束——可直接用于 CI。 - 运行对比 ——
leettest compare before.json after.json显示容量下降了多少或 p99 上升了多少。 - 运行护照 —— 报告记录它是在哪台机器、用哪份配置得出的;
-json-file把报告写入文件。 - 数据的随机顺序 —— 文件中的请求按可重复的随机顺序发送,或不重复发送。
另外:按方法的 p99.9、gzip 压缩、崩溃点搜索中可自定义的错误上限、压测机自身 CPU 不足时的提示、在 Linux 和 macOS 上一条命令安装。
修复
- 在单核机器上,请求速率达到 500 rps 及以上时,压测机不再给延迟额外加上自身的延迟。
- 对 unary 调用的应答没有消息或多出消息时,现在归为
bad response,而不是目标的错误。 - 未设置
${ENV}的报错会说明如何设置。
升级须知
- 同一个 YAML 锚点名(
&a)定义两次,现在是配置错误:此前某个字段可能悄悄取到别的锚点的值。请重命名其中一个锚点。 - 元数据中的保留头(
content-type、te、connection等)现在会在启动前被拒绝。
v0.2.0
Теперь LeetTest сам находит нагрузку, на которой сервис перестаёт справляться. Плюс разные запросы в
каждом вызове и несколько соединений. English · Deutsch · 简体中文
Что нового
- Поиск точки отказа. Секция
load.breakpointвместоrpsиduration: LeetTest поднимает
нагрузку ступенями и называет, на какой ступени цель держалась и на какой сломалась. Ступень
ломается от доли ошибок или от p99 (порог можно задать); сломанную ступень он повторяет и проверяет,
что цель вернулась к прежнему p99. Если упёрся сам генератор, итог говорит об этом, а не о цели.
Итог в отчёте и в JSON — из закрытого списка (broke,broke_at_first,held_all,run_limit,
stopped,invalid) с причиной, у поиска есть живой экран. - Разные данные в каждом вызове.
dataset: wallets.jsonlу вызова: по JSON на строку, по порядку
и по кругу. Файл проверяется до старта по схеме метода; ошибка называет строку и не печатает её
содержимое. Отчёт говорит, сколько файла использовано. - Несколько соединений.
app.connections: N(1–256): вызовы идут по соединениям по кругу, имя с
несколькими адресами раскладывается по ним. Отчёт показывает блок по соединениям — адрес, вызовы,
доля отказов, p99 — так что мёртвый или медленный бэкенд за именем не усредняется. -plain. Без живого экрана и без диалога первого запуска: строка прогресса раз в секунду, как
без терминала. Удобно по ssh и в скриптах.- Точнее про оборванные вызовы. Если grpc-go потерял статус вызова после прозрачного повтора
(grpc-go#9443), вызов —cut offбез кода, который
приписан цели; раньше он мог выглядеть ошибкой клиента или сбоем, присланным целью. - JSON остаётся
schema_version1: поля добавлены (mode,connections.per_connection,
methods[].dataset,breakpoint.*), в режиме поиска верхний объект другой — см.
справочник.
Ограничения
Только unary. Нет разгона с нуля, порогов для CI и экспорта метрик —
что будет дальше. Несколько
соединений делят вызовы по кругу между адресами имени; за L4-балансировщиком они не гарантируют
разные бэкенды. Мерьте с Linux рядом с целью.
Не хватает возможности — напишите issue.
English
LeetTest now finds the load at which a service stops coping by itself. Plus a different request on
each call and several connections.
What is new
- Breaking-point search. A
load.breakpointsection instead ofrpsandduration: LeetTest
raises the load in steps and names the step the target held and the step it broke on. A step
breaks on the share of errors or on p99 (the limit can be set); a broken step is repeated, and the
target must come back to its earlier p99. If the generator itself hit a limit, the outcome says so
instead of blaming the target. The outcome in the report and in JSON is from a closed list
(broke,broke_at_first,held_all,run_limit,stopped,invalid) with a reason; the
search has a live screen. - A different request on each call.
dataset: wallets.jsonlon a call: one JSON per line, in
order and round and round. The file is checked against the method's schema before the start; an
error names the line and does not print its content. The report says how much of the file was used. - Several connections.
app.connections: N(1–256): calls go round-robin over the connections,
a name with several addresses is spread over them. The report shows a block per connection —
address, calls, share failed, p99 — so a dead or slow backend behind the name is not averaged
away. -plain. No live screen and no first-run dialog: a progress line once a second, as without a
terminal. Handy over ssh and in scripts.- Sharper about cut-off calls. When grpc-go loses a call's status after a transparent retry
(grpc-go#9443), the call iscut offwith no code
attributed to the target; before, it could read as a client error or as a failure the target
sent. - JSON stays
schema_version1: fields were added (mode,connections.per_connection,
methods[].dataset,breakpoint.*); in search mode the top-level object is different — see the
reference.
Limits
Unary only. No ramp-up from zero, CI thresholds or metrics export yet —
what comes next. Several
connections share calls round-robin over the addresses of a name; behind an L4 balancer they do not
guarantee different backends. Measure from Linux next to the target.
Missing something? Open an issue.
Deutsch
LeetTest findet jetzt selbst die Last, bei der ein Dienst nicht mehr zurechtkommt. Dazu eine andere
Anfrage bei jedem Aufruf und mehrere Verbindungen.
Was neu ist
- Suche nach dem Bruchpunkt. Ein Abschnitt
load.breakpointstattrpsundduration:
LeetTest erhöht die Last in Stufen und nennt die Stufe, die das Ziel hielt, und die, auf der es
brach. Eine Stufe bricht am Anteil der Fehler oder am p99 (die Grenze lässt sich setzen); eine
gebrochene Stufe wird wiederholt, und das Ziel muss zum früheren p99 zurückkehren. Stieß der
Generator selbst an eine Grenze, sagt das Ergebnis es, statt das Ziel zu beschuldigen. Das
Ergebnis in Bericht und JSON stammt aus einer geschlossenen Liste (broke,broke_at_first,
held_all,run_limit,stopped,invalid) mit einem Grund; die Suche hat eine Live-Ansicht. - Bei jedem Aufruf eine andere Anfrage.
dataset: wallets.jsonlam Aufruf: ein JSON pro Zeile,
der Reihe nach und im Kreis. Die Datei wird vor dem Start gegen das Schema der Methode geprüft;
ein Fehler nennt die Zeile und gibt ihren Inhalt nicht aus. Der Bericht sagt, wie viel der Datei
benutzt wurde. - Mehrere Verbindungen.
app.connections: N(1–256): Aufrufe gehen reihum über die
Verbindungen, ein Name mit mehreren Adressen wird darauf verteilt. Der Bericht zeigt einen Block
je Verbindung — Adresse, Aufrufe, Anteil Fehler, p99 —, damit ein totes oder langsames Backend
hinter dem Namen nicht untergemittelt wird. -plain. Keine Live-Ansicht und kein Dialog beim ersten Start: eine Fortschrittszeile pro
Sekunde, wie ohne Terminal. Praktisch über ssh und in Skripten.- Genauer bei abgeschnittenen Aufrufen. Verliert grpc-go den Status eines Aufrufs nach einem
transparenten Wiederholen (grpc-go#9443), ist der
Aufrufcut offohne einen dem Ziel zugeschriebenen Code; zuvor konnte er wie ein Fehler des
Clients oder wie ein vom Ziel gesendeter Fehler aussehen.- JSON bleibtschema_version1: Felder kamen hinzu (mode,connections.per_connection,
methods[].dataset,breakpoint.*); im Suchmodus ist das oberste Objekt ein anderes — siehe
Referenz.
Grenzen
Nur unär. Noch kein Hochfahren von null, keine CI-Schwellen, kein Metrik-Export —
was als Nächstes kommt.
Mehrere Verbindungen teilen die Aufrufe reihum auf die Adressen eines Namens auf; hinter einem
L4-Load-Balancer garantieren sie keine verschiedenen Backends. Messen Sie von Linux aus neben dem
Ziel.
Fehlt Ihnen etwas? Eröffnen Sie ein Issue.
简体中文
LeetTest 现在能自己找出服务开始吃不消的负载。此外,每次调用可用不同的请求,并支持多条连接。
新功能
- 崩溃点搜索。 用
load.breakpoint段代替rps和duration:LeetTest 分阶梯提高负载,指出目标
在哪一阶撑住、在哪一阶崩溃。一个阶梯因错误比例或 p99 而判为崩溃(p99 上限可设置);崩溃的阶梯会
重复,目标必须回到先前的 p99。如果是压测机自身触到上限,结论会如实说明,而不是归咎于目标。报告和
JSON 中的结论取自封闭列表(broke、broke_at_first、held_all、run_limit、stopped、
invalid)并附原因;搜索有实时界面。 - 每次调用不同的请求。 在调用上写
dataset: wallets.jsonl:每行一个 JSON,按顺序循环使用。文件在
启动前按方法的结构检查;错误会指出行号,且不输出该行内容。报告会说明文件用了多少。 - 多条连接。
app.connections: N(1–256):调用在连接间轮流分配,对应多个地址的名称会分摊到这些
地址上。报告按连接给出一个块——地址、调用数、失败比例、p99——因此名称背后失效或变慢的后端不会被
平均掉。 -plain。 没有实时界面,也没有首次运行对话框:每秒一行进度,与无终端时相同。适合 ssh 和脚本。- 对被截断的调用更准确。 当 grpc-go 在透明重试后丢失调用的状态
(grpc-go#9443),该调用归为cut off,不再给目标
记任何代码;此前它可能被当作客户端错误,或目标发来的故障。 - JSON 仍为
schema_version1:新增了字段(mode、connections.per_connection、
methods[].dataset、breakpoint.*);搜索模式下顶层对象不同——见
参考。
限制
仅支持 unary。尚无从零爬坡、CI 阈值和指标导出——
接下来会有什么。多条连接在名称
的各地址间轮流分配调用;在 L4 负载均衡器后面,不保证落到不同后端。请在目标旁边的 Linux 上测量。
缺少某项功能?提交 issue。
v0.1.0
Первая публичная версия: нагрузка на gRPC-сервис и отчёт, который не врёт, когда сервис
деградирует. English · Deutsch · 简体中文
Что умеет
- Нагрузка, похожая на настоящую. Несколько unary-методов в одном прогоне, у каждого свой RPS и
длительность. Вызовы уходят по расписанию, даже если предыдущие ещё не ответили. - Задержка, которая не прячет зависания. Считается от момента, на который вызов был
запланирован; p50/p90/p95/p99 и максимум по каждому методу, без усреднений. - Без
.proto. Методы и тело запроса берутся у сервиса через server reflection; тело пишется в
конфиге обычным YAML и проверяется до старта. - Доступ к настоящим сервисам. TLS, взаимный TLS, свой CA,
server_name; заголовки с
секретами из переменных окружения — их значения нигде не печатаются. - Ошибки — до первого вызова. Строгий конфиг, проверка подключения и запаса на зависшую цель —
с тем, что поменять. - Отчёт говорит, что случилось. Вызовы по категориям (перегрузка, сбой цели, таймаут, обрыв,
недоступность и др.); коды ошибок отдельно «от цели» и «от клиента»; при какой нагрузке и с
какого вызова цель перестала отвечать; таймаут показан как нижняя граница (>500ms), а не
числом; прогрев отдельно. - Видна доля самого генератора. Опоздание старта вызовов, ожидание соединения и стрима, p99 без
них — и что из этого держит хвост. - Недействительный прогон назван таким. Если числа не про цель (упор в потолок, ничего не измерено,
слишком грубые часы машины), прогон объявляется недействительным, код выхода 2. Ctrl+C
останавливает мягко и всё равно печатает отчёт. - Для людей и для скриптов. Живой экран в терминале, строка прогресса без терминала, JSON
(schema_version1) для CI. - Попробовать без своего сервиса. Эталонный стенд с известным поведением, готовые примеры на
каждый режим (быстрый старт),
встроенная фальшивая цель-fake.
Ограничения
Одно соединение — за балансировщиком нагрузку получает один бэкенд. Только unary. Нет разгона,
порогов для CI и экспорта метрик — что будет дальше.
Мерьте с Linux рядом с целью.
Известные проблемы
- Редкий обрыв, о котором grpc-go сообщает без статуса (голый
io.EOF), попадает вcut offс
кодомUnknown. Вызов всё равно считается неудачным и не приписывается цели.
Не хватает возможности — напишите issue.
English
The first public version: load on a gRPC service and a report that does not lie while the service
degrades.
What it does
- Load that looks like production. Several unary methods in one run, each at its own RPS and
duration. Calls go out on schedule even if earlier ones have not answered. - Latency that does not hide stalls. Counted from the moment each call was scheduled for;
p50/p90/p95/p99 and max per method, never averaged. - No
.proto. Methods and request bodies come from the service through server reflection; the
body is plain YAML in the config, checked before the start. - Access to real services. TLS, mutual TLS, a custom CA,
server_name; headers with secrets
from environment variables, their values printed nowhere. - Errors before the first call. A strict config, checks of the connection and of the headroom
for a hanging target, with what to change. - A report that says what happened. Calls by category (overload, target failure, timeout, cut
off, unreachable and more); error codes split into "from the target" and "from the client"; at
what load and from which call the target stopped answering; a timeout shown as a lower bound
(>500ms), not a number; warm-up apart. - The generator's own share is visible. How late calls started, waits for a connection and a
stream, p99 without them — and which of them holds the tail. - An invalid run is called invalid. When the numbers are not about the target (in-flight cap hit, nothing
measured, the machine's clock too coarse) the run is declared invalid, exit code 2. Ctrl+C stops
softly and still prints the report. - For people and scripts. A live terminal view, a progress line without a terminal, JSON
(schema_version1) for CI. - Try it without a service of your own. A reference stand with known behaviour, examples for
every mode (quickstart),
a built-in-faketarget.
Limits
One connection — behind a load balancer one backend gets the load. Unary only. No ramp-up, CI
thresholds or metrics export yet — what comes next.
Measure from Linux next to the target.
Known issues
- A rare drop that grpc-go reports with no status (a bare
io.EOF) lands incut offwith code
Unknown. The call still counts as failed and is not blamed on the target.
Missing something? Open an issue.
Deutsch
Die erste öffentliche Version: Last auf einen gRPC-Dienst und ein Bericht, der nicht lügt, während
der Dienst degradiert.
Was es kann
- Last wie in der Produktion. Mehrere unäre Methoden in einem Lauf, jede mit eigener RPS und
Dauer. Aufrufe gehen nach Plan raus, auch wenn frühere noch nicht geantwortet haben. - Latenz, die Stillstände nicht versteckt. Gezählt ab dem Zeitpunkt, für den jeder Aufruf
geplant war; p50/p90/p95/p99 und Maximum je Methode, nie gemittelt. - Kein
.proto. Methoden und Anfrage-Bodies kommen über Server Reflection vom Dienst; der Body
ist einfaches YAML in der Konfiguration, geprüft vor dem Start. - Zugang zu echten Diensten. TLS, gegenseitiges TLS, eigene CA,
server_name; Header mit
Geheimnissen aus Umgebungsvariablen, deren Werte nirgends ausgegeben werden. - Fehler vor dem ersten Aufruf. Eine strenge Konfiguration, Prüfung der Verbindung und der
Reserve für ein hängendes Ziel, mit dem, was zu ändern ist. - Ein Bericht, der sagt, was passiert ist. Aufrufe nach Kategorie (Überlastung, Fehler des
Ziels, Timeout, abgeschnitten, nicht erreichbar u. a.); Fehlercodes getrennt nach „vom Ziel" und
„vom Client"; bei welcher Last und ab welchem Aufruf das Ziel nicht mehr antwortete;
ein Timeout als Untergrenze (>500ms), nicht als Zahl; Aufwärmen getrennt. - Der Anteil des Generators ist sichtbar. Wie spät Aufrufe starteten, Warten auf Verbindung und
Stream, p99 ohne sie — und was davon das Ende der Verteilung hält. - Ein ungültiger Lauf heißt ungültig. Handeln die Zahlen nicht vom Ziel (Grenze erreicht, nichts gemessen,
zu grobe Uhr der Maschine), wird der Lauf für ungültig erklärt, Exit-Code 2. Ctrl+C hält sanft an
und gibt trotzdem den Bericht aus. - Für Menschen und Skripte. Eine Live-Ansicht im Terminal, eine Fortschrittszeile ohne Terminal,
JSON (schema_version1) für CI. - Ausprobieren ohne eigenen Dienst. Ein Referenz-Stand mit bekanntem Verhalten, Beispiele für
jeden Modus (Schnellstart),
ein eingebautes Scheinziel-fake.
Grenzen
Eine Verbindung — hinter einem Load Balancer bekommt ein Backend die Last. Nur unär. Noch kein
Hochfahren, keine CI-Schwellen, kein Metrik-Export —
was als Nächstes kommt. Messen
Sie von Linux aus neben dem Ziel.
Bekannte Probleme
- Ein seltener Abbruch, den grpc-go ohne Status meldet (ein nacktes
io.EOF), landet incut off
mit dem CodeUnknown. Der Aufruf zählt trotzdem als fehlgeschlagen und wird nicht dem Ziel
angelastet.
Fehlt Ihnen etwas? Eröffnen Sie ein Issue.
简体中文
第一个公开版本:对 gRPC 服务施加负载,并在服务退化时给出不说谎的报告。
功能
- 接近生产的负载。 一次运行中多个 unary 方法,各有自己的 RPS 和时长。即使之前的调用尚未应答,
调用也按计划发出。 - 不掩盖卡顿的延迟。 从每个调用被计划的时刻开始计算;按方法给出 p50/p90/p95/p99 和最大值,
从不做平均。 - 不需要
.proto。 方法和请求体通过 server reflection 从服务获取;请求体是配置中的普通 YAML,
在启动前检查。 - 访问真实服务。 TLS、双向 TLS、自定义 CA、
server_name;带机密的请求头取自环境变量,其值在
任何地方都不会输出。 - 错误发生在第一次调用之前。 严格的配置,检查连接以及应对目标挂起的余量,并说明应修改什么。
- 报告说明发生了什么。 调用按类别划分(过载、目标故障、超时、截断、不可达等);错误代码分为
“来自目标”和“来自客户端”;在什么负载下、从哪次调用起目标不再应答;
超时显示为下界(>500ms),而不是数字;预热单独统计。 - 压测机自身的影响清晰可见。 调用启动晚了多少、等待连接和流的时间、去掉这些等待后的 p99——
以及其中哪一项决定了尾部。 - 无效的运行会被标明无效。 当数字与目标无关时(触及上限、没有测到任何内容、机器时钟太粗),运行被
判为无效,退出码 2。Ctrl+C 温和停止,并仍然输出报告。 - 面向人和脚本。 终端中的实时界面,没有终端时的进度行,供 CI 使用的 JSON(
schema_version1)。 - 无需自己的服务即可试用。 行为已知的参考测试台,覆盖每种模式的示例
(快速上手),内置的
-fake假目标。
限制
一条连接——在负载均衡器后面只有一个后端承受负载。仅支持 unary。尚无爬坡、CI 阈值和指标导出——
接下来会有什么。请在目标旁边
的 Linux 上测量。
已知问题
- grpc-go 不带状态报告的罕见断开(裸
io.EOF)会归入cut off,代码为Unknown。该调用仍计为失败,
不会归咎于目标。
缺少某项功能?提交 issue。
v0.1.0-rc.1
Changelog
- e861479: feat: an exact schedule — one dispatcher sleeps to each call with clock_nanosleep (#142) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 3b1ce5d: fix: a client-side wait under a tenth of p99 is a note, not a verdict (#140) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 5595af7: fix: a clock step growing under a microsecond leaves the run valid (#139) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- d11daf0: fix: a silence names the planned rate of its own second, never planned 0 (#138) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 10b99c2: feat: an English, ASCII-only screen with exact counts (#127) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 972b0ab: fix: silence is counted by when the call went out (#132) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- e70cf79: fix: the last answer is when the call went out, not when it was due (#128) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- e4afcca: fix: the target's CANCELLED after our deadline is a timeout, not its failure (#129) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 98dd831: fix: refuse an oversized reply in our codec, not by a racy trailer signal (#126) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- d7c80c8: refactor: drop the timer raise; the step measure and its verdict stay (#122) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1da9d0b: fix: print +/- instead of a non-ASCII plus-minus in the clock note (#121) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 081f1e4: feat: measure the host clock step, raise the timer, invalidate runs it blurs (#120) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 2e940de: feat: rename limited_by to tail_wait_cause in the JSON report (#119) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- ca32ef3: feat: --output json, a versioned report for scripts (#118) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1dfa9a7: feat: overload and failure apart, client_error, bad_response; names are a contract (#116) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 77e0c4b: fix: name unsent calls without a cause in the report; e2e runs fail on sender defects (#115) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- e1eb174: fix: seconds split unsent calls by the totals' rule; per-method totals; unsent warmup calls counted (#114) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 85e7ee8: fix: a call answered before its body was written went out at its headers (#108) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 4c1b770: fix: the in-flight hint explains its margin once, in numbers, and advises the exact timeout (#102) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- f6b2787: feat: let a run receive replies over 4 MiB (#94) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 2c258aa: fix: compare p99 without every client-side wait (#93) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- d26427f: fix: the verdict names the largest cause of the wait (#90) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 9b97dfc: feat: measure each call's wait for a connection (#91) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 31f4566: fix: count warm-up calls apart from sent (#88) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 0aae0b9: fix: a rejected request is not pinned on the target (#86) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 14538e1: fix: an outcome never contradicts where its code came from (#85) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1e017ce: feat: list failed calls by their gRPC code (#79) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 45d8dc2: feat: print the version and build release binaries from a tag (#76) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- ec9392d: fix: ignore the service config a target hands out through its resolver (#83) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 22ddd1a: fix: count a transparently retried call by its last attempt (#75) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 36665d1: feat: reach a target that needs a token, its own CA or a client certificate (#81) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 6ddf472: refactor: one percentile rule behind Snapshot and Buffer (#73) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 5d9bb17: feat: report the stream limit the run hit and why calls did not go out (#72) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 4be4115: fix: latencies print with three significant figures (#70) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1c1472f: fix: a failed run's short verdict says the details are printed after exit (#68) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- c23ee14: fix: the final screen carries the text report's table (#66) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1c4ee80: fix: count only calls that went out as sent (#64) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 9ff44c1: fix: check every method against the target before the run (#62) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 4da987b: feat: give a pipeline exit codes it can tell apart (#63) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 3bf6ec6: fix: build the final screen from the same report as the log (#58) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 1eedbed: fix: name the moment the answers stopped, not the second it fell into (#57) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- bf030c4: feat: tell a rejected request from a target out of capacity (#56) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 5334124: fix: refuse a fractional rate and a warmup that covers a call (#55) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- c24b8fd: fix: rate the run over the time it was sending, not the drain (#54) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 6da86ab: fix: count every slot held past its deadline when the cap is hit (#61) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 2429d9a: feat: state what the target did not answer, and blame the cap on the generator (#52) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- e71b3cd: fix: lay the live view out from 60 columns in every language (#51) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 3eba475: perf: take live snapshots without allocating (#48) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- db01a3e: feat: time refusals apart from the time to serve (#47) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- d5f62ad: feat: say on the timeline whose fault each finished call was (#45) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- b7919e9: feat: count every second of a run per method (#43) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 4c0d08b: feat: say in the live view what another stop key press does (#38) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 0c18b45: fix: name only the field the request-data error is about (#39) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 141aff0: fix: keep a call's timings whole while the transport still writes them (#41) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 732a764: feat: stop a run in three stages and keep the calls it cuts off (#36) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- e65a8ab: fix: keep the stream-quota wait out of the target's service time (#35) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- edb656b: feat: build the request body from the method's data in the config (#33) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 423f248: feat: lead the header with status, service and target (#32) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 47efee0: feat: make the live view readable and leave it with one q (#29) (yeahgor 180073943+yhgrwav@users.noreply.github.com)
- 475aa76: feat: run the CLI ...