Общие сведения
Надёжность и безопасность
Покупка лицензии
Начало работы
Роли в системе
Проекты
Концепции
Компоненты
Инструкции
Задачи
Финансы
Ресурсы
Таймшиты
Клиенты
Вики
Затраты
Отчёты и аналитика
FAQ
Типы отчётов
Тип отчёта «Акты»
Тип отчёта «Баланс отсутствий»
Тип отчёта «Бронирование»
Тип отчёта «Биллинг»
Тип отчёта «Версии проектов»
Тип отчёта «Задачи»
Тип отчёта «Задачи проектов»
Тип отчёта «Затраты»
Тип отчёта «Заявки на затраты»
Тип отчёта «Заявки на отсутствия»
Тип отчёта «История ставок пользователей»
Тип отчёта «Запросы ресурсов»
Тип отчёта «Навыки пользователей»
Тип отчёта «Пользователи»
Тип отчёта «Проводки»
Тип отчёта «Ресурсный план»
Тип отчёта «Ресурсный план (по версиям)»
Тип отчёта «Проекты»
Тип отчёта «Сертификаты пользователей»
Тип отчёта «Счета»
Тип отчёта «Счета (строки)»
Тип отчёта «Таймшиты»
Тип отчёта «Таймшиты детально»
Тип отчёта «Финансы»
Тип отчёта «Структура работ»
Тип отчёта «Центры затрат проектов»
Тип отчёта «Задания воркфлоу»
Тип отчета Клиенты
Тип отчета «Контакты»
Тип отчёта «Сделки»
Тип отчёта «История состояний сделок»
Тип отчёта «Взаимодействия»
Использование отчётов
Группировка данных источника
Группировка данных в отчёте
Типы виджетов
Общие отчёты и шаблоны
Настройка отчёта
Экспорт отчётов
Пользовательские настройки отчёта
Вычисляемые поля
Особые колонки отчётов с временными рядами
Использование панелей мониторинга
Публикация панелей
Фильтры источников данных
Настройка и администрирование
Типовой порядок настройки системы
Язык формул и выражений
On-premises
API
История изменений
Термины и определения

Методика нагрузочного тестирования Timetta с использованием JMeter

Обновлено: 01.12.2025

1. Цель

Методика предназначена для проверки производительности и устойчивости системы Timetta при работе с целевым профилем нагрузки, характерным для облачной версии приложения. Тестирование направлено на:

  • проверку отклика сервисов под нагрузкой;
  • оценку потребности в соединениях с базой данных и брокерами сообщений;
  • выявление узких мест и возможности масштабирования системы.

2. Вводные данные и профиль использования

2.1 Основные параметры системы

Параметр Значение
Максимальное число зарегистрированных пользователей 20 000
Среда развертывания Kubernetes-кластер с выделенными нодами (Node Selector / Node Affinity)
PostgreSQL Отказоустойчивый кластер Postgres Pro на отдельной ВМ
Redis Кластер на отдельной ВМ
RabbitMQ Кластер на отдельной ВМ
Сервисы Настроены с отказоустойчивостью и автоматическим failover

2.2 Профиль нагрузки

  • Коэффициент ежедневной активности (DAU/MAU): 40–50% → ~10 000 активных пользователей в день.
  • Пиковая часовая активность: 30% дневных пользователей в самый загруженный час (10:00–11:00) → ~3 330 пользователей.
  • Коэффициент одновременности: 10–15% → верхний предел одновременных пользователей ~495.

2.3 Оценка соединений с PostgreSQL

  • Пиковый показатель TPS: ~2 800 операций/сек.
  • Среднее время выполнения запроса: 250 мс, плюс 250 мс на ожидание освобождения соединения.
  • Запас на потерянные соединения: +30%
  • Запас на служебные соединения: +30
  • Итого одновременных соединений: ~1 850

3. Подготовка к тестированию

  1. Установить Apache JMeter (версии 5.6+ рекомендуется).
  2. Создать отдельный тестовый план, включая Thread Group с числом потоков, соответствующим расчетной одновременной нагрузке (~500 пользователей).
  3. Настроить HTTP Request Defaults для базового URL приложения.
  4. Настроить HTTP Header Manager с авторизацией по ApiToken.
  5. Добавить Listeners для сбора метрик (Graph Results, Summary Report, Backend Listener для Prometheus/Grafana).

4. Сценарии запросов

В тестовом плане рекомендуется создать отдельные HTTP Request Sampler для каждого из ключевых запросов. Ниже приведены целевые эндпоинты и предполагаемое количество обращений в рамках тестового цикла:

Endpoint Метод Примерное количество вызовов
/odata/TimeAllocations POST 348
/odata/Projects(id)/UpdateResourcePlan POST 31
/odata/GetClientProfile(clientType='web') GET 187
/odata/GetEntityTypes GET 187
/odata/GetNavigationItems GET 187
/odata/Notifications? $apply=filter(read eq false)/aggregate(id with countdistinct as count) GET 222
/odata/Notifications? $top=50& $orderby=created desc GET 198
/odata/GetSession? $expand=configuration/metamodel/entities GET 196
/odata/GetIndicators GET 193
/odata/StartUndoRedo POST 44
/odata/TimeSheetLines POST 108
/odata/AbortUndoRedo POST 34
/odata/ProjectTasks(id) PATCH 6
/odata/ExtendedTimeSheets? $apply=filter((timeSheet/state/code eq 'Draft' and timeSheet/dueDate lt 01.12.2025))/aggregate($count as count) GET 55
/odata/Projects(id)/UpdateResourcePlan POST 5

Примечание: числа вызовов ориентировочные, используются для моделирования нагрузки в JMeter Thread Group.

5. Настройка нагрузки в JMeter

  1. Thread Group (Группа потоков):

    • Количество потоков: 495 (одновременных пользователей).
    • Ramp-Up Period: 300–600 сек для плавного выхода на пик.
    • Loop Count: 1–10 (в зависимости от продолжительности теста).
  2. HTTP Request Defaults:

    • Протокол: HTTPS
    • Сервер: <base_url>
    • Port: 443
  3. HTTP Header Manager:

    • Authorization: ApiToken <token>
    • Content-Type: application/json (для POST/PATCH запросов)
  4. Timers:

    • Использовать Constant Timer / Gaussian Random Timer для имитации реального пользовательского поведения.
  5. Listeners:

    • Summary Report для анализа TPS, среднего времени отклика и ошибок.
    • Graph Results для визуализации нагрузки.
    • Backend Listener для передачи метрик в систему мониторинга (Prometheus/Grafana).

6. Метрики и критерии успешного теста

  • Среднее время отклика: < 500 мс для большинства GET-запросов, < 1 сек для POST/PATCH.
  • Процент ошибок: < 1% (HTTP 5xx / timeout).
  • TPS: соответствует ожидаемой нагрузке (до 2 800 TPS в пике).
  • Использование соединений с PostgreSQL: не превышает рассчитанные 1 850 одновременных соединений.
  • Нагрузка на Redis и RabbitMQ: стабильная без ошибок подключения и переполнения очередей.

7. Рекомендации

  1. Перед нагрузочным тестированием убедиться, что все сервисы запущены в отказоустойчивом режиме и настроен failover.
  2. Проводить тестирование в тестовой среде, идентичной продакшену по ресурсам.
  3. Повторять тестирование с разными сценариями и интенсивностью для выявления узких мест.
  4. После теста анализировать логи сервисов, баз данных и брокеров сообщений.
  5. В случае превышения допустимой нагрузки корректировать масштабирование нод, пул соединений и ресурсы кластеров.

Вот обновлённый пункт, с учётом твоих условий: 4 ноды Kubernetes и 1 реплика PostgreSQL, без HA для остальных компонентов, только для нагрузочного тестирования.

8. Требования к оборудованию для нагрузочного тестирования

Для проведения нагрузочного тестирования Timetta выделяется минимальный набор ресурсов, достаточный для эмуляции целевого профиля нагрузки.

Роль Кол-во vCPU (Intel Ice Lake, 100%) RAM SSD (IOPS) Макс. bandwidth (чтение / запись)
Нода кластера K8s 4 8 32 GB 300 GB, ≥10k IOPS 150 МБ/с
PostgreSQL Primary VM 1 12 64 GB 500 GB, ≥15k IOPS 200 МБ/с
PostgreSQL Replica VM 1 12 64 GB 500 GB, ≥15k IOPS 200 МБ/с
Redis VM 1 4 8 GB 50–100 GB SSD 150 МБ/с
RabbitMQ VM 1 4 8 GB 200 GB, ≥10k IOPS 150 МБ/с
Клиент JMeter (нагрузка) 1 8 16 GB 100 GB 150 МБ/с

9. Конфигурация тест-плана


<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Timetta Load Test Plan" enabled="true">
      <stringProp name="TestPlan.comments">Нагрузочный тест для Timetta с профилем нагрузки облачной версии</stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments">
        <collectionProp name="Arguments.arguments">
          <elementProp name="base_url" elementType="Argument">
            <stringProp name="Argument.name">base_url</stringProp>
            <stringProp name="Argument.value">https://your-timetta-domain.com</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="api_token" elementType="Argument">
            <stringProp name="Argument.name">api_token</stringProp>
            <stringProp name="Argument.value">YOUR_API_TOKEN</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
        </collectionProp>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Timetta Users Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">495</stringProp>
        <stringProp name="ThreadGroup.ramp_time">300</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
      </ThreadGroup>
      <hashTree>
        <ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${base_url}</stringProp>
          <stringProp name="HTTPSampler.port"></stringProp>
          <stringProp name="HTTPSampler.protocol">https</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path"></stringProp>
          <stringProp name="HTTPSampler.concurrentPool">6</stringProp>
        </ConfigTestElement>
        <hashTree/>
        <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
          <collectionProp name="HeaderManager.headers">
            <elementProp name="Authorization" elementType="Header">
              <stringProp name="Header.name">Authorization</stringProp>
              <stringProp name="Header.value">ApiToken ${api_token}</stringProp>
            </elementProp>
            <elementProp name="Content-Type" elementType="Header">
              <stringProp name="Header.name">Content-Type</stringProp>
              <stringProp name="Header.value">application/json</stringProp>
            </elementProp>
          </collectionProp>
        </HeaderManager>
        <hashTree/>
        <!-- Пример HTTP Request Sampler -->
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="/odata/TimeAllocations POST" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain"></stringProp>
          <stringProp name="HTTPSampler.port"></stringProp>
          <stringProp name="HTTPSampler.protocol"></stringProp>
          <stringProp name="HTTPSampler.path">/odata/TimeAllocations</stringProp>
          <stringProp name="HTTPSampler.method">POST</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
        <!-- Timer для имитации реального поведения пользователя -->
        <ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Think Time Timer" enabled="true">
          <stringProp name="ConstantTimer.delay">500</stringProp>
        </ConstantTimer>
        <hashTree/>
        <!-- Listener -->
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>true</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

Предыдущая
 Сайзинг

Содержание

1. Цель 2. Вводные данные и профиль использования 2.1 Основные параметры системы 2.2 Профиль нагрузки 2.3 Оценка соединений с PostgreSQL 3. Подготовка к тестированию 4. Сценарии запросов 5. Настройка нагрузки в JMeter 6. Метрики и критерии успешного теста 7. Рекомендации 8. Требования к оборудованию для нагрузочного тестирования 9. Конфигурация тест-плана
Ничего не найдено

Перейти на русскую версию?