Kaspi Жұма без даунсекунд: Как мы пережили х50 трафика на e-commerce, переехав на GKE и Cloud Spanner
В календаре казахстанского ритейла есть события важнее Нового года и Наурыза. Это 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:
- Google Kubernetes Engine (GKE) Autopilot: бессерверный управляемый кластер Kubernetes, где Google берет на себя управление нодами, безопасность, автомасштабирование пулов узлов и оптимизацию сетевого стека с технологией eBPF.
- Google Cloud Spanner: глобально распределенная реляционная СУБД с аппаратной поддержкой синхронизации времени TrueTime API, сочетающая неограниченную горизонтальную масштабируемость NoSQL и строгие ACID-гарантии классического SQL.
- KEDA (Kubernetes Event-driven Autoscaling) + Cloud Pub/Sub: предиктивное масштабирование микросервисов на основе глубины очередей заказов с реакцией за секунды.
- 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 (вложенные таблицы). Вложенные таблицы физически хранят строки дочерней таблицы (позиции заказа) на том же дисковом блоке рядом с родительской строкой (заказ и клиент):
Топ-10 ошибок на сайтах казахстанских компаний: почему вы теряете клиентов и как это исправить
-- 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 рельсы:
- Покупатель нажимает «Оформить заказ» в мобильном приложении или на сайте.
- Запрос принимает легковесный API Gateway на Cloud Run, проводит базовую валидацию схемы и JWT-токена за 8 мс.
- Событие создания заказа мгновенно пушится в Google Cloud Pub/Sub (гарантированная пропускная способность свыше 1 000 000 сообщений в секунду).
- Клиент моментально получает HTTP
202 Acceptedс трек-номером заказа и WebSocket-подпиской на статус. - Внутри 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-фазную стратегию миграции:
- CDC (Change Data Capture) через Debezium: мы развернули Kafka Connect для непрерывного захвата изменений из WAL-лога PostgreSQL и потоковой репликации в Cloud Spanner в реальном времени.
- Dual-Write (Двойная запись): на уровне сервисного слоя включили асинхронную запись в обе базы данных с первичным чтением из старого PostgreSQL.
- Shadow Traffic (Теневой трафик через Envoy): с помощью Ingress-контроллера на базе Envoy мы дублировали 100% реального входящего трафика на новый кластер GKE + Spanner, отбрасывая ответы тени и замеряя производительность под нагрузкой.
- Мгновенное переключение (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
Опыт выдерживания национальных пиковых нагрузок доказывает: вертикальное масштабирование (покупка более дорогих серверов) мертво. В эпоху цифрового ритейла побеждают компании, заложившие эластичные облачные фундаменты.
Главные правила подготовки к экстремальным нагрузкам:
- Сделайте оформление заказа асинхронным: отвяжите пользователя от синхронной записи в БД. Очередь (Cloud Pub/Sub) спасет ваш бэкенд от захлебывания.
- Не экономьте на транзакционной базе: если бизнес завязан на точный учет остатков и платежей, Cloud Spanner окупает свою стоимость в первые 10 минут распродажи, предотвращая потерю заказов.
- Масштабируйтесь упреждающе (KEDA): масштабирование по размеру очередей сообщений опережает реальный наплыв трафика, гарантируя готовность вычислительных мощностей.
Команда OZAT обладает глубочайшей экспертизой в проектировании высоконагруженных систем, миграциях в Google Cloud и тонкой настройке распределенных баз данных. Изучите наши другие практические кейсы, чтобы узнать, как мы трансформируем IT-ландшафт ведущих компаний Казахстана.
💡 Совет OZAT: Готовы к внедрению? Рассчитайте архитектуру и бюджет через Scope Builder или пройдите бесплатный ИИ-аудит.

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