FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

First approach to slo performance (#58) · ydb-platform/ydb-java-examples@80d8013 · GitHub

Commit 80d8013

Browse files
authored
First approach to slo performance (#58)
Co-authored-by: KirillKurdyukov <kurdyukov-kir@ydb.tech> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 92ca970 commit 80d8013

14 files changed

Lines changed: 1997 additions & 0 deletions

File tree

‎pom.xml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<module>jdbc</module>
3232
<module>project-course</module>
3333
<module>slo</module>
34+
<module>slo-workload</module>
3435
</modules>
3536

3637
<dependencyManagement>

‎slo-workload/README.md‎

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# YDB SLO Workload Tests
2+
3+
This module hosts SLO (Service Level Objective) workloads that test the
4+
reliability of YDB Java clients under load and chaos using the
5+
[YDB SLO action](https://github.com/ydb-platform/ydb-slo-action).
6+
7+
Each submodule is a self-contained, runnable workload that follows the same
8+
contract as the SDK SLO workload in [`../slo`](../slo): it reads its
9+
configuration from environment variables, runs setup/run/teardown phases, and
10+
pushes OpenTelemetry (OTLP) metrics that the action scrapes and compares
11+
between the current PR run and a baseline run.
12+
13+
| Module | Component under test | Description |
14+
| --- | --- | --- |
15+
| [`jdbc`](jdbc) | `ydb-jdbc-driver` | Plain JDBC KV workload (no framework) |
16+
17+
## How a workload behaves
18+
19+
Every workload runs three phases:
20+
21+
1. **Setup** — creates a partitioned KV table and prefills it with rows.
22+
2. **Run** — drives concurrent read and write loops at fixed RPS for the
23+
configured duration. Each operation is timed and retried; the outcome is
24+
recorded as OTLP metrics.
25+
3. **Teardown** — drops the workload table even if the run failed, so the
26+
cluster is left clean.
27+
28+
While the workload runs, the SLO action injects chaos (node restarts, network
29+
black holes, container pauses). The metrics show how well the client copes.
30+
31+
## Metrics
32+
33+
Every metric carries a `ref` label taken from the `WORKLOAD_REF` environment
34+
variable, which lets the report action separate the **current** run from the
35+
**baseline** run. Names are shown below in Prometheus form (dots become
36+
underscores during the OTLP → Prometheus conversion).
37+
38+
| Metric | Type | Labels |
39+
| --- | --- | --- |
40+
| `sdk_operations_total` | counter | `operation_type`, `operation_status` |
41+
| `sdk_errors_total` | counter | `operation_type`, `error_kind` |
42+
| `sdk_retry_attempts_total` | counter | `operation_type`, `operation_status` |
43+
| `sdk_pending_operations` | up/down counter | `operation_type` |
44+
| `sdk_operation_latency_p50_seconds` | gauge | `operation_type`, `operation_status` (always `success`) |
45+
| `sdk_operation_latency_p95_seconds` | gauge | `operation_type`, `operation_status` (always `success`) |
46+
| `sdk_operation_latency_p99_seconds` | gauge | `operation_type`, `operation_status` (always `success`) |
47+
48+
Latency percentiles are computed from per-operation HDR histograms and reflect
49+
only successful operations — failure latency is dominated by retry budgets and
50+
timeouts and would mask real regressions during chaos. Counters cover both
51+
branches, so availability is computed correctly.
52+
53+
## Inputs
54+
55+
Connection details and run parameters come from environment variables:
56+
57+
| Variable | Description |
58+
| --- | --- |
59+
| `YDB_JDBC_URL` | Full JDBC URL (`jdbc:ydb:...`), used verbatim if set |
60+
| `YDB_CONNECTION_STRING` | YDB connection string; prefixed with `jdbc:ydb:` |
61+
| `YDB_ENDPOINT` + `YDB_DATABASE` | Used to compose the connection string if the above are unset |
62+
| `YDB_TOKEN` | Optional auth token |
63+
| `WORKLOAD_REF` | Value of the `ref` label on every metric |
64+
| `WORKLOAD_NAME` | Workload name (also part of the table name) |
65+
| `WORKLOAD_DURATION` | Run duration in seconds |
66+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP HTTP endpoint to push metrics to |
67+
68+
KV tunables are passed on the command line and parsed by JCommander:
69+
70+
```
71+
--read-rps <int> Target read RPS (default 1000)
72+
--write-rps <int> Target write RPS (default 100)
73+
--read-timeout-ms <int> Per-attempt read timeout in ms (default 10000)
74+
--write-timeout-ms <int> Per-attempt write timeout in ms (default 10000)
75+
--prefill-count <int> Rows to prefill before the run phase (default 1000)
76+
--partition-size <int> Auto-partitioning partition size in MB (default 1)
77+
--min-partition-count <int> Minimum number of table partitions (default 6)
78+
--max-partition-count <int> Maximum number of table partitions (default 1000)
79+
--duration <int> Override WORKLOAD_DURATION when > 0
80+
```
81+
82+
Unknown flags are ignored, so a workload accepts command strings designed for
83+
other SDKs without erroring.
84+
85+
## How CI uses this module
86+
87+
This repository only hosts the workload sources. The CI that actually runs them
88+
lives in the repository of the component under test — for `jdbc` that is
89+
[`ydb-jdbc-driver`](https://github.com/ydb-platform/ydb-jdbc-driver) — mirroring
90+
how the SDK SLO workload in [`../slo`](../slo) is driven from the
91+
`ydb-java-sdk` repository rather than from here.
92+
93+
The driver's workflow, via [`ydb-platform/ydb-slo-action`](https://github.com/ydb-platform/ydb-slo-action):
94+
95+
1. checks out the driver under test (current and baseline) and this repository
96+
for the workload sources;
97+
2. `ydb-platform/ydb-slo-action/init` deploys a YDB cluster (storage + database
98+
nodes), Prometheus with an OTLP receiver, and a chaos monkey, exposing the
99+
database node IPs and the OTLP endpoint as step outputs;
100+
3. builds the workload jar and runs it, pointing `YDB_CONNECTION_STRING` at a
101+
database node and `OTEL_EXPORTER_OTLP_ENDPOINT` at the Prometheus OTLP
102+
receiver;
103+
4. `ydb-platform/ydb-slo-action/report` compares the current run against the
104+
baseline and posts a summary to the PR.
105+
106+
## Building locally
107+
108+
From the `ydb-java-examples` repository root:
109+
110+
```bash
111+
mvn -pl slo-workload/jdbc -am -DskipTests package
112+
```
113+
114+
The resulting jar is at
115+
`slo-workload/jdbc/target/ydb-slo-jdbc-workload.jar`. To run it against a
116+
local YDB:
117+
118+
```bash
119+
export YDB_CONNECTION_STRING="grpc://localhost:2136/local"
120+
export WORKLOAD_REF=local
121+
export WORKLOAD_NAME=java-slo-jdbc
122+
123+
java -jar slo-workload/jdbc/target/ydb-slo-jdbc-workload.jar \
124+
--duration 60 --read-rps 100 --write-rps 10 --prefill-count 100
125+
```
126+
127+
If `OTEL_EXPORTER_OTLP_ENDPOINT` is not set, metrics are still recorded
128+
in-process but never exported — handy for verifying that the workload runs
129+
cleanly before pushing to CI.
130+
131+
## Adding a new workload
132+
133+
1. Create a module next to `jdbc` (e.g. `spring-data-jpa`).
134+
2. Reuse `Config`, `Metrics`, and the `kv` package; replace only the data
135+
access layer with the framework under test.
136+
3. Register the module in `slo-workload/pom.xml` and wire it into the SLO
137+
workflow of the component under test (in its own repository).
138+
139+
## Links
140+
141+
- [SDK SLO workload (reference)](../slo)
142+
- [YDB SLO Action](https://github.com/ydb-platform/ydb-slo-action)
143+
- [YDB JDBC Driver](https://github.com/ydb-platform/ydb-jdbc-driver)
144+
- [YDB Documentation](https://ydb.tech/docs/)

‎slo-workload/jdbc/Dockerfile‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Multi-stage Dockerfile for the YDB JDBC SLO workload.
2+
#
3+
# The image can be consumed by the YDB SLO action
4+
# (`ydb-platform/ydb-slo-action`): the workload reads its connection details
5+
# and run parameters from environment variables and pushes OTLP metrics to the
6+
# endpoint the action provides.
7+
#
8+
# Build context: the `ydb-java-examples` repository root.
9+
#
10+
# Optional build args:
11+
# MAVEN_IMAGE Builder image. Defaults to `maven:3.9-eclipse-temurin-17`.
12+
# RUNTIME_IMAGE Runtime image. Defaults to `eclipse-temurin:17-jre`.
13+
# YDB_JDBC_VERSION Override the ydb-jdbc-driver version under test.
14+
15+
ARG MAVEN_IMAGE=maven:3.9-eclipse-temurin-17
16+
ARG RUNTIME_IMAGE=eclipse-temurin:17-jre
17+
18+
# ---------- builder ---------------------------------------------------------
19+
FROM ${MAVEN_IMAGE} AS workload-build
20+
21+
WORKDIR /src
22+
COPY . /src
23+
24+
ARG YDB_JDBC_VERSION=""
25+
26+
# Pin the JDBC driver version under test when provided, then build only the
27+
# workload module (and the parent context it needs).
28+
RUN if [ -n "${YDB_JDBC_VERSION}" ]; then \
29+
echo "Pinning ydb-jdbc-driver to ${YDB_JDBC_VERSION}" && \
30+
mvn -B -q versions:set-property \
31+
-Dproperty=ydb.jdbc.version \
32+
-DnewVersion="${YDB_JDBC_VERSION}" \
33+
-DgenerateBackupPoms=false \
34+
-pl slo-workload ; \
35+
fi && \
36+
mvn -B -q -pl slo-workload/jdbc -am \
37+
-DskipTests \
38+
-Dmaven.javadoc.skip=true \
39+
package
40+
41+
# ---------- runtime ---------------------------------------------------------
42+
FROM ${RUNTIME_IMAGE}
43+
44+
WORKDIR /app
45+
46+
# The jar's manifest Class-Path points at libs/, so a single `java -jar` call
47+
# is enough.
48+
COPY --from=workload-build /src/slo-workload/jdbc/target/ydb-slo-jdbc-workload.jar /app/ydb-slo-jdbc-workload.jar
49+
COPY --from=workload-build /src/slo-workload/jdbc/target/libs /app/libs
50+
51+
ENTRYPOINT ["java", "-jar", "/app/ydb-slo-jdbc-workload.jar"]

‎slo-workload/jdbc/README.md‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# JDBC SLO workload
2+
3+
A plain-JDBC SLO workload that exercises the
4+
[YDB JDBC driver](https://github.com/ydb-platform/ydb-jdbc-driver) under load
5+
and chaos. It mirrors the structure and metrics contract of the SDK SLO
6+
workload in [`../../slo`](../../slo), so reports are directly comparable.
7+
8+
> See the [parent README](../README.md) for the shared metrics, environment
9+
> variables, CLI flags and CI flow.
10+
11+
## What it does
12+
13+
The workload runs as a standalone jar (`tech.ydb.slo.Main`) and goes through
14+
three phases against a partitioned KV table:
15+
16+
1. **Setup** — `CREATE TABLE IF NOT EXISTS` plus a prefill of `--prefill-count`
17+
rows.
18+
2. **Run** — dedicated read and write thread pools, each paced by a Guava
19+
`RateLimiter` to the target RPS, running until the configured duration.
20+
3. **Teardown** — `DROP TABLE`.
21+
22+
Every worker thread owns its own JDBC `Connection` (the driver's connections
23+
are not thread-safe) and reuses prepared statements. On a connection-level
24+
error the connection is transparently reopened on the next attempt.
25+
26+
## Schema
27+
28+
```
29+
hash Uint64 -- primary key, derived from id on the client
30+
id Uint64 -- primary key
31+
payload_str Utf8
32+
payload_double Double
33+
payload_timestamp Timestamp
34+
payload_hash Uint64
35+
```
36+
37+
The primary-key `hash` column is derived from `id` with a SplitMix64-style mix
38+
(`KvWorkload#numericHash`) so reads and writes target the same key without
39+
relying on server-side YQL builtins inside parameterized statements.
40+
41+
## Retries
42+
43+
Operations are retried with exponential backoff (up to 10 attempts). An error
44+
is considered retryable when the driver throws a `SQLRecoverableException` or
45+
`SQLTransientException` (which covers the driver's
46+
`YdbRetryableException`, `YdbConditionallyRetryableException`,
47+
`YdbUnavailbaleException` and `YdbTimeoutException`). The number of retries is
48+
recorded in `sdk_retry_attempts_total`, and the failure reason is reported via
49+
the `error_kind` label on `sdk_errors_total` (using the YDB status code when
50+
available).
51+
52+
## Files
53+
54+
```
55+
jdbc/
56+
├── Dockerfile
57+
├── pom.xml
58+
├── README.md
59+
└── src/main/
60+
├── java/tech/ydb/slo/
61+
│ ├── Config.java Reads env vars, resolves the JDBC URL
62+
│ ├── Main.java Entry point
63+
│ ├── Metrics.java OTLP metrics + HDR histograms
64+
│ └── kv/
65+
│ ├── KvWorkload.java Setup/run/teardown loop over JDBC
66+
│ ├── KvWorkloadParams.java JCommander-bound CLI flags
67+
│ ├── Row.java Row data class
68+
│ └── RowGenerator.java Random payload generator
69+
└── resources/
70+
└── log4j2.xml Console logging config
71+
```
72+
73+
## Building and running locally
74+
75+
```bash
76+
# From the repository root
77+
mvn -pl slo-workload/jdbc -am -DskipTests package
78+
79+
export YDB_CONNECTION_STRING="grpc://localhost:2136/local"
80+
export WORKLOAD_REF=local
81+
export WORKLOAD_NAME=java-slo-jdbc
82+
83+
java -jar slo-workload/jdbc/target/ydb-slo-jdbc-workload.jar \
84+
--duration 60 --read-rps 100 --write-rps 10 --prefill-count 100
85+
```
86+
87+
Build the container image (context is the repository root):
88+
89+
```bash
90+
docker build -f slo-workload/jdbc/Dockerfile -t ydb-slo-jdbc-workload .
91+
```

‎slo-workload/jdbc/pom.xml‎

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
4+
http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>tech.ydb.examples</groupId>
9+
<artifactId>slo-workload</artifactId>
10+
<version>1.1.0-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>jdbc</artifactId>
15+
<packaging>jar</packaging>
16+
<name>JDBC SLO workload</name>
17+
<description>SLO workload exercising the YDB JDBC driver, compatible with ydb-slo-action</description>
18+
19+
<dependencies>
20+
<!-- The component under test -->
21+
<dependency>
22+
<groupId>tech.ydb.jdbc</groupId>
23+
<artifactId>ydb-jdbc-driver</artifactId>
24+
</dependency>
25+
26+
<!-- CLI parameters -->
27+
<dependency>
28+
<groupId>com.beust</groupId>
29+
<artifactId>jcommander</artifactId>
30+
</dependency>
31+
32+
<!-- Rate limiting for the read/write loops -->
33+
<dependency>
34+
<groupId>com.google.guava</groupId>
35+
<artifactId>guava</artifactId>
36+
</dependency>
37+
38+
<!-- Latency percentiles -->
39+
<dependency>
40+
<groupId>org.hdrhistogram</groupId>
41+
<artifactId>HdrHistogram</artifactId>
42+
</dependency>
43+
44+
<!-- OpenTelemetry metrics + OTLP exporter -->
45+
<dependency>
46+
<groupId>io.opentelemetry</groupId>
47+
<artifactId>opentelemetry-api</artifactId>
48+
</dependency>
49+
<dependency>
50+
<groupId>io.opentelemetry</groupId>
51+
<artifactId>opentelemetry-sdk</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>io.opentelemetry</groupId>
55+
<artifactId>opentelemetry-sdk-metrics</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>io.opentelemetry</groupId>
59+
<artifactId>opentelemetry-exporter-otlp</artifactId>
60+
</dependency>
61+
62+
<!-- Logging -->
63+
<dependency>
64+
<groupId>org.apache.logging.log4j</groupId>
65+
<artifactId>log4j-slf4j2-impl</artifactId>
66+
</dependency>
67+
</dependencies>
68+
69+
<build>
70+
<finalName>ydb-slo-jdbc-workload</finalName>
71+
<plugins>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-compiler-plugin</artifactId>
75+
<configuration>
76+
<release>17</release>
77+
</configuration>
78+
</plugin>
79+
80+
<!-- Copy transitive dependencies into target/libs so a single
81+
`java -jar` works (Class-Path points at libs/). -->
82+
<plugin>
83+
<groupId>org.apache.maven.plugins</groupId>
84+
<artifactId>maven-dependency-plugin</artifactId>
85+
</plugin>
86+
87+
<plugin>
88+
<groupId>org.apache.maven.plugins</groupId>
89+
<artifactId>maven-jar-plugin</artifactId>
90+
<configuration>
91+
<archive>
92+
<manifest>
93+
<addClasspath>true</addClasspath>
94+
<classpathPrefix>libs/</classpathPrefix>
95+
<mainClass>tech.ydb.slo.Main</mainClass>
96+
</manifest>
97+
</archive>
98+
</configuration>
99+
</plugin>
100+
</plugins>
101+
</build>
102+
</project>

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL