Как вы проектируете RAG для 10k RPS с P99 latency <200ms? Архитектура.

Краткий тезис

Проектирование RAG-системы на 10 000 запросов в секунду с задержкой P99 менее 200 мс требует распределённой многослойной архитектуры. Ключевые элементы: multi-region deployment для географической близости, semantic cache на Redis для горячих запросов, кластер Qdrant с replicas|read replicas для быстрого поиска, vLLM с batching|continuous batching для эффективного инференса на 8x H100, глобальный балансировщик с consistent hashing по user_id и автомасштабирование LLM реплик по GPU utilization. Такая архитектура позволяет выдерживать пиковую нагрузку при соблюдении жёсткого SLA по latency.

1. Термины и требования

RPS (Requests Per Second) — количество запросов, которое система обрабатывает за секунду. 10k RPS — это высокая нагрузка, характерная для крупных продуктов (поиск, чат-боты с миллионами пользователей).

P99 latency — задержка, которую не превышают 99% запросов. Если P99 < 200 мс, это означает, что лишь 1% запросов может быть медленнее 200 мс. Такой SLA типичен для real-time приложений.

RAG pipeline состоит из этапов: приём запроса → кэш (опционально) → retrieval из векторной БД → формирование промпта → генерация ответа LLM → постобработка. Каждый этап вносит свою задержку. Для достижения P99 < 200 мс необходимо уложить latency каждого этапа в бюджет.

ЭтапТипичная latencyЦель для 200ms
Сетевое взаимодействие1-5 ms< 10 ms
Semantic cache lookup< 1 ms< 5 ms
Retrieval (Qdrant)5-20 ms< 30 ms
LLM inference (vLLM)50-150 ms< 150 ms
Постобработка< 1 ms< 5 ms
Итого< 200 ms

2. Multi-region deployment и глобальная балансировка

Размещаем инфраструктуру в нескольких регионах: us-east, eu-west, ap-southeast. Это снижает сетевую задержку для пользователей из разных частей света. Используем глобальный балансировщик нагрузки (например, AWS Global Accelerator или Cloudflare) с consistent hashing по user_id. Consistent hashing гарантирует, что запросы одного пользователя попадают в один и тот же регион и на одни и те же кэш/БД ноды, что повышает cache hit ratio и упрощает управление состоянием.

Термин: Consistent hashing — метод распределения запросов, при котором добавление или удаление сервера затрагивает минимальное количество ключей. В нашем случае ключ — user_id, что обеспечивает стабильность маршрутизации.

3. Semantic cache (Redis)

Semantic cache хранит ответы на часто задаваемые вопросы. В отличие от обычного кэша по точному совпадению, semantic cache использует эмбеддинги запроса и ищет семантически похожие. Если найден похожий запрос с высокой косинусной близостью (порог 0.95), возвращаем закэшированный ответ, минуя retrieval и LLM.

Реализация: Redis с модулем RediSearch для векторного поиска. Храним пары (эмбеддинг запроса, ответ). Для каждого входящего запроса вычисляем эмбеддинг (можно лёгкой моделью, например, all-MiniLM-L6-v2) и ищем top-1 в Redis. Если similarity > threshold, возвращаем ответ.

Cache hit ratio для горячих запросов может достигать 30-50%, что существенно снижает нагрузку на retrieval и LLM.

4. Векторная БД: Qdrant cluster с read replicas

Для retrieval используем Qdrant — высокопроизводительную векторную БД с поддержкой шардирования и репликации. Разворачиваем кластер из 3+ нод с read replicas. Write-ноды принимают обновления индекса, read replicas обслуживают запросы на чтение. Это позволяет горизонтально масштабировать retrieval.

Шардирование по user_id или по типу контента. Каждый шард хранит часть векторов. Балансировка запросов между read replicas через внутренний балансировщик (например, HAProxy или встроенный Qdrant).

Для latency < 30 ms используем HNSW (Hierarchical Navigable Small World) индекс с параметрами: ef_construct=200, M=16. Это даёт высокую скорость поиска при небольшой потере точности.

5. LLM инференс: vLLM с continuous batching

Для генерации ответа используем vLLM — библиотеку для эффективного инференса LLM. Continuous batching позволяет обрабатывать несколько запросов параллельно на одном GPU, динамически формируя батчи. Это увеличивает throughput и снижает latency.

Разворачиваем 8x H100 (NVIDIA H100 Tensor Core GPU) с 80GB памяти каждая. Этого достаточно для модели размером 70B параметров (например, Llama-3-70B) в 4-bit квантизации (GPTQ или AWQ). vLLM поддерживает PagedAttention для эффективного управления KV-кэшем, что снижает потребление памяти.

Latency budget для LLM: 150 мс. При continuous batching и оптимизациях (flash attention, tensor parallelism) можно достичь latency 100-120 мс для batch size 8-16.

6. Consistent hashing для балансировки LLM реплик

Для распределения запросов между репликами LLM используем consistent hashing по user_id. Это гарантирует, что запросы одного пользователя попадают на одну и ту же реплику, что улучшает cache hit для KV-кэша (vLLM поддерживает prefix caching). Также это упрощает мониторинг и дебаггинг.

Пример реализации на Python (упрощённо):

import hashlib

class ConsistentHashRing:
    def __init__(self, nodes, replicas=100):
        self.replicas = replicas
        self.ring = {}
        self.sorted_keys = []
        for node in nodes:
            for i in range(replicas):
                key = self._hash(f"{node}:{i}")
                self.ring[key] = node
                self.sorted_keys.append(key)
        self.sorted_keys.sort()

    def _hash(self, key):
        return int(hashlib.md5(key.encode()).hexdigest(), 16)

    def get_node(self, user_id):
        if not self.ring:
            return None
        hash_val = self._hash(str(user_id))
        for key in self.sorted_keys:
            if hash_val <= key:
                return self.ring[key]
        return self.ring[self.sorted_keys[0]]

7. Автомасштабирование LLM реплик

Мониторим GPU utilization каждой реплики. Если средняя загрузка GPU превышает 70% в течение 5 минут, добавляем новую реплику. Если падает ниже 30% — удаляем. Используем Kubernetes HPA (Horizontal Pod Autoscaler) с кастомными метриками от Prometheus.

Термин: GPU utilization — процент времени, когда GPU занят вычислениями. Высокая утилизация (80-90%) оптимальна для throughput, но для low latency лучше держать 50-70%, чтобы оставался запас для пиков.

8. Предсказание ресурсов

Для планирования инфраструктуры оцениваем необходимые ресурсы:

  • GPU: 8x H100. Одна H100 может обрабатывать ~1500 RPS для модели 70B (с continuous batching). Для 10k RPS нужно 7-8 GPU. С запасом — 8.
  • Memory: 512 GB RAM для серверов приложений, Redis, Qdrant. Qdrant хранит векторы в RAM для быстрого доступа. Для 10M векторов размером 768 dim (float32) нужно ~30 GB. С индексами и репликами — 100 GB.
  • Storage: 2 TB NVMe SSD для логов, чекпоинтов моделей, временных данных.

9. Мониторинг и алертинг

Критические метрики:

Настраиваем алерты: если P99 latency > 200 ms в течение 1 минуты — эскалация. Используем Prometheus + Grafana для дашбордов.

Пет-проект для закрепления

Задача: Спроектировать и развернуть прототип RAG-системы на 1000 RPS с P99 < 300 ms (упрощённо) с использованием Terraform, Kubernetes, Qdrant, Redis, vLLM.

Инструменты:

  • Terraform для provisioning облачных ресурсов (AWS EKS, RDS для метаданных)
  • Kubernetes (EKS) для оркестрации микросервисов
  • Qdrant Operator для развертывания кластера
  • Redis Enterprise или OSS с модулем RediSearch
  • vLLM с Docker образом
  • Locust для нагрузочного тестирования

Шаги:

  1. Развернуть Kubernetes кластер в одном регионе.
  2. Установить Qdrant cluster (3 ноды) и Redis.
  3. Развернуть vLLM с моделью (например, Llama-3-8B для тестов).
  4. Написать сервис-оркестратор (FastAPI), который принимает запросы, проверяет кэш, вызывает retrieval и LLM.
  5. Настроить HPA для vLLM по GPU utilization.
  6. Запустить Locust с 1000 concurrent users и измерить P99 latency.
  7. Оптимизировать параметры (batch size, threshold кэша, количество реплик).

Ожидаемый результат: Работающая система, выдерживающая 1000 RPS с P99 < 300 ms. Дашборд Grafana с метриками.

Связь с другими вопросами

ВопросТема
7Как вы уменьшаете latency RAG-системы (время ответа)?
8Как вы используете кэширование в RAG?
12Как вы масштабируете векторную БД?
15Как вы деплоите LLM для инференса?
20Как вы проектируете multi-region RAG?
30Как вы настраиваете автомасштабирование?

Навигация