Shopify завершила миграцию критически важного узла своей платформы — системы резервирования товаров во время оформления заказа — с Redis на MySQL. В ходе прошедшей «Черной пятницы» обновленная архитектура успешно справилась с нагрузкой, достигавшей $5,1 млн в продажах ежеминутно.
Почему отказ от Redis стал архитектурной необходимостью
Ранее для контроля остатков в «горячий» момент — между кликом пользователя на кнопку оплаты и финальным подтверждением транзакции — использовался Redis. Механизм был реализован через атомарную команду `DECR` для управления счетчиком количества товара.Технически это обеспечивало низкую задержку, но создавало фундаментальный разрыв в консистентности данных. Истинные показатели запасов хранились в MySQL, а оперативные счетчики — в Redis. Так как эти системы независимы, реализовать единую ACID-транзакцию было невозможно. Если коротко, возникали состояния «гонки»: товар мог быть списан в основной БД, но «зависнуть» как зарезервированный в Redis, или наоборот. Помимо проблем с целостностью, поддержка отдельного кластера Redis под конкретную задачу с несколькими складами требовала избыточных операционных затрат.
Переход к строковой модели и SKIP LOCKED
В новой архитектуре Shopify отказалась от концепции счетчика в пользу модели, где каждая единица товара представлена отдельной строкой в базе. Если на складе доступно 10 экземпляров позиции, в таблице создается 10 соответствующих записей. Процесс резервирования теперь сводится к выполнению `SELECT ... FOR UPDATE SKIP LOCKED`.На практике это значит, что при параллельных запросах транзакции не выстраиваются в очередь. Инструкция `SKIP LOCKED`, появившаяся в MySQL 8, позволяет базе игнорировать строки, которые уже заблокированы другими процессами, и сразу переходить к свободным. Чтобы не раздувать таблицы до гигабайтных размеров, введена система лимитов: на комбинацию «товар + склад» создается не более 1000 строк резерва. При необходимости система автоматически дозаполняет пул из основного реестра остатков в фоновом режиме.
Борьба за соединения с ProxySQL
Наиболее сложная часть оптимизации прошла уже после внедрения решения. Инженеры столкнулись с тем, что даже после настройки индексов и SQL-запросов производительность упиралась в невидимый «потолок». Оказалось, что узким местом была не сама логика обработки товаров, а исчерпание пула соединений с БД.Другие модули платформы удерживали соединения с MySQL дольше, чем того требовала логика операций. Резервирование, будучи высоконагруженным процессом, просто «добивало» оставшиеся свободные слоты в пуле. Для диагностики инженеры начали размечать SQL-запросы специальными метками в комментариях (например, `/* conn_tag:checkout_completion */`). Это позволило через ProxySQL точно отследить, какие бизнес-процессы блокируют соединения на избыточное время. Результатом оптимизации пайплайна стало сокращение количества чтений с основной базы на 50%, а общего объема транзакций — на 33%.
Поэтапный отказ от Redis
Процесс декоммиссии Redis проводился без резких отключений. В течение нескольких месяцев Shopify поддерживала работу в режиме «shadow mode», где оба хранилища обрабатывали поток данных параллельно, но финальное решение о резервировании принимал Redis. После того как сверка данных на различных нагрузках подтвердила идентичность результатов, компания плавно переключила трафик на MySQL — от небольших магазинов к крупнейшим мерчантам платформы.