Инженерный хаб

Как мы перевезли крупный проект на WordPress в Google Cloud и не поседели

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

Привет, инженеры! Сегодня я хочу поделиться с вами подробностями одного из самых масштабных, сложных и в то же время захватывающих проектов в нашей практике — миграцией гигантского WordPress-проекта. Точное название клиента находится под строжайшим NDA, но масштаб системы вы можете себе представить по одному простому факту: генеральным подрядчиком и провайдером платформы выступала сама компания Automattic (да-да, те самые создатели и главные контрибьюторы WordPress). Когда к тебе приходят ребята такого уровня, ты понимаешь, что стандартными решениями из учебников тут не обойтись. Задача казалась классической: перевезти высоконагруженные сайты на масштабируемую, отказоустойчивую и современную облачную инфраструктуру Google Cloud Platform (GCP) Platform (GCP), используя связку Cloud Run для вычислений и Cloud SQL для хранения данных. Но, как водится в нашей индустрии, дьявол кроется в деталях и легаси.

С чего все началось: аудит легаси-монстра

Когда мы впервые заглянули под капот текущей инфраструктуры клиента, у нас зашевелились волосы даже в тех местах, где их давно нет. Это был классический монолит, который годами обрастал костылями, кастомными плагинами и оптимизациями под конкретное старое железо. Трафик там был просто космический: миллионы уникальных пользователей в сутки, регулярные медийные спайки, когда посещаемость могла вырасти в 10–15 раз за несколько минут из-за хайповых новостей, и терабайты медиаконтента.

Архитектура старой площадки представляла собой распределенную группу виртуальных машин, где синхронизация медиафайлов осуществлялась через медленный и постоянно сбоящий GlusterFS, а сессии пользователей синхронизировались через перегруженный Redis. База данных трещала по швам от огромного количества таблиц (специфика работы WordPress Multisite), а время отклика сервера (TTFB) в пиковые часы зашкаливало за разумные пределы. Сразу стало очевидно, что простой перенос виртуалок методом lift-and-shift в облако не решит проблем, а лишь увеличит счет за инфраструктуру в GCP. Нам требовалось полностью переосмыслить архитектуру приложения, сделав его по-настоящему cloud-native.

Почему Cloud Run, а не Kubernetes (GKE)?

Перед нами стоял выбор целевой платформы для контейнеризации. С одной стороны, проверенный временем Google Kubernetes Engine (GKE), который дает полный контроль над кластером. С другой стороны — полностью управляемый serverless-сервис Cloud Run, работающий на базе технологии Knative. После проведения серии нагрузочных тестов и оценки стоимости эксплуатации (TCO) мы сделали выбор в пользу Cloud Run. И вот почему:

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

Однако контейнеризация WordPress — это та еще задача, поскольку эта CMS исторически создавалась как stateful-система, которая любит писать логи, кэш и медиафайлы на локальный диск.

Инженерный хардкор: База данных и тюнинг пула соединений

Первым серьезным вызовом стала миграция базы данных без остановки обслуживания пользователей. Объем базы составлял более 500 гигабайт. Мы разработали комплексную стратегию миграции с использованием кастомных скриптов на Python и Go, которые осуществляли первоначальный слепок данных, а затем докатывали изменения в реальном времени через бинарные логи. Для обеспечения безопасности и минимальной задержки мы развернули VPC Serverless Access Connector — специальный сетевой мост, позволяющий контейнерам Cloud Run общаться с базой данных Cloud SQL напрямую через приватные IP-адреса, минуя публичный интернет.

Но настоящая головная боль началась, когда мы приступили к нагрузочному тестированию. WordPress по умолчанию создает новое подключение к базе данных на каждый HTTP-запрос. Когда Cloud Run под нагрузкой мгновенно масштабировался с 10 до 300 инстансов, каждый из которых запускал десятки воркеров PHP-FPM, база данных Cloud SQL моментально утилизировала лимит подключений и уходила в глубокий нокдаун. Процессор поднимался до 100%, и пользователи видели ошибку Error Establishing a Database Connection.

Хотя классический WordPress работает на MySQL, в данном проекте по требованию архитекторов из Automattic использовалась кастомная сборка с адаптером PG4WP для базы данных PostgreSQL. Это позволило нам применить мощный инструмент пулленга соединений — PgBouncer. Мы развернули PgBouncer в качестве промежуточного слоя. Он мультиплексировал тысячи кратковременных клиентских соединений от контейнеров Cloud Run в стабильный пул из нескольких десятков постоянных соединений к самой БД.

Активные соединения с БД при автоскейлинге Cloud Run

Сравнение количества открытых коннектов к Cloud SQL с использованием PgBouncer и без него при резком росте нагрузки (инстансов Cloud Run).

Настройка файла конфигурации pgbouncer.ini потребовала тонкого тюнинга. Мы перевели пул в режим работы pool_mode = transaction, что позволило максимально эффективно переиспользовать соединения, хотя и потребовало от нас переписать несколько legacy-плагинов, которые некорректно работали с транзакционным режимом (например, использовали временные таблицы вне транзакций).

Решение проблемы stateless: Медиафайлы и сессии

Поскольку контейнеры в Cloud Run эфемерны и могут быть уничтожены или перезапущены в любой момент, мы не могли хранить загружаемые пользователями файлы на локальном диске контейнера. Для решения этой проблемы мы полностью переписали логику работы с медиафайлами. Все статические ресурсы были перенаправлены в объектное хранилище Google Cloud Storage (GCS).

Для этого мы использовали плагин WP Offload Media, предварительно оптимизировав его код для работы в высоконагруженной среде. Теперь при загрузке картинки редактором сайта она мгновенно улетала в GCS, а в базу данных записывался правильный URL, указывающий на глобальную сеть доставки контента Cloud CDN. Это не только решило проблему сохранности данных, но и сняло колоссальную нагрузку с бэкенд-серверов: статика теперь раздавалась из кэша на пограничных серверах Google (Edge Points of Presence) по всему миру с минимальным пингом.

Для кэширования объектов внутри WordPress (Object Cache) и хранения сессий пользователей мы развернули отказоустойчивый кластер Memorystore for Redis. Это позволило разгрузить базу данных от повторяющихся тяжелых SQL-запросов и обеспечило бесшовную авторизацию пользователей: даже если контейнер Cloud Run, на котором находился пользователь, уничтожался, его сессия оставалась активной, так как она хранилась в общем централизованном кэше Redis.

Сборка контейнеров и оптимизация PHP-FPM

Чтобы добиться максимальной производительности, мы ушли от стандартных Docker-образов WordPress. Мы собрали свой кастомный образ на базе чистого Alpine Linux, установили туда только необходимые расширения PHP, настроили OPcache для кэширования байт-кода в оперативной памяти и оптимизировали конфигурацию PHP-FPM.

В конфигурационном файле opcache.ini мы задали следующие параметры:

opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=20000 opcache.validate_timestamps=0

Параметр opcache.validate_timestamps=0 критически важен для продакшена: он отключает проверку изменений файлов на диске при каждом запросе. Поскольку наш код упакован в неизменяемый контейнер, файлы не могут измениться во время работы, и эта оптимизация экономит драгоценное процессорное время и дисковые операции ввода-вывода (I/O).

Смешной эпизод с DNS на cutover

Но самое интересное и запоминающееся случилось непосредственно в ночь переключения (cutover). Те, кто занимался миграциями крупных проектов, знают это непередаваемое чувство: ночь, в созвоне Google Meet сидит около пятнадцати человек — инженеры с нашей стороны, архитекторы из Automattic, представители клиента, дежурные системные администраторы. Все сосредоточены, в воздухе висит напряжение, литры кофе уже выпиты.

Мы начинаем финальную синхронизацию базы данных, переводим старую площадку в режим read-only, проверяем, что все лаги репликации сошлись в ноль. Переключаем трафик на уровне Cloud DNS, меняя A-записи на IP-адрес нашего нового балансировщика нагрузки GCP HTTPS Load Balancer. Метрики в панели управления Cloud Monitoring начинают оживать, запросы плавно перетекают на новую инфраструктуру, все графики зеленые, ошибок нет. Полный триумф!

И тут в общий чат пишет наш джуниор-инженер, который помогал с ручным тестированием интерфейса после переключения: "Ребят, а почему у нас тестовый домен и админка до сих пор резолвятся на localhost? Я пытаюсь зайти, а мне выдает ошибку подключения!". В созвоне повисает гробовая тишина. У всех начинает холодеть внутри — неужели мы где-то прописали жесткий хардкод локального хоста в конфигурационных файлах WordPress Multisite или в базе данных, и теперь миллионы пользователей не могут зайти на сайт?

Я судорожно начинаю проверять конфигурационный файл wp-config.php, лезу в базу данных через консоль, проверяю таблицы, но там все чисто. И тут до меня доходит... Я смотрю на свой собственный терминал и понимаю, что буквально за полчаса до начала миграции я сам прописал заглушку в локальный файл /etc/hosts на своей рабочей машине, чтобы протестировать один специфический скрипт локально, и забыл ее удалить! И наш джун, который сидел со мной в одном офисе, просто скопировал мои настройки окружения.

Оказалось, что я полчаса тестировал прод локально, думая, что все идеально работает на новых серверах GCP, а джун паниковал из-за моей же забывчивости! Мы быстро удалили строчку из /etc/hosts, проверили реальный DNS через публичные резолверы по всему миру — всё обновилось без единого сучка и задоринки. Напряжение в звонке сменилось дружным хохотом, мы выдохнули, допили остывший кофе и с чувством выполненного долга пошли спать.

Результаты миграции

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

Среднее время отклика (Latency) до и после миграции

Динамика изменения времени загрузки страниц (в миллисекундах) на старой инфраструктуре и в новой конфигурации Cloud Run + Cloud CDN.

Помимо снижения задержки, клиент получил:

  • Zero Downtime: Миграция прошла абсолютно незаметно для конечных пользователей.
  • Экономию бюджета: За счет автоматического масштабирования Cloud Run затраты на инфраструктуру снизились на 35% по сравнению со старой схемой с постоянно запущенными виртуалками.
  • Безопасность: Интеграция с Cloud Armor позволила настроить автоматическую защиту от DDoS-атак и попыток подбора паролей к админке WordPress (brute-force).

Гигантский проект теперь стабильно крутится на мощностях GCP к огромной радости наших коллег из Automattic, а мы получили бесценный опыт, отличный кейс в портфолио и пару новых седых волос в подарок. Cloud Run действительно рулит, если уметь его правильно готовить и не забывать очищать свои локальные конфиги! До новых встреч на страницах нашего блога!

Реальные ограничения и компромиссы решения

Инженерный аудит: реальные ограничения и компромиссы

Инженерная честность OZAT: при внедрении решения «Как мы перевезли крупный проект на WordPress в Google Cloud и не поседели» в промышленную эксплуатацию вы обязаны учитывать следующие технологические ограничения:

  1. Сложность горизонтального масштабирования медиафайлов WordPress: Директория wp-content/uploads требует синхронизации через Cloud Storage FUSE или плагин GCS Offload.
  2. Ограничения блокировок таблиц MySQL при высоких нагрузках: База данных wp_options и transient-кэши создают конкуренцию за строки; обязателен вынос сессий в Cloud Memorystore (Redis).
  3. Уязвимости плагинов и тем: Открытый исходный код расширений требует сканирования уязвимостей и защиты через Cloud Armor WAF.
  4. Задержка холодного старта PHP-FPM контейнеров: Инициализация стека Apache/Nginx + PHP-FPM в Cloud Run требует прогрева и настройки min-instances.

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

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

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

Автор Инженерного хаба

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

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

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