ИнфраструктураHabr AI→ оригинал

Open-source LLM-шлюз KTMS 1.0 подключил свои GPU к облаку и пережил отказы

Команда Keystone выпустила версию 1.0 шлюза KTMS на Go под лицензией Apache 2.0. Шлюз стоит между приложениями и LLM-провайдерами. Теперь ему можно подключить свои машины, например Mac Studio или Linux-сервер с видеокартой, как ещё одного «вендора». Запросы идут туда в первую очередь, а облако платит только за переполнение. Каждые 5 секунд нода сообщает шлюзу свою загрузку. Если по закону Литтла ожидание в очереди выходит больше лимита модели, запрос сразу уходит дальше по цепочке, обычно в облако. Для интерактивных клиентов лимит жёстче: 250 мс. • Ключи вендоров в Postgres шифруются AES-256-GCM, ротация идёт в три шага без потери ключей. • Образы подписаны cosign без постоянного ключа, к ним приложены SBOM и SLSA-provenance. • Миграции только добавляют данные, поэтому rolling-деплой идёт без простоя. Отката нет, только восстановление из бэкапа.

AI-обработка оригинала Habr AI; редакция Hamidun News
Open-source LLM-шлюз KTMS 1.0 подключил свои GPU к облаку и пережил отказы
Источник: Habr AI. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникHabr AI ↗
Главный редактор
Ключевой факт #1Ключи вендоров в Postgres шифруются AES-256-GCM, ротация идёт в три шага без потери ключей.
Ключевой факт #2Образы подписаны cosign без постоянного ключа, к ним приложены SBOM и SLSA-provenance.
Ключевой факт #3Миграции только добавляют данные, поэтому rolling-деплой идёт без простоя. Отката нет, только восстановление из бэкапа.

KTMS (Keystone. The Model Switchboard) — открытый LLM-шлюз на Go: единая точка, через которую приложения компании ходят к моделям разных провайдеров. Авторы выпустили версию 1.0 и разобрали, как шлюз живёт в продакшене. Можно подключить собственные видеокарты и отправлять на них запросы раньше, чем в платное облако. Для каждой из трёх зависимостей (Postgres, Redis, сервис учёта) заранее прописано поведение при отказе. Ключи шифрования меняются без потерь, а релизы подписаны и проверяются. Обновление идёт без остановки сервиса.

Свои видеокарты первыми, облако — запасным

У многих команд есть Mac Studio или Linux-машина с хорошей картой, которая половину времени простаивает. Облачный счёт при этом растёт за запросы, с которыми справилась бы и локальная модель. KTMS превращает такие машины в отдельного вендора с именем local.

Администратор через gRPC выдаёт ключ ноды (показывается один раз) и регистрирует модель. На самой машине запускается один скрипт. Он ставит Ollama, модель и агента ноды, настраивает фоновые сервисы и не даёт компьютеру уснуть. На macOS права администратора не нужны. Если что-то сломалось, тот же скрипт с флагом --doctor сообщит причину: Ollama не отвечает, модель не загружена, Ollama работает на CPU через Rosetta, указан неверный --tls. Поддерживаются Ollama, vLLM, TGI и llama.cpp.

Шлюз сам обращается к ноде, поэтому её нужно сделать доступной. Агент умеет поднять туннель Cloudflare и фильтр перед движком. Через него проходят только POST /v1/chat/completions и GET /v1/models, поэтому скачать или удалить модель снаружи нельзя.

Выбор ноды устроен в три шага:

  • Фильтр. Остаются ноды с нужной моделью, свободным слотом и достаточным контекстным окном. Здоровые идут раньше подозрительных, а «тёплые» (модель уже в памяти) раньше «холодных».
  • Вес. Базовый вес умножается на штраф за загрузку, который растёт квадратично с занятостью слотов, и на поправку за скорость. Поправка считается из скорости генерации (токенов в секунду, вес 0,7) и времени до первого токена (вес 0,3) относительно медианы по всем нодам с этой моделью.
  • Выбор. Применяется smooth weighted round-robin, как в nginx.

Главная защита от тормозов — оценка очереди по закону Литтла: глубина очереди умножается на ожидаемую длительность запроса. Если выходит больше queue_timeout_ms модели (в примере 2000 мс), запрос сразу идёт к следующей модели цепочки. Для интерактивных клиентов лимит 250 мс. Слот — аренда в Redis, которая продлевается, пока идёт генерация.

Политики размещения: nodes_first (по умолчанию), nodes_only (нет свободной ноды — ошибка, облако не трогаем), cloud_first и cloud_only. Выбирать можно заголовком, полем запроса или суффиксом модели, например auto:nodes-only:high.

Что делает шлюз, когда падают Redis и Postgres

Принцип: отказ учёта не должен превращаться в отказ сервиса.

  • Redis. Лимиты запросов и токенов пропускаются без учёта. Для лимитов в долларах выбирается режим: open пропускает, closed отклоняет. Кэш считается промахом. Состояние нод неизвестно, поэтому их пропускают и отвечает облако. После трёх сетевых ошибок подряд шлюз 2 секунды не обращается к Redis вовсе, и зависший Redis стоит запросу один таймаут.
  • Postgres. Ключи, проверенные за последние 5 минут, продолжают работать, остальные получают auth_unavailable. Проверка ограничена 3 секундами. Конфигурация берётся из последнего удачного снимка. Batch, у которого нельзя проверить идемпотентность, отклоняется, чтобы за него не заплатили дважды.
  • Сервис учёта. События копятся в памяти (до 10 000), запросы их не ждут.

При сбоях Postgres /readyz отвечает 200 со статусом degraded, пока действует окно известных ключей, и 503 после. Kubernetes не перезапустит поды раньше времени. Пять сбоев подряд размыкают предохранитель вендора, и через 30 секунд проходит одна пробная попытка. Алерт стоит поставить на ktms_dependency_errors_total.

Ключи, подписи релизов и обновление без простоя

Ключи вендоров лежат в Postgres, зашифрованные AES-256-GCM. Keyring с ключами шифрования передаётся переменной KTMS_ENCRYPTION_KEYS и в базе не хранится. Ротация состоит из трёх шагов. Сначала добавить новую версию keyring на все реплики и дождаться конца раскатки. Затем вызвать RotateEncryption: в одной транзакции перешифруются ключи вендоров и токены нод. Наконец, убрать старую версию, когда не осталось бэкапов, требующих её. Дамп вместе с keyring даёт все ключи в открытом виде, поэтому хранить их надо раздельно.

Образы с версии 0.14.0 подписываются cosign в keyless-режиме: подпись привязана к идентичности workflow в GitHub Actions, и красть нечего. К образам приложены SBOM (список компонентов) и SLSA-provenance (запись о том, где и как собрано). Каждый pull request проверяет govulncheck, а релиз не выходит без buf breaking и теста обновления. Авторы честно оговариваются: подпись подтверждает происхождение, а не безопасность. Тот, кто получит права на релизный workflow, подпишет и вредоносный образ.

В пределах 1.x публичный API не ломается. Миграции применяются при старте под advisory-lock и только добавляют схему, поэтому старые реплики работают на новой базе, пока поднимаются новые. Отката нет: возвращаться надо через бэкап, снятый перед обновлением. На SIGTERM запросам даётся 30 секунд, а агент ноды сначала уходит в drain.

Для команд с простаивающими GPU это готовый способ сократить облачный счёт без риска остаться без ответа при перегрузке. Перед запуском стоит проверить TLS (сам шлюз говорит plaintext gRPC), убрать BOOTSTRAP_ADMIN_KEY, завести отдельный ключ на клиента и следить за соединениями Postgres (до 25 на реплику).

Сюжет

Вопросы и ответы по материалу

Что известно по теме: свои видеокарты первыми, облако — запасным?

У многих команд есть Mac Studio или Linux-машина с хорошей картой, которая половину времени простаивает. Облачный счёт при этом растёт за запросы, с которыми справилась бы и локальная модель. KTMS превращает такие машины в отдельного вендора с именем local. Администратор через gRPC выдаёт ключ ноды (показывается один раз) и регистрирует модель. На самой машине запускается один скрипт. Он ставит Ollama, модель и агента ноды, настраивает фоновые сервисы и не даёт компьютеру уснуть. На macOS права администратора не нужны. Если что-то сломалось, тот же скрипт с флагом --doctor

Что известно по теме: что делает шлюз, когда падают Redis и Postgres?

Принцип: отказ учёта не должен превращаться в отказ сервиса. Redis. Лимиты запросов и токенов пропускаются без учёта. Для лимитов в долларах выбирается режим: open пропускает, closed отклоняет. Кэш считается промахом. Состояние нод неизвестно, поэтому их пропускают и отвечает облако. После трёх сетевых ошибок подряд шлюз 2 секунды не обращается к Redis вовсе, и зависший Redis стоит запросу один таймаут. Postgres. Ключи, проверенные за последние 5 минут, продолжают работать, остальные получают auth_unavailable. Проверка ограничена 3 секундами. Конфигурация берётся из последн

Что известно по теме: ключи, подписи релизов и обновление без простоя?

Ключи вендоров лежат в Postgres, зашифрованные AES-256-GCM. Keyring с ключами шифрования передаётся переменной KTMS_ENCRYPTION_KEYS и в базе не хранится. Ротация состоит из трёх шагов. Сначала добавить новую версию keyring на все реплики и дождаться конца раскатки. Затем вызвать RotateEncryption: в одной транзакции перешифруются ключи вендоров и токены нод. Наконец, убрать старую версию, когда не осталось бэкапов, требующих её. Дамп вместе с keyring даёт все ключи в открытом виде, поэтому хранить их надо раздельно. Образы с версии 0.14.0 подписываются cosign в keyless-режим

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Единое AI-пространство · Nomad

Протестируйте новые LLM и мультимодальные модели в одном окне

Платформа Nomad AI (nomadnet.ai) даёт прямой доступ к Claude Opus 5.5, GPT-6, Gemini 3.1, DeepSeek и автономным агентам без VPN, зарубежных карт и зоопарка подписок.

Открыть Nomad AI →Автономный Nomad Agent
Что вы думаете?
Загружаем комментарии…