Реализация симуляции реального трафика для нагрузочного тестирования

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация симуляции реального трафика для нагрузочного тестирования
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Симуляция реального трафика в нагрузочном тестировании

Равномерный трафик 100 VU — не то, что происходит в реальности. Реальный трафик: утренние и вечерние пики, разные типы пользователей (браузеры/мобильные/API), сессионное поведение, случайные паузы, распределение Парето. Реалистичная симуляция выявляет проблемы, которые пропускают синтетические тесты.

Анализ реального трафика как основа теста

# Извлечь паттерны из nginx access log
import re
from collections import Counter, defaultdict
import json

def analyze_access_log(log_file: str):
    pattern = re.compile(
        r'(?P<ip>\S+) .+ \[(?P<time>[^\]]+)\] '
        r'"(?P<method>\w+) (?P<path>[^"]+) HTTP/\d+" '
        r'(?P<status>\d+) (?P<bytes>\d+)'
    )

    endpoint_counts = Counter()
    method_counts = Counter()
    hourly_traffic = defaultdict(int)

    with open(log_file) as f:
        for line in f:
            m = pattern.match(line)
            if not m:
                continue

            # Нормализовать path (убрать ID)
            path = re.sub(r'/\d+', '/{id}', m.group('path').split('?')[0])
            endpoint_counts[f"{m.group('method')} {path}"] += 1
            method_counts[m.group('method')] += 1

            # Почасовое распределение
            hour = m.group('time').split(':')[1]
            hourly_traffic[hour] += 1

    total = sum(endpoint_counts.values())

    print("=== Top Endpoints (% of traffic) ===")
    for endpoint, count in endpoint_counts.most_common(20):
        pct = count / total * 100
        print(f"  {pct:.1f}% {endpoint}")

    print("\n=== Hourly Distribution ===")
    for hour in sorted(hourly_traffic):
        bar = '█' * (hourly_traffic[hour] // 100)
        print(f"  {hour}:00 {bar} {hourly_traffic[hour]}")

    # Экспорт для k6 сценария
    weights = {ep: round(cnt/total, 3) for ep, cnt in endpoint_counts.most_common(20)}
    return weights

k6 сценарий с реалистичным поведением

// tests/realistic/user-journey.js
import http from 'k6/http'
import { check, sleep } from 'k6'
import { SharedArray } from 'k6/data'
import { randomItem, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'

// Загрузить тестовые данные из CSV
const users = new SharedArray('users', function() {
  return open('./data/test-users.csv').split('\n')
    .slice(1)
    .map(row => {
      const [email, token, userId] = row.split(',')
      return { email, token, userId }
    })
})

const searchTerms = new SharedArray('searches', function() {
  return open('./data/popular-searches.txt').split('\n').filter(Boolean)
})

export const options = {
  scenarios: {
    // Анонимные браузеры (40% трафика)
    anonymous_browse: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '5m', target: 40 },
        { duration: '30m', target: 40 },
        { duration: '5m', target: 0 }
      ],
      exec: 'anonymousBrowse'
    },

    // Авторизованные пользователи (50% трафика)
    logged_in_users: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '5m', target: 50 },
        { duration: '30m', target: 50 },
        { duration: '5m', target: 0 }
      ],
      exec: 'loggedInJourney'
    },

    // API-клиенты (10% трафика)
    api_clients: {
      executor: 'constant-arrival-rate',
      rate: 10,
      timeUnit: '1s',
      duration: '40m',
      preAllocatedVUs: 20,
      exec: 'apiClient'
    }
  },

  thresholds: {
    http_req_duration: ['p(95)<800'],
    http_req_failed: ['rate<0.01'],
  }
}

const BASE = __ENV.BASE_URL || 'https://staging.example.com'

// Сценарий: анонимный браузер
export function anonymousBrowse() {
  // Лендинг → каталог → товар → выход
  http.get(`${BASE}/`)
  sleep(randomIntBetween(1, 4))

  const category = randomItem(['electronics', 'clothing', 'books', 'sports'])
  http.get(`${BASE}/api/products?category=${category}&limit=20`)
  sleep(randomIntBetween(2, 8))

  // 30% уходят сразу, 70% смотрят товар
  if (Math.random() > 0.3) {
    const productId = randomIntBetween(1, 500)
    http.get(`${BASE}/api/products/${productId}`)
    sleep(randomIntBetween(3, 15))
  }

  // 20% делают поиск
  if (Math.random() < 0.2) {
    const term = randomItem(searchTerms)
    http.get(`${BASE}/api/search?q=${encodeURIComponent(term)}`)
    sleep(randomIntBetween(1, 5))
  }
}

// Сценарий: авторизованный пользователь
export function loggedInJourney() {
  const user = randomItem(users)
  const headers = {
    'Authorization': `Bearer ${user.token}`,
    'Content-Type': 'application/json'
  }

  // Профиль
  http.get(`${BASE}/api/me`, { headers })
  sleep(randomIntBetween(1, 3))

  // Просмотр товаров
  for (let i = 0; i < randomIntBetween(2, 8); i++) {
    const productId = randomIntBetween(1, 500)
    http.get(`${BASE}/api/products/${productId}`, { headers })
    sleep(randomIntBetween(2, 10))
  }

  // 40% добавляют в корзину
  if (Math.random() < 0.4) {
    http.post(`${BASE}/api/cart/items`, JSON.stringify({
      productId: randomIntBetween(1, 500),
      quantity: randomIntBetween(1, 3)
    }), { headers })
    sleep(randomIntBetween(1, 3))

    // 60% из добавивших — оформляют заказ
    if (Math.random() < 0.6) {
      http.get(`${BASE}/api/cart`, { headers })
      sleep(randomIntBetween(2, 5))

      const checkout = http.post(`${BASE}/api/orders`, JSON.stringify({
        paymentMethod: 'saved_card',
        shippingAddressId: 1
      }), { headers })
      check(checkout, { 'order created': (r) => r.status === 201 })
    }
  }
}

// Сценарий: API-клиент (интеграция)
export function apiClient() {
  const apiKey = __ENV.API_KEY
  const headers = {
    'X-API-Key': apiKey,
    'Content-Type': 'application/json'
  }

  // Синхронизация продуктов
  const r = http.get(`${BASE}/api/v1/products?since=${Date.now() - 3600000}`,
    { headers })
  check(r, { 'api: 200': (r) => r.status === 200 })
}

Распределение Pareto (80/20)

Реальный трафик: 20% страниц получают 80% трафика:

// Генератор Pareto-распределения для ID
function paretoId(maxId, shape = 1.5) {
  // Power law: большинство запросов к популярным ID
  const u = Math.random()
  return Math.ceil(maxId * Math.pow(1 - u, 1 / shape))
}

// Использование
const productId = paretoId(10000)  // преимущественно ID 1-200, редко ID 9000+

Запись реального трафика для воспроизведения

# Записать реальные запросы в HAR файл через Nginx
# nginx.conf
log_format har_format escape=json
  '{"startedDateTime":"$time_iso8601",'
  '"request":{"method":"$request_method","url":"$request_uri",'
  '"headers":{"Authorization":"$http_authorization"}},'
  '"response":{"status":$status}}';

access_log /var/log/nginx/har.log har_format;

# Конвертировать в k6 сценарий
npm install -g har-to-k6
har-to-k6 nginx-har.log -o tests/recorded-traffic.js

Тепловая карта трафика по часам

# Задать профиль нагрузки по реальным данным о трафике
HOURLY_WEIGHTS = {
    0: 0.2, 1: 0.1, 2: 0.1, 3: 0.1, 4: 0.1, 5: 0.15,
    6: 0.3, 7: 0.5, 8: 0.7, 9: 0.9, 10: 1.0, 11: 1.0,
    12: 0.95, 13: 0.9, 14: 0.85, 15: 0.85, 16: 0.9, 17: 0.95,
    18: 1.0, 19: 0.95, 20: 0.9, 21: 0.75, 22: 0.5, 23: 0.35
}

BASE_VUS = 100  # VU в пиковый час

def generate_k6_stages():
    stages = []
    for hour in range(24):
        vus = int(BASE_VUS * HOURLY_WEIGHTS[hour])
        stages.append(f'{{ duration: "1h", target: {vus} }}')
    return ',\n  '.join(stages)

print(f"stages: [\n  {generate_k6_stages()}\n]")

Срок выполнения

Разработка реалистичного сценария нагрузочного теста на основе анализа реального трафика — 2–3 рабочих дня.