Все статьи
Архитектура2026-01-1412 мин

Архитектура Highload Telegram ботов: От 100 до 100k RPS

Как масштабировать бота, когда стандартный aiogram перестает справляться. Очереди Redis, шардинг базы и паттерны, которые позволяют значительно экономить на серверах.

Главное за 30 секунд

  • Aiogram + Polling - это смерть для продакшена. Переходите на Webhooks.
  • Без очереди сообщений (Redis/RabbitMQ) вы потеряете данные при первом скачке трафика.
  • PostgreSQL нужно тюнить: используйте PGBouncer и шардинг, если таблица users перевалила за 10 млн.
  • Архитектура должна быть асинхронной: Receiver (принимает вебхуки) и Worker (обрабатывает логику) - это разные микросервисы.

Классическая ситуация в Highload: маркетинговая рассылка на 50 000 пользователей в "Черную пятницу". Все нажимают кнопку «Получить скидку» одновременно. Сервер перестает отвечать, логи забиты таймаутами, а контейнеры падают от нехватки памяти.

Это типичная ошибка: архитектура строится «на вырост», но не учитывается, что пиковая нагрузка может прийти мгновенно.

В этой статье мы разберем архитектуру, которая используется в highload-проектах. Она способна держать высокие нагрузки и позволяет масштабироваться горизонтально за считанные минуты.

Бизнес-ценность правильной архитектуры

Почему владельцу бизнеса не всё равно, что там «под капотом»?

  1. Потеря лидов = Потеря денег. Если бот «тупит» 3 секунды, пользователь уходит к конкуренту.
  2. Экономия на серверах. Правильный код позволяет держать 1 млн юзеров на сервере за $50/мес, а не платить $500 за «железо», которое простаивает.
  3. Отказоустойчивость. Когда Telegram шлет дубликаты вебхуков (а он шлет!), ваша база не должна создавать дубликаты заказов.

Технический стек 2026

Забудьте про синхронный код. В 2026 году стандарт индустрии для Telegram Highload - это:

  • Язык: Python (FastAPI + Aiogram 3.x) или Go / Rust (для совсем экстремальных нагрузок)
  • Broker: Redis Stream / RabbitMQ
  • Database: PostgreSQL 16+ (с PGBouncer)
  • Storage: S3 (для медиа)
  • Deploy: Kubernetes (K8s) или Docker Swarm

Нужен аудит вашего бота?

Если ваш текущий бот падает или работает медленно - мы проведем нагрузочное тестирование и предложим план оптимизации.

Архитектура решения

Главный секрет highload - разделение ответственности. Эффективно разделять бота на два независимых слоя:

  1. Webhook Receiver: Максимально простой и быстрый сервис. Его задача - принять JSON от Telegram, кинуть его в очередь Redis и мгновенно ответить 200 OK. Время обработки < 50ms.
  2. Workers: Умные рабочие лошадки. Они берут задачи из очереди в своем темпе и делают тяжелую логику (запросы в БД, генерацию картинок, вызовы AI).

Схема потока данных

Эта схема позволяет просто добавить еще 10 контейнеров с воркерами, если нагрузка выросла, не трогая основной сервер приема вебхуков.

Реализация

1. Webhook Receiver (FastAPI)

# receiver.py
from fastapi import FastAPI, Request
from redis.asyncio import Redis
import os

app = FastAPI()
redis = Redis.from_url(os.getenv("REDIS_URL"))

@app.post(f"/webhook/{os.getenv('BOT_TOKEN')}")
async def receive_webhook(request: Request):
    # 1. Читаем сырые байты (так быстрее)
    body = await request.body()
    
    # 2. Атомарно кидаем в очередь. Никакой логики!
    # Используем Redis Stream для надежности или RPUSH для простоты
    await redis.rpush("telegram_updates", body)
    
    # 3. Мгновенный ответ Телеграму, чтобы он не слал дубликаты
    return {"ok": True}

2. Worker (Aiogram)

# worker.py
import asyncio
import json
from aiogram import Bot, Dispatcher, types
from redis.asyncio import Redis

bot = Bot(token="TOKEN")
dp = Dispatcher()

async def process_update(update_data):
    # Превращаем JSON обратно в объект Aiogram
    # В Aiogram 3.x это делается через Update.model_validate
    update = types.Update.model_validate_json(update_data)
    
    # Пропускаем через диспетчер (хендлеры, мидлвари)
    await dp.feed_update(bot, update)

async def main():
    redis = Redis.from_url("redis://localhost")
    print("Worker started")
    
    while True:
        # Блокирующее чтение из очереди
        task = await redis.blpop("telegram_updates", timeout=1)
        if not task:
            continue
            
        _, data = task
        # Запускаем обработку в фоне или ждем (зависит от стратегии)
        await process_update(data)

if __name__ == "__main__":
    asyncio.run(main())

Типичные ошибки новичков (Грабли)

  1. Long-polling в проде: Это работает на 100 людях. На 10,000 это перестает работать. Сервер Telegram просто разорвёт соединение из-за таймаутов.
  2. Синхронные запросы в БД: time.sleep или долгий SQL-запрос в хендлере блокирует весь поток. Пока один юзер ждет, 1000 других получают игнор. Используйте только asyncpg / SQLAlchemy Async.
  3. Хранение стейтов в памяти: MemoryStorage в Aiogram - это зло. При перезагрузке бота вы теряете всё: кто на каком шаге регистрации находился. Только RedisStorage.
  4. Отсутствие идемпотентности: Telegram гарантирует доставку, но не гарантирует, что доставит сообщение только 1 раз. Если вы списываете деньги - проверяйте update_id, чтобы не списать дважды за один клик.

Заключение

Highload - это не магия, это инженерный подход. Разделяйте,, изолируйте и кешируйте. Если вы на старте проекта заложите эту архитектуру, вам не придется переписывать всё с нуля через полгода, когда придет успех.

Боитесь не справиться с нагрузкой?

Мы спроектируем и внедрим отказоустойчивую архитектуру для вашего бота под SLA 99.9%. Спите спокойно, пока бот работает.

FAQ: Ответы на частые вопросы

Один воркер на Python обрабатывает ~100-300 апдейтов в секунду (зависит от логики). 10 воркеров - это уже 3000 RPS. Ограничением станет база данных, но Redis как буфер сгладит пики.

Для Telegram ботов Redis часто удобнее: он же используется как FSM Storage и Cache. Меньше инфраструктурных блоков - проще поддержка. RabbitMQ нужен, если важна гарантия доставки "хотя бы раз" и сложный роутинг.

Мы рекомендуем VPS с хорошим CPU (Hetzner, DigitalOcean) или облака (AWS, Yandex Cloud) с Kubernetes. Обычный Shared-хостинг не подойдет.


Понравилась статья?

Поделитесь ей с коллегами или обсудите с нами