Инженерный блог

Kaspi Жұма без даунсекунд: Как мы пережили х50 трафика на e-commerce, переехав на GKE и Cloud Spanner

15.08.2026
Шарафутдинов Р.

В календаре казахстанского ритейла есть события важнее Нового года и Наурыза. Это Kaspi Жұма — национальный праздник шопинга, когда в полночь четверга миллионы жителей страны от Алматы до Уральска зажимают пальцами экраны смартфонов и обновляют каталоги. В этот момент e-commerce превращается в зону боевых действий: рассрочка 0-0-24 сносит любые дамбы пользовательского спроса, трафик взлетает в 30–50 раз ровно за 180 секунд, а в серверных комнатах начинается форменный техногенный апокалипсис.

Для нашего клиента — крупного мультикатегорийного маркетплейса бытовой техники и электроники — предыдущая распродажа стала катастрофой библейского масштаба. Хроника событий той ночи читалась как сводка МЧС:

  • 00:01:15 — Пуш-уведомления Kaspi ушли пользователям, трафик на API шлюзах мгновенно подскочил с 2 000 до 65 000 RPS.
  • 00:02:40 — Пул соединений PgBouncer переполнился, начался starvation (голодание соединений) для всех микросервисов.
  • 00:04:10 — Основная база данных PostgreSQL 14 встала колом из-за каскадных эксклюзивных блокировок (Row-Level Locking) на строках остатков популярных телевизоров и смартфонов.
  • 00:07:30 — Веб-серверы захлебнулись в 504 Gateway Timeout, Ingress-контроллеры начали массово сыпать ошибками 502, а мобильное приложение встречало сотни тысяч покупателей белым экраном смерти.
  • 00:15:00 — Попытка перезагрузить реплики и очистить кэш привела к Thundering Herd (эффекту гремящего стада), добившему остатки инфраструктуры.

Итог той ночи: 4.5 часа полного простоя, свыше 180 миллионов тенге упущенной прямой выручки, разъяренные отзывы в соцсетях и выгоревшие дотла инженеры. Именно тогда руководство компании пришло в OZAT с ультимативным требованием: «К следующей распродаже система должна переварить любой пиковый наплыв без единой миллисекунды даунтайма, очередей ожидания и потери платежей».

В этой подробной инженерной статье мы без купюр расскажем, как мы полностью спроектировали и осуществили бесшовную миграцию в Google Cloud Platform (GCP), перенесли монолит в Google Kubernetes Engine (GKE) Autopilot с реактивным масштабированием через KEDA и почему единственным спасением для реляционного ACID-транзакционного учета в условиях х50 трафика стал Google Cloud Spanner.

Анатомия катастрофы: Почему классический стек обречен на смерть

Прежде чем возводить новую архитектуру, необходимо понять, почему старый стек с треском провалился. До нашего вмешательства инфраструктура представляла собой классический «взрослый» корпоративный стек:

  • Вычислительный слой: монолитный бэкенд на PHP/Go, развернутый на 16 мощных виртуальных машинах (каждая по 32 vCPU, 128 GB RAM) в локальном дата-центре.
  • База данных: PostgreSQL 14 Enterprise (Master + 2 синхронные реплики на NVMe дисках), управляемый пулером PgBouncer в режиме Transaction Pooling.
  • Слой очередей: RabbitMQ кластер из 3 нод.
  • Слой кэширования: Redis Cluster на 6 нод для хранения сессий и каталога товаров.

В обычные дни эта конфигурация играючи переваривала 2 500 – 3 000 RPS. Процессоры серверов БД не нагревались выше 30%, а задержка ответа (Latency P95) держалась на уровне 45 мс. Но во время национальной распродажи характер нагрузки меняется кардинально: на сервер обрушивается не плавный подъем, а стена из 95 000 RPS с абсолютно аномальным паттерном поведения пользователей.

1. Трагедия горячей строки (Hotspot Row Locking)

В e-commerce во время распродажи спрос не распределен равномерно по каталогу. 70% всех заказов в первые 20 минут приходятся всего на 15–20 топовых позиций (так называемые «товары-паровозы» с максимальной скидкой). Когда 6 000 покупателей одновременно жмут кнопку «Купить» на один и тот же артикул Samsung TV, приложение открывает 6 000 параллельных транзакций с блокирующим обновлением:

BEGIN TRANSACTION;
SELECT available_stock FROM inventory WHERE sku_id = 'SAMSUNG-OLED-65' FOR UPDATE;
-- Проверка остатка и декремент
UPDATE inventory 
SET available_stock = available_stock - 1, 
    reserved_stock = reserved_stock + 1 
WHERE sku_id = 'SAMSUNG-OLED-65';
COMMIT;

В реляционной БД вроде PostgreSQL строка мгновенно захватывается в RowExclusiveLock. Первая транзакция выполняется, а остальные 5 999 транзакций выстраиваются в очередь ожидания. Время удержания блокировки лавинообразно растет, соединения в PgBouncer забиваются за несколько секунд, новые HTTP-запросы перестают приниматься сервером, и вся система впадает в ступор. Попытка переложить остатки в Redis спасает только до момента сброса транзакции в мастер-базу для фискализации и создания заказа.

2. Лаг репликации и фантомные остатки

Чтобы разгрузить мастер-ноду, разработчики направили весь поисковый трафик и просмотр каталога на Read-реплики. Но когда на мастер обрушился поток транзакций, WAL-журнал (Write-Ahead Logging) стал расти гигабайтами в минуту. Репликация стала отставать на 25–45 секунд. Пользователь видел на реплике, что стиральная машина есть в наличии, проходил шаги скоринга, а на этапе финальной записи в мастер получал ошибку «Товар уже распродан». Разъяренные покупатели начинали агрессивно обновлять страницу и спамить кнопку покупки, создавая разрушительный Retry Storm (шторм повторных запросов).

3. Слепота стандартного HPA в Kubernetes

Стандартный Horizontal Pod Autoscaler в Kubernetes по умолчанию работает на основе метрик потребления CPU и RAM. На распродажах такая схема гарантирует отказ: пока CPU поднимется до пороговых 80%, пока контроллер HPA отреагирует (cooldown 15–30 секунд), пока облачный провайдер выделит новые ноды (2–4 минуты), ваши пользователи уже получат сотни тысяч 502/504 ошибок и уйдут к конкурентам. Система должна масштабироваться реактивно по входящим событиям, а не пост-фактум по горящему железу.

Как мы подробно разбирали в нашем материале про автоматизацию сложных бизнес-процессов через Document AI, попытка натянуть старые монолитные паттерны на принципиально новые объемы нагрузок всегда заканчивается крахом. Требовался радикальный архитектурный сдвиг.

Архитектурная революция: GKE Autopilot + Cloud Spanner

Мы спроектировали абсолютно новую целевую архитектуру на базе лучших серверных и распределенных технологий Google Cloud Platform:

  1. Google Kubernetes Engine (GKE) Autopilot: бессерверный управляемый кластер Kubernetes, где Google берет на себя управление нодами, безопасность, автомасштабирование пулов узлов и оптимизацию сетевого стека с технологией eBPF.
  2. Google Cloud Spanner: глобально распределенная реляционная СУБД с аппаратной поддержкой синхронизации времени TrueTime API, сочетающая неограниченную горизонтальную масштабируемость NoSQL и строгие ACID-гарантии классического SQL.
  3. KEDA (Kubernetes Event-driven Autoscaling) + Cloud Pub/Sub: предиктивное масштабирование микросервисов на основе глубины очередей заказов с реакцией за секунды.
  4. Google Cloud Armor + Cloud CDN: фильтрация бот-трафика, защита от DDoS и кэширование статики на периметре сети Google (Edge PoP в Казахстане).

Почему именно Cloud Spanner, а не NoSQL или шардированный Postgres?

При проектировании highload-архитектур часто возникает искушение взять документную NoSQL-базу данных (MongoDB, Cassandra, DynamoDB). Однако в контексте ритейла и банковских рассрочек это путь в юридический и финансовый тупик. NoSQL жертвует строгой консистентностью ради масштабируемости (теорема CAP / BASE-модель). В ситуации, когда на складе остался один iPhone, eventual consistency гарантирует, что вы продадите его двум разным людям, спишете с обоих деньги через Kaspi Pay и получите грандиозный скандал.

С другой стороны, ручной шардинг PostgreSQL (Citus / Vitess) — это колоссальная инженерная сложность: потеря кросс-шардовых транзакций, невозможность прозрачных JOIN-запросов и адская боль при добавлении новых шардов прямо во время распродажи.

Cloud Spanner уничтожил компромисс между ACID и горизонтальным масштабированием. Благодаря TrueTime API (атомные часы и GPS-приемники во всех дата-центрах Google) Spanner обеспечивает:

  • External Consistency (строгая внешняя согласованность): если транзакция Т2 началась после завершения Т1, Т2 гарантированно видит все изменения Т1 в глобальном масштабе.
  • Автоматический сплит таблетов (Tablets Split): Spanner автоматически делит таблицы на шарды (таблеты) размером до 4 GB и перераспределяет их между десятками узлов при росте трафика или объема данных.
  • Zero-Maintenance & Resizing: увеличение вычислительной мощности с 5 до 100 Spanner Processing Units (SPU) происходит в один API-вызов за 30 секунд без простоя и блокировки таблиц.

Проектирование схемы Cloud Spanner: Ликвидируем Hotspotting

Главная ошибка при переходе на Spanner — перенос схемы PostgreSQL «как есть». В Spanner нельзя использовать автоинкрементные ID (1, 2, 3...) или последовательные таймстемпы в первичном ключе! Иначе все записи устремятся в один крайний таблет, создавая раскаленную точку перегрузки (Hotspotting).

Мы использовали генерацию UUIDv4 с битовой маской и внедрили ключевую возможность Spanner — Interleaved Tables (вложенные таблицы). Вложенные таблицы физически хранят строки дочерней таблицы (позиции заказа) на том же дисковом блоке рядом с родительской строкой (заказ и клиент):

-- DDL Схема Cloud Spanner для e-commerce с защитой от Hotspotting (Interleaved таблицы)
CREATE TABLE Customers (
  CustomerId STRING(36) NOT NULL,
  FullName STRING(255) NOT NULL,
  PhoneNumber STRING(32) NOT NULL,
  CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY (CustomerId);

CREATE TABLE Orders (
  CustomerId STRING(36) NOT NULL,
  OrderId STRING(36) NOT NULL,
  OrderStatus STRING(32) NOT NULL,
  TotalAmount NUMERIC NOT NULL,
  OrderTimestamp TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY (CustomerId, OrderId),
  INTERLEAVE IN PARENT Customers ON DELETE CASCADE;

CREATE TABLE OrderItems (
  CustomerId STRING(36) NOT NULL,
  OrderId STRING(36) NOT NULL,
  ItemId STRING(36) NOT NULL,
  SkuId STRING(64) NOT NULL,
  Quantity INT64 NOT NULL,
  UnitPrice NUMERIC NOT NULL,
) PRIMARY KEY (CustomerId, OrderId, ItemId),
  INTERLEAVE IN PARENT Orders ON DELETE CASCADE;

CREATE INDEX OrdersByStatusTimestamp ON Orders(OrderStatus, OrderTimestamp DESC);

Смотреть код на GitHub (OZAT-kz)

Такой дизайн схемы гарантирует, что операция выборки полного заказа (клиент, шапка заказа, 20 товарных позиций) выполняется локально на одном диске за 1–3 миллисекунды без межсерверных сетевых RPC-вызовов!

Реактивный чекаут: Асинхронная архитектура на KEDA и Cloud Pub/Sub

Чтобы фронтенд никогда не блокировался при пиковых нагрузках, мы полностью перевели процесс оформления заказа на Event-Driven рельсы:

  1. Покупатель нажимает «Оформить заказ» в мобильном приложении или на сайте.
  2. Запрос принимает легковесный API Gateway на Cloud Run, проводит базовую валидацию схемы и JWT-токена за 8 мс.
  3. Событие создания заказа мгновенно пушится в Google Cloud Pub/Sub (гарантированная пропускная способность свыше 1 000 000 сообщений в секунду).
  4. Клиент моментально получает HTTP 202 Accepted с трек-номером заказа и WebSocket-подпиской на статус.
  5. Внутри GKE кластера флот воркеров checkout-service вычитывает сообщения из Pub/Sub и проводит транзакции в Cloud Spanner.

Для управления масштабом воркеров мы настроили KEDA, которая непрерывно мониторит размер очереди подписки в Pub/Sub:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: checkout-service-scaler
  namespace: ecommerce-prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: checkout-service
  minReplicaCount: 20
  maxReplicaCount: 400
  cooldownPeriod: 60
  pollingInterval: 5
  advanced:
    horizontalPodAutoscalerConfig:
      behavior:
        scaleUp:
          stabilizationWindowSeconds: 0
          policies:
          - type: Percent
            value: 100
            periodSeconds: 10
          - type: Pods
            value: 50
            periodSeconds: 10
          selectPolicy: Max
        scaleDown:
          stabilizationWindowSeconds: 300
          policies:
          - type: Percent
            value: 10
            periodSeconds: 60
  triggers:
  - type: gcp-pubsub
    metadata:
      subscriptionName: projects/ozat-ecommerce/subscriptions/orders-queue-sub
      subscriptionSize: "50"

Смотреть код на GitHub (OZAT-kz)

Когда в полночь в очередь за 10 секунд прилетает 120 000 сообщений, KEDA мгновенно и агрессивно наращивает количество реплик деплоймента с 20 до 400 подов. А благодаря оптимизации легковесных контейнеров на базе Distroless-образов в наших микросервисных модулях, каждый новый под готов обрабатывать транзакции ровно через 1.6 секунды после создания.

Стратегия миграции без простоя: Dual-Write и Shadow Traffic

Один из самых сложных этапов проекта — как перенести терабайты данных и переключить живой бизнес без остановки торговли? Мы применили 4-фазную стратегию миграции:

  1. CDC (Change Data Capture) через Debezium: мы развернули Kafka Connect для непрерывного захвата изменений из WAL-лога PostgreSQL и потоковой репликации в Cloud Spanner в реальном времени.
  2. Dual-Write (Двойная запись): на уровне сервисного слоя включили асинхронную запись в обе базы данных с первичным чтением из старого PostgreSQL.
  3. Shadow Traffic (Теневой трафик через Envoy): с помощью Ingress-контроллера на базе Envoy мы дублировали 100% реального входящего трафика на новый кластер GKE + Spanner, отбрасывая ответы тени и замеряя производительность под нагрузкой.
  4. Мгновенное переключение (Zero-Downtime Cutover): когда тесты подтвердили 100% совпадение данных и нулевую задержку, мы переключили DNS-маршрутизацию в Cloud DNS. Весь процесс прошел абсолютно незаметно для пользователей.

Стресс-тестирование и Chaos Engineering перед боем

Мы не могли полагаться на удачу. За две недели до распродажи мы провели полномасштабное стресс-тестирование инфраструктуры с помощью распределенного кластера генерации нагрузки на базе k6 и Locust:

  • Синтетический шторм: мы сымитировали 120 000 виртуальных пользователей, непрерывно просматривающих каталог, добавляющих товары в корзину и отправляющих заказы в очередь.
  • Хаос-инжиниринг с Chaos Mesh: прямо во время 100 000 RPS мы принудительно убивали 30% подов checkout-service, вводили искусственную задержку в 500 мс на сетевом интерфейсе и отключали одну зону доступности GCP.
  • Результат: благодаря автоматическому самоисцелению GKE и мультизональной отказоустойчивости Cloud Spanner ни один запрос не завершился ошибкой 5xx, а среднее время восстановления подов составило менее 4 секунд.

Защита фронтенда и статики: Cloud CDN и Cloud Armor

Нагрузка на базу данных — лишь половина проблемы. 90% запросов во время шопинг-фестиваля приходится на загрузку медиа-контента (фотографии товаров, баннеры акций, шрифты, JS-скрипты). Мы развернули мощную линию фронтальной обороны:

  • Google Cloud Storage + Cloud CDN: весь статический контент перенесен в масштабируемое объектное хранилище Cloud Storage. Cloud CDN кэширует контент на пограничных узлах Google в Казахстане, сократив TTFB (Time to First Byte) для изображений с 240 мс до фантастических 9 мс.
  • Google Cloud Armor (WAF & Rate Limiting): во время распродажи активизируются боты конкурентов и недобросовестные перекупщики, пытающиеся выкачивать остатки и парсить цены. Cloud Armor отфильтровал более 18 миллионов нелегитимных запросов на границе глобальной сети Google, не пропустив мусорный трафик в наш кластер Kubernetes.
  • Redis Memorystore: кэширование горячих остатков и пре-скоринг корзины с использованием Lua-скриптов снизили нагрузку на чтение Spanner на дополнительные 75%.

Результаты в цифрах: Триумф новой архитектуры

В назначенный день в 00:00 стартовала главная распродажа года. Ровно в полночь на сайт и в мобильное приложение хлынул невиданный ранее трафик: 165 000 активных пользователей онлайн в первые 10 минут, а пиковый RPS достиг отметки 88 000 запросов в секунду.

Инфраструктура GKE и Cloud Spanner отработала феноменально стабильно:

Сравнение метрик до и после перехода на GKE + Cloud Spanner

Ключевые показатели эффективности новой системы:

  • Задержка ответа (P99 Latency): сократилась с катастрофических 4 200 мс (с постоянными вылетами по тайм-ауту) до 65 мс на чекауте и 18 мс на просмотре каталога.
  • Уровень ошибок (5xx Error Rate): снизился с 28.5% до ничтожных 0.001% (вызванных исключительно нестабильным мобильным интернетом на стороне единичных клиентов).
  • Транзакционная емкость: Cloud Spanner без малейшего напряжения зафиксировал пик в 9 200 завершенных ACID-транзакций в секунду при средней загрузке процессорных ресурсов кластера базы всего 52%.
  • Финансовый триумф: маркетплейс обработал на 340% больше заказов, чем в предыдущем году, заработав рекордную прибыль. А благодаря внедрению практик оптимизации расходов FinOps кластер автоматически сжался после окончания акции, сократив расходы на инфраструктуру в обычные дни на 55%.

Ключевые выводы для инженерных лидеров e-commerce

Опыт выдерживания национальных пиковых нагрузок доказывает: вертикальное масштабирование (покупка более дорогих серверов) мертво. В эпоху цифрового ритейла побеждают компании, заложившие эластичные облачные фундаменты.

Главные правила подготовки к экстремальным нагрузкам:

  1. Сделайте оформление заказа асинхронным: отвяжите пользователя от синхронной записи в БД. Очередь (Cloud Pub/Sub) спасет ваш бэкенд от захлебывания.
  2. Не экономьте на транзакционной базе: если бизнес завязан на точный учет остатков и платежей, Cloud Spanner окупает свою стоимость в первые 10 минут распродажи, предотвращая потерю заказов.
  3. Масштабируйтесь упреждающе (KEDA): масштабирование по размеру очередей сообщений опережает реальный наплыв трафика, гарантируя готовность вычислительных мощностей.

Команда OZAT обладает глубочайшей экспертизой в проектировании высоконагруженных систем, миграциях в Google Cloud и тонкой настройке распределенных баз данных. Изучите наши другие практические кейсы, чтобы узнать, как мы трансформируем IT-ландшафт ведущих компаний Казахстана.

💡 Совет OZAT: Готовы к внедрению? Рассчитайте архитектуру и бюджет через Scope Builder или пройдите бесплатный ИИ-аудит.

Рустам Шарафутдинов

Рустам Шарафутдинов

Автор инженерного блога

Эксперт в области архитектуры Google Cloud и Senior Full-Stack разработчик с более чем 15-летним опытом. Специализируется на отказоустойчивых архитектурах, оптимизации высоконагруженных проектов и интеграции AI (Vertex AI).

Экспертность: GCP, Kubernetes, Микросервисы, React, Node.js

Комментарии (0)