Skip to content

Commit 6db6c3c

Browse files
committed
Topic workload SLO
1 parent 2d1ff8d commit 6db6c3c

File tree

6 files changed

+670
-38
lines changed

6 files changed

+670
-38
lines changed

.github/workflows/slo.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ jobs:
3030

3131
strategy:
3232
matrix:
33-
workload:
34-
- sync-table
35-
- sync-query
33+
include:
34+
- prefix: table
35+
workload: sync-table
36+
- prefix: table
37+
workload: sync-query
38+
3639

3740
concurrency:
3841
group: slo-${{ github.ref }}-${{ matrix.workload }}
@@ -64,14 +67,14 @@ jobs:
6467

6568
- name: Prepare SLO Database
6669
run: |
67-
python ./tests/slo/src create grpc://localhost:2135 /Root/testdb
70+
python ./tests/slo/src ${{ matrix.prefix }}-create grpc://localhost:2135 /Root/testdb
6871
6972
- name: Run SLO Tests
7073
env:
7174
REF: '${{ github.head_ref || github.ref }}'
7275
WORKLOAD: '${{ matrix.workload }}'
7376
run: |
74-
python ./tests/slo/src run grpc://localhost:2135 /Root/testdb \
77+
python ./tests/slo/src ${{ matrix.prefix }}-run grpc://localhost:2135 /Root/testdb \
7578
--prom-pgw localhost:9091 \
7679
--report-period 250 \
7780
--time ${{inputs.slo_workload_duration_seconds || 600}} \
@@ -83,7 +86,7 @@ jobs:
8386
- if: always()
8487
name: Cleanup SLO Database
8588
run: |
86-
python ./tests/slo/src cleanup grpc://localhost:2135 /Root/testdb
89+
python ./tests/slo/src ${{ matrix.prefix }}-cleanup grpc://localhost:2135 /Root/testdb
8790
8891
- if: always()
8992
name: Store ydb chaos testing logs

tests/slo/TOPIC_SLO.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# YDB Python SDK Topic SLO Tests
2+
3+
Этот документ описывает как использовать SLO тесты для топиков YDB.
4+
5+
## Описание
6+
7+
Topic SLO тесты измеряют производительность операций с топиками YDB:
8+
- **TopicWriter** - запись сообщений в топик
9+
- **TopicReader** - чтение сообщений из топика с коммитом
10+
11+
Тесты собирают метрики:
12+
- Latency (задержка операций)
13+
- RPS (количество операций в секунду)
14+
- Error rate (процент ошибок)
15+
- Retry attempts (количество попыток повтора)
16+
17+
## Использование
18+
19+
### Запуск Topic SLO тестов
20+
21+
Topic SLO тесты автоматически создают топик перед началом тестирования и удаляют его после завершения:
22+
23+
```bash
24+
cd tests/slo
25+
python -m src topic-run grpc://localhost:2135 /local
26+
```
27+
28+
### Параметры
29+
30+
#### Основные параметры:
31+
- `endpoint` - YDB endpoint (например: `grpc://localhost:2135`)
32+
- `db` - база данных (например: `/local`)
33+
34+
#### Параметры для топиков:
35+
- `--topic-path` - путь к топику (по умолчанию: `/local/slo_topic`)
36+
- `--topic-consumer` - имя консьюмера (по умолчанию: `slo_consumer`)
37+
- `--topic-message-size` - размер сообщения в байтах (по умолчанию: 100)
38+
39+
#### Параметры производительности:
40+
- `--topic-write-rps` - RPS для записи (по умолчанию: 20)
41+
- `--topic-read-rps` - RPS для чтения (по умолчанию: 50)
42+
- `--topic-write-threads` - количество потоков записи (по умолчанию: 2)
43+
- `--topic-read-threads` - количество потоков чтения (по умолчанию: 4)
44+
45+
#### Таймауты:
46+
- `--topic-write-timeout` - таймаут записи в мс (по умолчанию: 10000)
47+
- `--topic-read-timeout` - таймаут чтения в мс (по умолчанию: 5000)
48+
49+
#### Временные параметры:
50+
- `--time` - время работы теста в секундах (по умолчанию: 60)
51+
- `--shutdown-time` - время на graceful shutdown в секундах (по умолчанию: 10)
52+
53+
#### Метрики:
54+
- `--prom-pgw` - Prometheus push gateway (по умолчанию: `localhost:9091`)
55+
- `--report-period` - период отправки метрик в мс (по умолчанию: 1000)
56+
57+
### Примеры использования
58+
59+
#### Базовый запуск с настройками по умолчанию:
60+
```bash
61+
python -m src topic-run grpc://localhost:2135 /local
62+
```
63+
64+
#### Запуск с повышенной нагрузкой:
65+
```bash
66+
python -m src topic-run grpc://localhost:2135 /local \
67+
--topic-write-rps 100 \
68+
--topic-read-rps 200 \
69+
--topic-write-threads 4 \
70+
--topic-read-threads 8 \
71+
--time 300
72+
```
73+
74+
#### Запуск с большими сообщениями:
75+
```bash
76+
python -m src topic-run grpc://localhost:2135 /local \
77+
--topic-message-size 1024 \
78+
--topic-write-rps 10 \
79+
--topic-read-rps 20
80+
```
81+
82+
#### Запуск с кастомным топиком и консьюмером:
83+
```bash
84+
python -m src topic-run grpc://localhost:2135 /local \
85+
--topic-path /local/my_slo_topic \
86+
--topic-consumer my_consumer
87+
```
88+
89+
## Архитектура
90+
91+
### Компоненты
92+
93+
1. **topic_jobs.py** - основная логика для работы с топиками:
94+
- `run_topic_writes()` - цикл записи сообщений
95+
- `run_topic_reads()` - цикл чтения сообщений
96+
- `setup_topic()` - создание топика и консьюмера
97+
- `cleanup_topic()` - очистка топика
98+
99+
2. **metrics.py** - расширен для поддержки топик метрик:
100+
- `OP_TYPE_TOPIC_WRITE` - метрики записи
101+
- `OP_TYPE_TOPIC_READ` - метрики чтения
102+
103+
3. **options.py** - добавлена команда `topic-run` с параметрами для топиков
104+
105+
4. **runner.py** - добавлена функция `run_topic_slo()` для запуска топик тестов
106+
107+
### Workflow
108+
109+
1. **Инициализация**: создание топика и консьюмера (если не существуют)
110+
2. **Запуск воркеров**:
111+
- Потоки записи создают и отправляют сообщения
112+
- Потоки чтения получают и коммитят сообщения
113+
3. **Сбор метрик**: все операции измеряются и отправляются в Prometheus
114+
4. **Завершение**: graceful shutdown всех воркеров
115+
116+
## Метрики
117+
118+
Топик SLO тесты создают следующие метрики:
119+
120+
### Counters
121+
- `sdk_operations_total{operation_type="topic_write"}` - общее количество операций записи
122+
- `sdk_operations_total{operation_type="topic_read"}` - общее количество операций чтения
123+
- `sdk_operations_success_total{operation_type="topic_write|topic_read"}` - успешные операции
124+
- `sdk_operations_failure_total{operation_type="topic_write|topic_read"}` - неуспешные операции
125+
- `sdk_errors_total{operation_type="topic_write|topic_read", error_type="ErrorType"}` - ошибки по типам
126+
127+
### Histograms
128+
- `sdk_operation_latency_seconds{operation_type="topic_write|topic_read", operation_status="success|err"}` - латентность операций
129+
130+
### Gauges
131+
- `sdk_pending_operations{operation_type="topic_write|topic_read"}` - количество операций в процессе
132+
- `sdk_retry_attempts{operation_type="topic_write|topic_read"}` - количество попыток повтора
133+
134+
## Мониторинг
135+
136+
Для мониторинга рекомендуется использовать Grafana с Prometheus. Примеры запросов:
137+
138+
### RPS записи в топик:
139+
```promql
140+
rate(sdk_operations_total{operation_type="topic_write"}[1m])
141+
```
142+
143+
### RPS чтения из топика:
144+
```promql
145+
rate(sdk_operations_total{operation_type="topic_read"}[1m])
146+
```
147+
148+
### Процент ошибок записи:
149+
```promql
150+
rate(sdk_operations_failure_total{operation_type="topic_write"}[1m]) /
151+
rate(sdk_operations_total{operation_type="topic_write"}[1m]) * 100
152+
```
153+
154+
### 95-й перцентиль латентности чтения:
155+
```promql
156+
histogram_quantile(0.95, rate(sdk_operation_latency_seconds_bucket{operation_type="topic_read", operation_status="success"}[1m]))
157+
```
158+
159+
## Troubleshooting
160+
161+
### Часто встречающиеся проблемы:
162+
163+
1. **Топик не создается**: проверьте права доступа и корректность пути к топику
164+
2. **Таймауты чтения**: нормально, если нет новых сообщений; увеличьте `--topic-read-timeout` если нужно
165+
3. **Высокий error rate**: проверьте подключение к YDB и лимиты топика
166+
4. **Низкий RPS**: увеличьте количество потоков или RPS лимиты
167+
168+
### Логи:
169+
Тесты логируют в уровне INFO основные события. Для подробной диагностики включите DEBUG:
170+
```bash
171+
export PYTHONPATH=src
172+
python -c "import logging; logging.basicConfig(level=logging.DEBUG)" -m src topic-run ...
173+
```

tests/slo/src/metrics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from prometheus_client import CollectorRegistry, Counter, Gauge, Histogram, push_to_gateway # noqa: E402
1111

1212
OP_TYPE_READ, OP_TYPE_WRITE = "read", "write"
13+
OP_TYPE_TOPIC_READ, OP_TYPE_TOPIC_WRITE = "topic_read", "topic_write"
1314
OP_STATUS_SUCCESS, OP_STATUS_FAILURE = "success", "err"
1415

1516
REF = environ.get("REF", "main")

tests/slo/src/options.py

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,96 @@ def add_common_options(parser):
77
parser.add_argument("-t", "--table-name", default="key_value", help="Table name")
88

99

10-
def make_create_parser(subparsers):
11-
create_parser = subparsers.add_parser("create", help="Create tables and fill with initial content")
12-
add_common_options(create_parser)
10+
def make_table_create_parser(subparsers):
11+
table_create_parser = subparsers.add_parser("table-create", help="Create tables and fill with initial content")
12+
add_common_options(table_create_parser)
1313

14-
create_parser.add_argument(
14+
table_create_parser.add_argument(
1515
"-p-min", "--min-partitions-count", default=6, type=int, help="Minimum amount of partitions in table"
1616
)
17-
create_parser.add_argument(
17+
table_create_parser.add_argument(
1818
"-p-max", "--max-partitions-count", default=1000, type=int, help="Maximum amount of partitions in table"
1919
)
20-
create_parser.add_argument("-p-size", "--partition-size", default=100, type=int, help="Partition size [mb]")
21-
create_parser.add_argument(
20+
table_create_parser.add_argument("-p-size", "--partition-size", default=100, type=int, help="Partition size [mb]")
21+
table_create_parser.add_argument(
2222
"-c", "--initial-data-count", default=1000, type=int, help="Total number of records to generate"
2323
)
2424

25-
create_parser.add_argument("--write-timeout", default=20000, type=int, help="Write requests execution timeout [ms]")
25+
table_create_parser.add_argument("--write-timeout", default=20000, type=int, help="Write requests execution timeout [ms]")
2626

27-
create_parser.add_argument(
27+
table_create_parser.add_argument(
2828
"--batch-size", default=100, type=int, help="Number of new records in each create request"
2929
)
30-
create_parser.add_argument("--threads", default=10, type=int, help="Number of threads to use")
30+
table_create_parser.add_argument("--threads", default=10, type=int, help="Number of threads to use")
3131

3232

33-
def make_run_parser(subparsers, name="run"):
34-
run_parser = subparsers.add_parser(name, help="Run measurable workload")
35-
add_common_options(run_parser)
33+
def make_table_run_parser(subparsers):
34+
table_run_parser = subparsers.add_parser("table-run", help="Run table SLO workload")
35+
add_common_options(table_run_parser)
3636

37-
run_parser.add_argument("--read-rps", default=100, type=int, help="Read request rps")
38-
run_parser.add_argument("--read-timeout", default=10000, type=int, help="Read requests execution timeout [ms]")
37+
table_run_parser.add_argument("--read-rps", default=100, type=int, help="Read request rps")
38+
table_run_parser.add_argument("--read-timeout", default=10000, type=int, help="Read requests execution timeout [ms]")
3939

40-
run_parser.add_argument("--write-rps", default=10, type=int, help="Write request rps")
41-
run_parser.add_argument("--write-timeout", default=20000, type=int, help="Write requests execution timeout [ms]")
40+
table_run_parser.add_argument("--write-rps", default=10, type=int, help="Write request rps")
41+
table_run_parser.add_argument("--write-timeout", default=20000, type=int, help="Write requests execution timeout [ms]")
4242

43-
run_parser.add_argument("--time", default=10, type=int, help="Time to run in seconds")
44-
run_parser.add_argument("--shutdown-time", default=10, type=int, help="Graceful shutdown time in seconds")
43+
table_run_parser.add_argument("--time", default=10, type=int, help="Time to run in seconds")
44+
table_run_parser.add_argument("--shutdown-time", default=10, type=int, help="Graceful shutdown time in seconds")
4545

46-
run_parser.add_argument("--prom-pgw", default="localhost:9091", type=str, help="Prometheus push gateway")
47-
run_parser.add_argument("--report-period", default=1000, type=int, help="Prometheus push period in [ms]")
46+
table_run_parser.add_argument("--prom-pgw", default="localhost:9091", type=str, help="Prometheus push gateway")
47+
table_run_parser.add_argument("--report-period", default=1000, type=int, help="Prometheus push period in [ms]")
4848

49-
run_parser.add_argument("--read-threads", default=8, type=int, help="Number of threads to use for write")
50-
run_parser.add_argument("--write-threads", default=4, type=int, help="Number of threads to use for read")
49+
table_run_parser.add_argument("--read-threads", default=8, type=int, help="Number of threads to use for write")
50+
table_run_parser.add_argument("--write-threads", default=4, type=int, help="Number of threads to use for read")
5151

5252

53-
def make_cleanup_parser(subparsers):
54-
cleanup_parser = subparsers.add_parser("cleanup", help="Drop tables")
55-
add_common_options(cleanup_parser)
53+
def make_topic_run_parser(subparsers):
54+
"""Создает парсер для команды topic-run - запуск SLO тестов для топиков"""
55+
topic_parser = subparsers.add_parser("topic-run", help="Run topic SLO workload")
56+
add_common_options(topic_parser)
57+
58+
topic_parser.add_argument("--topic-read-rps", default=50, type=int, help="Topic read request rps")
59+
topic_parser.add_argument("--topic-read-timeout", default=5000, type=int, help="Topic read timeout [ms]")
60+
topic_parser.add_argument("--topic-write-rps", default=20, type=int, help="Topic write request rps")
61+
topic_parser.add_argument("--topic-write-timeout", default=10000, type=int, help="Topic write timeout [ms]")
62+
topic_parser.add_argument("--topic-read-threads", default=1, type=int, help="Number of threads for topic reading")
63+
topic_parser.add_argument("--topic-write-threads", default=1, type=int, help="Number of threads for topic writing")
64+
topic_parser.add_argument("--topic-path", default="/local/slo_topic", type=str, help="Topic path")
65+
topic_parser.add_argument("--topic-consumer", default="slo_consumer", type=str, help="Topic consumer name")
66+
topic_parser.add_argument("--topic-message-size", default=100, type=int, help="Topic message size in bytes")
67+
topic_parser.add_argument("--topic-min-partitions", default=1, type=int, help="Minimum active partitions")
68+
topic_parser.add_argument("--topic-max-partitions", default=10, type=int, help="Maximum active partitions")
69+
topic_parser.add_argument("--topic-retention-hours", default=24, type=int, help="Retention period in hours")
70+
71+
topic_parser.add_argument("--time", default=60, type=int, help="Time to run in seconds")
72+
topic_parser.add_argument("--shutdown-time", default=10, type=int, help="Graceful shutdown time in seconds")
73+
topic_parser.add_argument("--prom-pgw", default="", type=str, help="Prometheus push gateway (empty to disable)")
74+
topic_parser.add_argument("--report-period", default=1000, type=int, help="Prometheus push period in [ms]")
75+
76+
77+
def make_topic_create_parser(subparsers):
78+
"""Создает парсер для команды topic-create"""
79+
topic_create_parser = subparsers.add_parser("topic-create", help="Create topic with consumer")
80+
add_common_options(topic_create_parser)
81+
82+
topic_create_parser.add_argument("--topic-path", default="/local/slo_topic", type=str, help="Topic path")
83+
topic_create_parser.add_argument("--topic-consumer", default="slo_consumer", type=str, help="Topic consumer name")
84+
topic_create_parser.add_argument("--topic-min-partitions", default=1, type=int, help="Minimum active partitions")
85+
topic_create_parser.add_argument("--topic-max-partitions", default=10, type=int, help="Maximum active partitions")
86+
topic_create_parser.add_argument("--topic-retention-hours", default=24, type=int, help="Retention period in hours")
87+
88+
89+
def make_table_cleanup_parser(subparsers):
90+
table_cleanup_parser = subparsers.add_parser("table-cleanup", help="Drop tables")
91+
add_common_options(table_cleanup_parser)
92+
93+
94+
def make_topic_cleanup_parser(subparsers):
95+
"""Создает парсер для команды topic-cleanup"""
96+
topic_cleanup_parser = subparsers.add_parser("topic-cleanup", help="Drop topic")
97+
add_common_options(topic_cleanup_parser)
98+
99+
topic_cleanup_parser.add_argument("--topic-path", default="/local/slo_topic", type=str, help="Topic path")
56100

57101

58102
def get_root_parser():
@@ -67,9 +111,12 @@ def get_root_parser():
67111
help="List of subcommands",
68112
)
69113

70-
make_create_parser(subparsers)
71-
make_run_parser(subparsers)
72-
make_cleanup_parser(subparsers)
114+
make_table_create_parser(subparsers)
115+
make_table_run_parser(subparsers)
116+
make_table_cleanup_parser(subparsers)
117+
make_topic_create_parser(subparsers)
118+
make_topic_run_parser(subparsers)
119+
make_topic_cleanup_parser(subparsers)
73120

74121
return parser
75122

0 commit comments

Comments
 (0)