Всем привет! Уверен, многие из вас когда-нибудь покупали майку, мяч, кроссовки, ну или какой-нибудь другой спортивный инвентарь в наших магазинах, но мало кто знает, что из себя представляет Спортмастер с технической точки зрения.
Немного Спортмастера образца 2003 года с сайта web.archive.org
Меня зовут Дмитрий, я старший java-разработчик в компании Спортмастер, и сегодня я хотел бы рассказать о нашем интернет-магазине, о том, какой путь он проделал, чтобы стать тем, каким вы его знаете сейчас: с чего мы начинали, как развивались, что получилось, а что нет, о проблемах сегодня, и о планах на будущее. Интересно? Добро пожаловать под кат!
История присутствия нашей компании в паутине начиналась аж в далёком 1999 году с первого сайта Спортмастера, который был просто визитной карточкой и каталогом товаров для оптовых покупателей. Собственно интернет-магазин компании ведёт свою историю с 2001 года. В те времена в компании не было собственной команды разработки online-проектов, и интернет-магазин ухитрился сменить несколько самопальных платформ (теперь уж и не вспомнить сколько). Первое относительно устойчивое решение для нас создал очередной интегратор в 2011 году на PHP, на базе CMS 1С Битрикс. Сайт получился простенький, фактически был использован коробочный функционал Битрикс, с небольшими кастомизациями по оформлению заказа. По железу — стартовая конфигурация включала 2 сервера приложений и один сервер БД.
Тем временем компания начала активно наращивать собственные компетенции в сфере онлайн-продаж, в первую очередь на стороне бизнеса, который, надо сказать, довольно быстро вошёл во вкус, и команда разработки вынуждена была быстро расти во всех смыслах, чтобы успевать удовлетворять его потребности. Не прошло и года, как за развитие и поддержку сайта стали отвечать сразу три команды — сам интегратор, внутренняя команда Спортмастера, на тот момент насчитывающая буквально нескольких человек, и ещё один подрядчик – его появление, собственно, было вызвано тем, что интегратор в какой-то момент не смог предоставить нужные нам мощности по людям.
Какие проблемы мы испытывали на тот момент? Проблем было немало, но самая главная – это нестабильная работа нашего интернет-магазина.
Мы могли упасть даже от того, что бизнес провёл какую-то рассылку, после которой на сайт пришло ~2000-2500 человек, или, как сейчас помню, рекламный баннер на Яндексе отправил нас в глубокий нокдаун. Конечно, такие вещи недопустимы, ведь это не только упущенная прибыль, но и имидж компании – в общем, мы понимали, что нужно что-то менять. В первую очередь пришло осознание того, что стандартные решения с нашими нагрузками (на тот момент и не сверхбольшими, но все-таки уже и не маленькими) работать не будут. Тогда мы имели ~1000 посетителей онлайн в штатном режиме, ~2500 в пиках, плюс планы по развитию x2 ежегодно.
Сразу же усилились по железу: добавили ещё 2 сервера приложений и сделали кластер из 2 серверов баз данных. Наш стэк на тот момент — nginx, MySQL, PHP. Параллельно мы пытались оптимизировать текущее решение — искали узкие места, пытались переписать всё, что было возможно. Так как нашим узким местом была база, первой всегда «умирала» она, то мы решили по максимуму её разгрузить. Внедрили sphinx для полнотекстового поиска и вывода товарной плитки с фасетами по выбранным фильтрам и подключили кеши. И вуаля — те нагрузки, которые вчера оказывались для нас фатальными, мы стали с лёгкостью держать.
Вместе с этим параллельно был запущен пилот, в рамках которого хотели провести технологическое обновление сайта — перевод на принципиально другую платформу. Задумок и идей было много — в то время набирала популярность персонализация всего и вся, персональные рекомендации, рассылки, скидки и прочие полезные штуки, и мы тоже, конечно, хотели всем этим пользоваться. Посмотрели, что есть на рынке из подобного, ну и купили самую дорогую платформу по принципу «Раз дороже — значит, круче». Внедрение планировалось с помощью интегратора, а на нас оставалась поддержка и дальнейшее развитие условно старого ИМ до того момента, пока новый на новой платформе не будет сдан в эксплуатацию.
Но так как скорость функционального развития текущего сайта была очень высокой, мы решили, что начнём внедрение новой e-commerce платформы с более маленького и простого на тот момент интернет-магазина розничной сети Остин, которая также обслуживалась командой ИТ Спортмастера. В процессе мы поняли, что штука-то здоровенная и функционально навороченная, но с технологической точки зрения устаревшая, а найти людей по её полноценному внедрению оказалось вообще огромной проблемой. Кроме того, сделанный перед началом проекта сайзинг дал сильно заниженные требования к железу и количеству лицензий – жизнь оказалась гораздо более жестокой. В общем, мы поняли одно: Спортмастер мы на ней делать не будем. А так как команда для миграции на платформу была уже в процессе набора, то ребята решили начать прототипирование своего собственного решения, основываясь на требованиях, выставленных бизнесом к новой платформе.
Технологический стэк был выбран следующий: Java, Spring, Tomcat, ElasticSearch, Hazelcast.
По итогу, примерно к концу 2014 года, у нас была готова новая версия ИМ, полностью самописная, на которую мы успешно переключились. Она же — первая версия того сайта, который вы видите сегодня. Естественно, сегодняшняя версия гораздо более функциональна и технологична, но базовая платформа у них одинаковая.
Основные задачи
Само собой, когда говорим о большом интернет-магазине, речь идет о готовности справляться не только с ежедневными, но и пиковыми нагрузками — быть стабильными для бизнеса и конечных пользователей.
Основные подходы здесь — возможность горизонтально масштабироваться и применение подходов кеширования данных на разных уровнях. И вот, как и какое-то время назад, мы решили оптимизировать доступ к нашим данным. Но мы не можем использовать обычное кеширование страничек. Вообще. Это требование бизнеса, и требование довольно разумное — если показать в конкретный момент времени пользователю сайта неправильную цену или неправильное наличие товара, это с большой вероятностью приведёт к отказу от покупки и к падению лояльности покупателя.
И ладно бы ещё, если бы клиент заказал 15 пар носков по 299 рублей, а в магазине обнаружил, что на самом деле есть только 14 пар и по 300 рублей — с этим можно как-то жить. Смириться, купить, что есть, и жить дальше с этим шрамом в душе. А вот если расхождения по цифрам серьёзные, или ты искал конкретный размер — а его раскупили, пока ты читал отзывы счастливых владельцев клетчатых шорт, вот здесь уже все печальнее. То есть сразу и потеря довольного (до этого момента) клиента, и потеря времени и денег на работу колл-центра, куда этот клиент будет звонить, чтобы узнать, что вообще случилось и почему.
Следовательно, пользователь всегда должен видеть самую свежую цену и самые актуальные данные о товарных остатках, и поэтому наши кеши умные и знают о том, когда данные в БД меняются. Для кеширования мы используем Hazelcast.
Кстати, об остатках
Здесь важно отметить, что сама глубина товарных остатков у нас небольшая. А на самовывоз идет очень большое количество заказов (очень). Поэтому клиент должен нормально забронировать товар в нужном магазине и отслеживать остатки. В свое время, на Битриксе, проблему остатков забороли тем, что просто считали любые остатки более 10 единиц бесконечностью. То есть все, что больше 10, всегда равно 10, а вот уже нижние значения нам интересны для подсчёта и мы их учитываем, подгружаем на сайт.
Сейчас так делать уже нельзя, поэтому мы загружаем остатки из всех магазинов присутствия раз в 15 минут. А магазинов у нас около 500, плюс ряд региональных складов, плюс несколько торговых сетей. И всё это надо оперативно обновлять. Вишенкой здесь тот факт, что в масштабах РФ очень часто меняются условия работы курьерских компаний, поэтому приходится подгружать ещё и параметры доставки. Плюс ко всему на склады компании идёт непрерывный поток поставок товара, из-за чего количество товаров на складах ожидаемо меняется. Значит, его тоже надо подтягивать заново.
А вот как формируются идентификаторы товарных позиций (SKU). Есть у нас около 40 000, так называемых, цветомоделей товаров. Если углубляться далее до размеров товаров — получится порядка 200 000 SKU. И по всем этим 200 000 надо обновлять остатки в масштабах 500 магазинов.
Городов и деревень, в которые мы доставляем товары из магазинов или со складов, у нас тоже десятки тысяч. Поэтому и получается, что вариативность кеша только для одной товарной странички (города * SKU) — это миллионные значения. Подход у нас такой: расчёт доступности той или иной товарной единицы происходит на лету, когда пользователь заходит на карточку товара. Смотрим работу курьерок в регионе пользователя, смотрим их график работы, рассчитываем цепочку доставки и считаем её длительность. Вместе с этим параллельно анализируются остатки в магазинах поблизости, от которых можно организовать подвоз.
Чтобы было проще со всем этим управляться, у нас есть определённое количество очень быстрых кешей в приложении — благодаря этому мы можем быстро получить по ID все необходимые данные, и на лету их перебирать. То же самое с курьерками — мы группируем их по кластерам, а затем кластера уже сохраняем в базу данных. Раз в 15 минут всё это обновляется, на каждый входящий запрос мы обсчитываем определенный кластер курьерок с нужными параметрами, агрегируем их и быстро выдаем на выходе покупателю — все ОК, вот такие шорты зелёного цвета 50-го размера у нас точно есть, их можно или забрать ручками вот в этих трёх магазинах поблизости прямо сейчас, или заказать в магазин через дорогу (или вообще домой) в течение 3 дней, выбирай.
Для Москвы такая ситуация может казаться излишней, но вот для регионов это совсем другое дело, там очень часто заказывают товары до какого-то из магазинов (до которого, возможно, тоже надо специально добираться).
Цифры
Сейчас сайт получает тысячи запросов в секунду с учетом статики и 500-1000 запросов в секунду к серверам приложений. Количество серверов приложений у нас не изменилось, но вот их конфигурация подросла значительно. За сутки в среднем получается около 3 000 000 просмотров.
DDoS-ы на сайт временами встречаются. Стучатся при этом ботнетами, причем нашими, родными, из РФ. Давненько были случаи с попытками стучаться ботнетами из Мексики и Тайваня, но сейчас такого уже нет.
На рынке сейчас есть ряд решений по облачной защите от DDoS, да, и довольно неплохих. Но по определенным политикам безопасности мы не можем использовать облачные решения такого рода.
Что сейчас
Мы начинаем делать именно платформенное решение, разделяя команды не вертикально (вида одни пилят один сайт, а вторые — другой), а горизонтально, выделяя общий платформенный слой, деля его на части, формируя команду вокруг него. А на них уже замыкаем сайт и не только, включая любые клиенты компании, как внешние, так и внутренние. Поэтому нам предстоит много сложной и интересной работы.
Стек на фронте по понятным причинам за это время не особо изменился — Java, Spring, Tomcat, ElasticSearch, Hazelcast всё так же хороши для наших нужд. Другое дело, что сейчас за сайтом скрывается и множество бэк-офисных систем на различных технологиях. И, конечно же, активно идёт реинжиниринг (потому что запросы к внутренним системам и работу с ними в целом нужно оптимизировать, плюс не забываем о требованиях бизнеса и новых бизнес-функциях).
А ещё вы можете смело кидать мне в личку (или в комменты) любые пожелания насчет улучшения сайта — как в плане новых функций, так и визуальной составляющей и общего пользовательского опыта. Постараемся на всё оперативно ответить и учесть. А если хотите стать частью команды и пилить всё это изнутри — добро пожаловать.
Автор: davsyukov