Перейти к основному содержимому

Бенчмарки

Синтетические данные

Методология

Мы подготовили набор бенчмарков, которые постарались сделать максимально воспроизводимыми и детерминированными. Датасет, который использовался во время бенчмарков, детерминирован и состоит из 40 гигабайт (219 млн) структурированных логов в формате json. Пример лога:

{
"@timestamp": 897484581,
"clientip": "162.146.3.0",
"request": "GET /images/logo_cfo.gif HTTP/1.1",
"status": 200,
"size": 1504
}

Тесты запускались на AWS хосте c6a.4xlarge, который имеет следующую конфигурацию:

CPURAMDisk
AMD EPYC 7R13 Processor 3.6 GHz, 16 vCPU32 GiBGP3

Более подробно ознакомиться с тем, какие компоненты участвую в данном сьюте, какие настройки компонентов были выставлены и как его запускать, вы можете тут.

Ниже представлена информация о конфигурации локального кластера:

ContainerReplicasCPU LimitRAM Limit
seq-db (--mode single)148 GiB
elasticsearch148 GiB
file.d1-12 GiB

Результаты (write-path)

На синтетических тестах у нас получились следующие числа:

ContainerAverage Logs Per SecondAverage ThroughputAverage CPU UsageAverage RAM Usage
seq-db370_00048 MiB/s3.31.8 GiB
elasticsearch110_00014 MiB/s1.92.4 GiB

Отсюда видно, что при сопоставимых значений используемых ресурсов, seq-db показала пропускную способность, которая в среднем 3.4 раз выше, чем пропускная способность у Elasticsearch.

Результаты (read-path)

В оба хранилища был предварительно загружен одинаковый датасет (формат см выще). Тесты read-path запускались без нагрузки на запись.

Важные замечания по настройкам запросов в elasticsearch:

  • был отключен кеш запросов (request_cache=false)
  • был отключен подсчёт total hits (track_total_hits=false)

Тесты проводились при помощи утилиты Grafana k6, параметры запросов указаны в каждом из сценариев, а также доступны в папке benchmarks/k6.

Сценарий: поиск всех логов с оффсетами

В Elasticsearch в конфигурации по умолчанию ограничивает page_size*offset <= 10.000.

Параметры: запросы параллельно с 20 потоков в течение 10 секунд. Выбирается и подгружается случайная страница [1–50].

DBAvgP50P95
seq-db5.56ms5.05ms9.56ms
elasticsearch6.06ms5.11ms11.8ms

Сценарий status: in(500,400,403)

Параметры: 20 looping VUs for 10s

DBAvgP50P95
seq-db364.68ms356.96ms472.26ms
elasticsearch21.68ms18.91ms29.84ms

Сценарий request: GET /english/images/top_stories.gif HTTP/1.0

Параметры: 20 looping VUs for 10s

DBAvgP50P95
seq-db269.98ms213.43ms704.19ms
elasticsearch46.65ms43.27ms80.53ms

Сценарий: агрегация с подсчётом кол-ва логов с определённым статусом

Написан запрос c таким sql аналогом: SELECT status, COUNT(*) GROUP BY status.

Параметры: 10 запросов параллельно с 2 потоков.

DBAvgP50P95
seq-db16.81s16.88s16.10s
elasticsearch6.46s6.44s6.57s

Сценарий: минимальный размер лога каждого статуса

SQL-аналог: SELECT status, MIN(size) GROUP BY status.

Параметры: 5 итераций с 1 потока.

DBAvgP50P95
seq-db33.34s33.41s33.93s
elasticsearch16.88s16.82s17.5s

Сценарий : range запросы - выборка из 5000 документов

Параметры: 20 потоков, 10 секунд.

Выбирается случайная страница [1-50], на каждой странице по 100 документов.

DBAvgP50P95
seq-db406.09ms385.13ms509.05ms
elasticsearch22.75ms18.06ms64.61ms

Реальные (production) данные

Методология

Помимо синтетических тестов, нам также необходимо было проверить, как seq-db и Elasticsearch показывают себя на реальных данных - логах, которые собираются со всех наших production сервисов. Мы подготовили несколько сценариев бенчмарков, которые показывают перформанс характеристики в рамках одного инстанса и в рамках среднего по размеру по кластера:

  • Тестирование пропускной способности одного инстанса seq-db и Elasticsearch (Конфигурация 1x1);
  • Тестирование пропускной способности 6 инстансов seq-db и Elasticsearch с RF=2 (Конфигурация 6x6);

Также для всех тестов мы заранее подготовили датасеты, которые были собраны из production логов, и произвели над ними все необходимые трансформации, чтобы минимизировать потребление CPU при непосредственной транспортировки логов из file.d в seq-db или Elasticsearch. Суммарный размер датасета равен 280 GiB.

Таким образом мы получили:

  • Детерминированность в рамках датасета;
  • Избавление от внешних зависимостей для доставки логов до file.d (конкретно в нашем случае - Apache Kafka);

Верхнеуровнево схема записи выглядит следующим образом:

┌──────────────┐        ┌───────────┐  
│ ┌──────┐ │ │ │
│ │ file ├──┐ │ ┌──►│ elastic │
│ └──────┘ │ │ │ │ │
│ ┌─────────▼┐ │ │ └───────────┘
│ │ ├─┼────┘ ┌───────────┐
│ │ file.d │ │ │ │
│ │ ├─┼───────►│ seq-db │
│ └──────────┘ │ │ │
└──────────────┘ └───────────┘

Ниже представлена информация о конфигурации кластера:

ContainerCPURAMDisk
seq-db (--mode store)Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHzDDR4 3200 MHzRAID 10 4x SSD MZILT7T6HALA/007
seq-db (--mode ingestor)Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHzDDR4 3200 MHz-
elasticsearch (master)Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHzDDR4 3200 MHzRAID 10 4x SSD MZILT7T6HALA/007
elasticsearch (data)Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHzDDR4 3200 MHzRAID 10 4x SSD MZILT7T6HALA/007
file.dIntel(R) Xeon(R) Gold 6240R CPU @ 2.40GHzDDR4 3200 MHz-

Далее мы выделили базовый набор полей, которые мы будем индексировать. Так как Elasticsearch по умолчанию индексирует все поля, мы создали индекс k8s-logs-index, который индексирует только ранее выбранное нами множество полей.

Конфигурация 1x1

В данной конфигурации использовались следующие настройки индексов:

curl -X PUT "http://localhost:9200/k8s-logs-index/" -H 'Content-Type: application/json' -d'
{
"settings": {
"index": { "codec": "best_compression" },
"number_of_replicas": 0,
"number_of_shards": 6,
},
"mappings": {
"dynamic": "false",
"properties": {
"k8s_cluster": { "type": "keyword" },
"k8s_container": { "type": "keyword" },
"k8s_group": { "type": "keyword" },
"k8s_label_jobid": { "type": "keyword" },
"k8s_namespace": { "type": "keyword" },
"k8s_node": { "type": "keyword" },
"k8s_pod": { "type": "keyword" },
"k8s_pod_label_cron": { "type": "keyword" },
"client_ip": { "type": "keyword" },
"http_code": { "type": "integer" },
"http_method": { "type": "keyword" },
"message": { "type": "text" }
}
}
}'

Ровно такую же конфигурацию индексирования и репликации мы задали и для seq-db.

Результат
ContainerCPU LimitRAM LimitAverage CPU UsageAverage RAM Usage
seq-db (--mode store)816 GiB6.57 GiB
seq-db (--mode proxy)88 GiB73 GiB
elasticsearch (master)24 GiB00 GiB
elasticsearch (data)1632 GiB15.830 GiB
ContainerAverage ThroughputAverage Logs Per Second
seq-db520 MiB/s162_000
elasticsearch195 MiB/s62_000

Отсюда видно, что при сопоставимых значений используемых ресурсов, seq-db показала пропускную способность, которая в среднем 2.6 раза выше, чем пропускная способность у Elasticsearch.

Конфигурация 6x6

Для данной конфигурации было поднято 6 нод seq-db в режиме --mode proxy и 6 нод в режиме --mode store.

Настройки индексов сохранились такими же, за исключением number_of_replicas=1:

curl -X PUT "http://localhost:9200/k8s-logs-index/" -H 'Content-Type: application/json' -d'
{
"settings": {
"index": { "codec": "best_compression" },
"number_of_replicas": 1,
"number_of_shards": 6,
},
"mappings": {
"dynamic": "false",
"properties": {
"k8s_cluster": { "type": "keyword" },
"k8s_container": { "type": "keyword" },
"k8s_group": { "type": "keyword" },
"k8s_label_jobid": { "type": "keyword" },
"k8s_namespace": { "type": "keyword" },
"k8s_node": { "type": "keyword" },
"k8s_pod": { "type": "keyword" },
"k8s_pod_label_cron": { "type": "keyword" },
"client_ip": { "type": "keyword" },
"http_code": { "type": "integer" },
"http_method": { "type": "keyword" },
"message": { "type": "text" }
}
}
}'

Также твикали index.merge.scheduler.max_thread_count, при уменьшении увеличивалась пропускная способность. Ровно такую же конфигурацию индексирования и репликации мы задали и для seq-db.

Результат
ContainerCPU LimitRAM LimitReplicasAverage CPU Usage (per instance)Average RAM Usage (per instance)
seq-db (--mode proxy)58 GiB63.61.5 GiB
seq-db (--mode store)816 GiB66.16.3 GiB
elasticsearch (data)1332 GiB64.513 GIB
ContainerAverage ThroughputAverage Logs Per Second
seq-db1.3 GiB/s585,139 docs/sec
elasticsearch113.58 MiB/s37,658 docs/sec