[recovery mode] Подарки от М.Видео: что под капотом?
Вместо введения
Эта история началась в декабре далекого 2007 года. Я был аспирантом МГТУ им. Н.Э. Баумана, и устроился на работу в маленькую компанию, где только что запустили проект под непонятным мне тогда названием — «Процессинг подарочных карт М.Видео». Как мне объяснили на кратком инструктаже в первый рабочий день, процессинг — это такая система, в которой хранятся данные о подарочных картах, и с ними можно осуществлять разные операции. Ещё мне сказали, что почти никаких наработок нет, но создать такую систему совершенно несложно. В связи с этим выход в продуктив был предварительно запланирован через пару месяцев. «Понятно», ответил я, и с головой погрузился в творческий процесс, из которого не вынырнул до сих пор.
Эта статья о том, насколько важно принимать правильные решения в отношении технологий и архитектуры будущего продукта. О том, как их нужно принимать. И о том, что бывает, когда принятые решения оказываются ошибочными. Если бы в декабре 2007-го я имел за плечами опыт, который имею сейчас, процессинг подарочных карт М.Видео развивался бы гладко и размеренно. Не было бы множества бессонных ночей и цейтнотов без выходных, с завтраками, обедами и ужинами перед монитором. Но, в то же время, не было бы такого яростного драйва при работе над продуктом.
Что такое процессинг
Так что же такое процессинговая система? Прежде чем начать повествование о тернистом и длинном пути создания этой системы, неплохо было бы определиться с терминологией.
Процессинговая система (процессинг) — предназначена для обработки информации, используемой при совершении платежных операций.
Принято выделять два типа процессингов: банковский (работает с банковскими картами: Visa, MasterCard и т.п.) и небанковский (работает с небанковскими картами: подарочные карты, скидочные карты, промо-коды и т.п.).
Как вы уже, наверное, догадались, речь в этой статье пойдет о небанковском процессинге.
С чего всё начиналось, или как были выбраны технологии для будущего продукта. Это самая емкая глава моего повествования, потому что начало, на мой взгляд, самое интересное время в создании какого-либо продукта с нуля. Ну, или почти с нуля. На начальных стадиях создания продукта принимаются ключевые (я бы даже сказал, судьбоносные) решения, от правильности которых напрямую зависит будущее продукта. Ошиблись в выборе платформы? Продукт захлебнется в растущем трафике или окажется настолько дорогим в обслуживании, что не принесет компании ничего кроме убытков. Ошиблись в выборе технологий? Через пару лет рискуете не найти специалистов (или найти, но за неадекватные деньги), способных работать с выбранными технологиями. Стоимость создания и обслуживания (я еще не раз вернусь к этому вопросу) является краеугольным камнем очень многих IT-решений, которые были бы на порядки дешевле, если бы сначала были приняты правильные решения.
Итак, была поставлена задача: командой из двух человек за два месяца с нуля разработать процессинговую систему для компании М.Видео. Естественно, система должна была учитывать багаж legacy-ограничений, имевшихся на тот момент (формат данных на магнитных дорожках карт, особенности работы кассовой системы и тому подобное). С точки зрения используемых технологий — полная свобода творчества. «На торрентах есть всё» — под таким лозунгом мы начали думать, на чем бы сваять наш продукт. Я не знал, с какими основными проблемами сталкиваются при использовании процессинговых систем. Найти в интернете какую-либо дельную информацию об этом тоже не удалось — направление довольно узкоспециальное, а, как мы все прекрасно знаем, в интернете, как правило, пишут о трендовых вещах (опять же, закон рынка). Поэтому при выборе технологий пришлось опираться на имевшийся опыт разработки других систем, техническую логику и банальные навыки владения теми или иными технологиями (думаю, вам очевидно, что времени на серьезное изучение новых технологий не было совсем). Забегая вперед скажу, что в выборе технологий я не ошибся (естественно, я не приписываю это своей гениальности, во многом — просто повезло). Я ошибся в другом — в архитектуре программного решения. Но обо всем по порядку.
Железо и аппаратная архитектура
Начнем с железа. Часто при проектировании систем оборудование подбирают, исходя из выбранной программной платформы (например, Oracle или IBM в спецификациях на свои платформы обычно указываются минимальные аппаратные требования), либо сложности решаемой задачи (например, обработка потокового видео 4K с заданными характеристиками производительности). В нашем случае — ни то, ни другое. Критериями выбора были: надежность системы и, как это ни банально, бюджет. Сразу стало понятно, что кластерные системы от IBM с возможностью «горячей» замены модулей и тому подобными фишками нам не по карману, от слова «вообще» (кто работал в маленьких компаниях/стартапах меня поймет). Поэтому наше внимание переместилось в низкий ценовой сегмент, с оговоркой, что резервирование системы нужно будет реализовать самостоятельно. В итоге выбрали недорогие сервера HP, ничем не примечательные. А вот построенный механизм резервирования на первых порах вызвал множество вопросов со стороны заказчика. Но в первый год эксплуатации системы они были полностью сняты. Механизм был следующий (Рис. 1).
Рис. 1.
Да, вот так всё примитивно. Два зеркальных фронтентд-сервера и один сервер БД. Но почему так, и какая польза от этой схемы? Так давно уже никто не делает, скажет читатель, разбирающийся в современных технологиях построения систем 24/7/365, и будет прав… Но лишь отчасти. Давайте разбираться. Как уже было сказано выше, вариант поставить реально крутую кластерную систему не рассматривался по причине дороговизны оной.
В этом месте повествования не могу не вставить небольшой оффтоп на эту тему. Мне известны как минимум о двух отказах подобных систем в крупных банках (названия, по понятным причинам, я приводить не буду). И дело там было не в ограниченных бюджетах (банки потратили на обеспечение отказоустойчивости своих систем суммы в несколько миллионов долларов), а в том, что реальность — безжалостная штука.
В первом случае — пьяный экскаваторщик порвал оптическое волокно одновременно основного и резервного канала связи. Это произошло несмотря на то, что архитекторы ЦОДа банка абсолютно правильно организовали вывод линий связи из здания, чтобы они расходились в разные стороны. Как же удалось одним взмахом ковша оборвать обе линии? Да очень просто. На противоположной стороне улицы эти линии сходились в одном колодце. И на это архитекторы ЦОДа никак повлиять не могли. Они даже не знали об этом.
Второй случай не столь эпичен, но тоже интересен. У банка был классический Active-Standby кластер. После отказа основной ноды из-за банального выхода из строя оборудования (абсолютно некритичная ситуация для любого, даже самого дешевого, кластера), резервная нода просто не поднялась. Расследование ситуации выявило причину — в стойке, где была смонтирована резервная нода, физически не хватало оборудования, был неполный комплект дисковых накопителей. Дальше выяснили, что отсутствующие дисковые накопители были использованы в качестве оперативного подменного фонда для поддержки работоспособности других систем банка. И опять возникает вопрос — ну как же так? Неужели люди не знали, что в этой стойке смонтирована резервная нода кластера, на котором работает одна из важнейших IT-систем банка? Знали. Но по счастливому (или несчастливому, смотря с какой стороны посмотреть) стечению обстоятельств, ни разу до рассматриваемого нами инцидента не возникало необходимости запускать резервную ноду кластера. Сотрудники годами наблюдали эту стойку выключенной. Возможно даже, люди, точно знавшие назначение оборудования в стойке, уже уволились. И, что довольно естественно в описанной ситуации (инфраструктурщики поймут), стойка пошла «под нож» для решения «горящих» проблем с продуктивным оборудованием.
Резюмируя это не такое уж маленькое, но очень нужное для дальнейшего рассказа отступление, хочу сделать два фундаментальных вывода, которые, на мой взгляд, обязательно должны учитываться при построении IT-систем любого уровня:
- Абсолютно надежных систем не существует (банально, но, почему-то, об этом часто забывают).
- Реальная (не на бумаге) надежность системы слабо зависит от ее стоимости (об этом забывают еще чаще).
Вернемся к процессингу подарочных карт М.Видео. У нас была вводная, что в ЦОДе М.Видео имеется два интернет-канала от разных провайдеров. Как там выходят провода из здания, мы, конечно, не знали, но два канала — для начала неплохо. Попробовали строить систему из двух зеркальных сегментов, которые должны были «сидеть» на разных каналах связи и каким-то образом резервировать друг друга. Но полноценно реализовать эту идею не получилось, потому что нужно было разделить базу данных процессинга на два зеркальных сегмента и обеспечить между ними высокопроизводительную (и даже очень) онлайн-репликацию. Забегая вперед скажу, что в качестве СУБД мы выбрали Microsoft SQL Server 2000. Изучив, как устроен механизм репликации этой этой СУБД, пришли к выводу, что не сможем обеспечить необходимую производительность. К тому же организация репликации потребует очень больших накладных расходов. Поэтому базу данных решили оставить централизованную. А вот фронтенд-серверы «развести» удалось довольно легко, потому что они не содержат данных, которые необходимо оперативно реплицировать. Логику переключения клиентов между фронтенд-серверами процессинга мы реализовали в клиентском модуле нашей системы, но об этом чуть позже.
Теперь давайте поговорим про надежность. Поскольку у нас было два канал связи от разных провайдеров, надежность фронтовой части получилась довольно высокая. Уложить ее мог разве что пьяный экскаваторщик (см. выше) или взрыв нашей стойки в ЦОДе. Опасения вызывал централизованный сервер базы данных. В связи с этим, мы изучили все статистические данные, собранные по результатам эксплуатации реальных систем, которые только удалось найти. Выписали три самые частые проблемы, возникающие в продуктиве:
- Отказ/перегрузка канала связи.
- Недостаточная производительность системы в периоды пиковых нагрузок (праздники, вечера пятницы и так далее).
- Ошибки/сбои программного обеспечения.
Отказ оборудования тоже был в общем списке, но не вошел в ТОП-3. Поскольку все три проблемы почти полностью решаются применением схемы с зеркальными фронтенд-серверами, мы решили рискнуть — оставили сервер базы данных централизованным (с оговоркой, что он должен быть мощным, на сколько позволяет бюджет, чтобы хватило производительности при всплесках нагрузки). Ставка оказалась верной. На этой аппаратной платформе процессинг проработал с марта 2008 года по май 2014 года включительно. За это время были инциденты, связанные со всеми перечисленными выше пунктами. Но отказов оборудования так и не случилось. Кто-то скажет, что просто повезло. Не буду спорить, но всё же.
Напоследок хочу рассказать, что больше всего не нравилось в описанной схеме. Прошаренные сисадмины не раз упрекали меня за использование в каждой ветви схемы отдельного роутера с отдельным IP-адресом. Мол, не дружественно это по отношению к клиенту — заставлять его уметь переключаться между двумя разными адресами (хотя на тот момент за переключение отвечал наш клиентский модуль, а не клиентское ПО, работающее с процессингом). Предлагали поставить либо балансировщик, который автоматически разруливал бы трафик между фронтенд-серверами, либо собрать схему из двух роутеров, общающихся по протоколу HSRP, чтобы для клиента был единый IP-адрес. Мое мнение об этом таково. Балансировщик — вообще в топку. Создание централизованного звена в распределенной системе есть максимальное зло, это очевидно. HSRP как бы создает распределенное звено (два роутера), но компоненты довольно сильно зависят друг от друга (роутеры постоянно общаются между собой и реализуют определенную протоколом логику совместной работы). Такое звено никогда не будет надежнее (или хотя бы не хуже) звена, состоящего из реально независимых элементов (два никак не взаимодействующих друг с другом роутера). Это даже можно доказать математически. Описанная здесь схема за время работы не раз доказала свою надежность, опередив по этому показателю множество систем стоимостью на несколько порядков выше нашего процессинга подарочных карт.
Платформа для веб-сервиса
Как я уже говорил, в качестве СУБД мы выбрали Microsoft SQL Server 2000 без каких-либо примочек, типа репликации данных между несколькими базами. Я ей неплохо разбирался в этой СУБД, и нам было известно множество реальных примеров использования SQL Server«а в высоконагруженных корпоративных системах, в том числе банковских. Неплохой аргумент «за», как мне кажется. По тем же причинам веб-сервис решили организовать на базе сервера IIS от той же Microsoft. Пока ничего необычного, верно? Интереснее другое. В качестве технологии написания скриптов, реализующих логику сервиса процессинга, мы взяли не ASP.NET, которая тогда уже начинала набирать популярность, а сейчас давно уже всеми забытую ASP Classic. Очередное спорное на тот момент решение, которое во многом предопределило будущий успех системы. Если вы на просторах интернета почитаете всевозможные сравнительные обзоры ASP.NET vs ASP Classic, то основные аргументы в пользу ASP.NET будут приблизительно следующие:
- Более современная технология.
- Предоставляет больше возможностей.
- Более упорядоченная структура веб-приложения.
- Большая производительность.
Звучит круто, правда? Правда. Всем нравится, все покупают. Продавцы и маркетологи Microsoft получают свои бонусы. Всем хорошо. А теперь давайте разберемся по существу.
С пунктом 1 всё понятно, новое — всегда хорошо. Новая куртка, машина, девушка, …, версия Java. Это всегда вызывает положительные эмоции, так устроена наша психика. С ничего поделать нельзя… да и не надо. Просто не нужно считать это «преимуществом» при выборе технологий для будущих продуктов. Это как выбирать машину не по техническим характеристикам, а на основании модных веяний. Я понимаю, что многие так и делают, но считаю, что разработчик должен всегда сохранять трезвый рассудок и рационально подходить к любому вопросу. К сожалению (моему; возможно, кому-то это нравится), сейчас я часто вижу именно такой «модный» подход к выбору технологий. И что в итоге? А в итоге получается дорого и глупо, потому что самые новые технологии стоят, как правило, дороже, а их преимущества при использовании в том или ином проекте не всегда четко осознаются заказчиками и/или исполнителями. А еще, как известно, новое — это хорошо забытое старое. Но это отдельная большая история, не будем о грустном.
Пункт 2 — возможности. Возможности — это всегда хорошо. Но нужно ли вам, например, в онлайне отслеживать погоду в городе Балтимор, штат Мэриленд, США? Вряд ли, если только вы туда в ближайшее время собираетесь или там живут ваши родственники. А многим ли среди ваших знакомых нужна такая возможность? На этом простейшем примере я хочу показать очевидное: когда кто-то завлекает вас новыми возможностями, нужно четко осознавать их пользу для решения вашей задачи. Изучив возможности ASP.NET, которых нет у ASP Classic, мы решили, что для нашей задачи у ASP.NET нет преимуществ перед ASP Classic.
Пункт 2 — структурность веб-приложения. Когда-то очень давно, на заре становления PHP, в одной очень хорошей книжке про этот язык, подаренной мне на день рождения другом, я прочитал утверждение о том, что всем веб-приложениям, разработанным с применением скриптов, выполняемых на стороне сервера и встроенных прямо в статический HTML, присущ серьезный недостаток — худшая по сравнению с настольными приложениями, написанными, например, на C++, структурность кода. И я с этим полностью согласен. Если C++ провоцирует разработчика на соблюдение определенной структурности (заголовочные файлы, директивы препроцессора, функция Main () в конце концов), то PHP, ASP Classic и тому подобные языки никак не подталкивают к какому-либо оформлению кода. При желании можно писать как угодно хаотично или структурно (правда, структурность придется контролировать самостоятельно). Тема полностью отдана на откуп программистам. С момента выхода той отличной книжки утекло много воды. Технологии продвинулись, и ASP.NET действительно лучше, чем ASP Classic, помогает разработчикам создавать приложения со структурированным кодом.
Но вернемся к нашим баранам. Разработчиков системы было всего двое (причем 90% кода написал один из них — я). Было понятно, что, при желании, мы сможем обеспечить структурность исходного кода приложения. И для нашей конкретной задачи это нивелирует преимущество ASP.NET перед ASP Classic. Ну и вишенка на торте — производительность. Я не буду растекаться мыслями по древу (и так длинно получается), и скажу сразу — да, производительность приложений ASP.NET в общем случае (обожаю эти слова в подобных утверждениях) выше, чем у приложений ASP Classic по фундаментальной причине — компилируемый (прекомпилируемый, если быть точным) код работает быстрее, чем интерпретируемый.
Но, как всегда, есть нюансы.
При первом запуске .NET-приложения (например, после перезагрузки сервера) из-за потерь на загрузку в память фреймворка и байт-кода, система некоторое время работает со скоростью ниже «крейсерской». Приложения ASP Classic избавлены от этого недостатка благодаря отсутствию байт-кода, и при каждом запуске интерпретатор обрабатывает скрипт одинаково (если, конечно, не настроено кэширование скриптов). Конечно, проблема небольшая, но, тем не менее, она существует и особенно ощутима для систем, обрабатывающих мощный непрерывный поток запросов (а наш процессинг как раз этим и занимается). Это, а также превышение на несколько порядков целевого значения производительности Classic-приложения, сделали выбор в пользу ASP Classic легким и непринужденным. В завершении темы противостояния ASP.NET и ASP Classic опишу несколько преимуществ ASP Classic перед .NET собратом (да, и в эту сторону преимущества тоже имеются, причем довольно весомые, на мой взгляд):
- Можно обновлять веб-приложение без перезапуска веб-сервера и, соответственно, без перерыва в обслуживании. Эта фишка до сих пор делает нашу систему клевой на фоне прочих корпоративных систем у которых нередко с этим проблемы.
- Для доработки системы не нужно ничего, кроме стандартного Блокнота (такой с голубой иконкой, его все знают, но никто не использует). Грамотный разработчик, который умеет писать код без всплывающих подсказок после набора на клавиатуре названия объекта и точки, может вести доработку приложения хоть с мобильного телефона. Вы можете писать .NET-код на мобильном телефоне? А прекомпилировать его на том же телефоне сможете?
- Общая «легковесность» приложения. Исходники ничего не весят. Их можно закачать на сервер практически по любому, даже самому медленному каналу связи. С 2008 года как я только не закачивал обновления на процессинговую систему М.Видео: через мобильную связь (2G/3G и старше), Yota-интернет, перегруженный торрентами офисный канал и даже Dial Up-соединение (было даже такое, правда, к счастью, всего один раз).
Архитектура веб-сервиса
«Архитектура» здесь присутствует только в названии раздела, потому что в системе на тот момент архитектуры не было в принципе. Да-да, в нашей системе был реализован полный список «фич» на тему «чего не нужно делать при разработке архитектуры веб-приложения». ASP-скрипты были абсолютно бесконтрольно размазаны по HTML-коду, файлы именовались так, что понять смысл того или иного скрипта по его названию было весьма непростой задачей. Причина — моя неопытность в разработке веб-приложений. Тем не менее, в таком виде система успешно работала в течение первого года, пока у нас не дошли руки до «причесывания» архитектуры.
Клиентский модуль
Сегодня наличие клиентского модуля в системе, в основе которой лежит веб-приложение, не вызывает ничего, кроме недоумения. И это понятно, ведь сейчас практически не осталось ПО, которое в принципе не способно обратиться к веб-сервису. Но в далеком 2007 году таких систем было больше, и в их число входила касса М.Видео. Единственным способом взаимодействия кассы с процессинговыми системами был файловый обмен. Причем речь идет не только о нашей системе, а еще и о процессинге банковских карт! Если сейчас кому-нибудь рассказать о передаче банковской информации через незашифрованные файлы, это лишь вызовет ухмылку. Но речь не об этом. Касса М.Видео не могла самостоятельно обращаться к создаваемому нами веб-сервису. Она могла лишь создать файл-запрос и дожидаться получения файла-ответа в папке обмена данными. Встал вопрос о разработке клиентского модуля, который, по сути, должен был стать транспортировщиком данных вида [файл] <---> [сервис]. И опять классическая задача — разработать легковесный и очень надежный (касса розничного магазина, как-никак!) клиентский модуль, который будет выполнять эту довольно корявую задачу.
И здесь мы применили самое, на мой взгляд, интересное во всем продукте решение — написать клиент на VBScript. На том самом, который может исполняться стандартным интерпретатором Windows. Уверен, вы удивлены. Скажу больше: в проектной команде со стороны заказчика не было ни одного человека, отреагировавшего иначе. Чего только я не услышал об этой идее во время работы над проектом: «это несерьезно!», «вы что, издеваетесь?!», «я не ослышался, вы на VBScript собрались писать модуль корпоративной системы?!», «это решение невозможно будет поддерживать» и тому подобные высказывания. Я тогда даже записал самые агрессивные и забавные фразы, но, к сожалению, потерял этот файлик. Так вот. Эта идея в итоге оказалась не только самой необычной во всем продукте, но и одной из самых эффективных. И вот почему.
Самая большая проблема таких вот клиентов — их дистанционное централизованное обновление. Например, со стороны кассы изменился формат файла обмена данными, типичная ситуация. Значит, нужно обновить все клиенты на всех кассах, а их, на минуточку, у М.Видео порядка тысячи было в 2008 году. Ясное дело, отправлять инженеров во все магазины — это закат солнца вручную. Нужен механизм, который позволил бы клиентскому модулю, общаясь с веб-сервисом, понять, что он устарел, скачать новую версию и заменить ею самого себя. Последнее действие самое трудное: в Windows работающий процесс не может заменить свои файлы. Это можно сделать только после прекращения работы приложения. Соответственно, приходится реализовывать всевозможные костыли типа вывода сообщения «Необходимо установить обновление, перезагрузите компьютер» и последующего запуска механизма, обновляющего файлы клиента перед очередным его запуском. И всё это не проблема для разработчика. Это проблема для пользователя. Нет «счастливее» кассира, который в субботу вечером перед Новым Годом, когда магазины забиты до отказа, обслуживая очередного клиента увидел на экране кассы вышеупомянутое сообщение. Нет «счастливее» клиента, при обслуживании которого оно появилось. Это реальная проблема. И до сих пор (а на дворе уже 2017 год, господа) большинство систем устроено именно таким образом.
Но я выступал и выступаю за качественное ПО, так что и эта проблема в нашей системе была решена. Помог нам в этом как раз тот самый «обиженный» всеми VBScript. А именно, одно его замечательное свойство: возможность переписывать VBS-файл, не прекращая его выполнение. Мы реализовали механизм, в рамках которого скрипт по ответу от веб-сервиса понимал, что нужно обновиться, скачивал новую версию себя (опять же, VBS-файлы ничего не весят), переписывал собственный файл на диске, запускал новую версию себя и, финальный аккорд, завершал старую версию себя. С точки зрения пользователя это выглядело… никак. И в этом самая большая ценность нашей задумки. Пользователь вообще никак не мог понять, что произошло обновление. Касса, обслуживая очередь, транзакцию N проводила на предыдущей версии клиентского модуля, а транзакцию N+1 — на новой версии. И все это без каких-либо задержек и прочих видимых признаков произошедшего. Обновление управлялось централизованно, при помощи закачки на сервер нового VBS-скрипта и повышения актуальной версии в соответствующей таблице базы данных.
Первые шаги в продуктиве и первые доработки
Если честно, после того, как в марте 2008 года система заработала в продуктиве, я ожидал огромного потока инцидентов, в котором, как мне тогда казалось, должна была захлебнуться наша немногочисленная команда (напомню, нас было всего двое). Но этого не случилось. Нет, инциденты, конечно, были, но ничего эпичного. Довольно быстро стало понятно, что необходимо хотя бы немного упорядочить структуру скриптов. Прилетели первые запросы на доработку веб-интерфейса системы. По традиции, заказчик смог понять, что же ему действительно нужно, только после того, как получил первую версию продукта. Здесь ничего необычного создано не было, поэтому не вижу смысла вдаваться в подробности. Главное, что я хотел бы отметить: система в продуктиве заработала сразу и очень хорошо, несмотря на все опасения, связанные с «революционностью» некоторых решений.
Эволюция системы и чем опасны праздники
В этой главе я хочу описать путь, который система прошла с 2008 года по настоящее время, и рассказать об одном (только об одном, иначе, придется выпускать книгу), но очень серьезном и весьма занятном с технической точки зрения инциденте, случившемся в 2013 году.
Итак, в марте 2008 года в базе данных процессинговой системы хранились сведения примерно о 16 миллионах подарочных карт М.Видео. Производительность системы достигала 30 транзакций в секунду при целевом значении в 16 транзакций в секунду. Сейчас в базе данных около 120 млн. сущностей (не только карт), а производительность достигает 700 транзакций в секунду. Путь, как видите, длинный и всё время в гору. Основные переломные моменты на этом пути я постарался отразить на временной шкале (рис. 2).
Рис. 2.
Развитие — это клево, но больше всего ценнейшего опыта мы получаем, как правило, в те моменты, когда что-то идет не так, как предполагалось. А если всё идет настолько не так, что не работает процессинг крупной федеральной компании, то количество опыта, получаемого в единицу времени, умножается как минимум на 10.
На дворе была пятница, 8 марта 2013 года. Расслабленное утро выходного дня не предвещало ничего плохого. Около полудня у меня зазвонил мобильный, и напряженный голос IT-директора сообщил, что «не работает процессинг». Меня, конечно, немного обеспокоило, что звонил лично IT-директор (обычно по подобным инцидентам мне названивали из техподдержки), но всё равно я поначалу не воспринял эту информацию всерьез. И связано это с тем, что в течение первых лет работы системы мне с завидной регулярностью звонили из техподдержки с точно такой же формулировкой. И в 99,9% случаев выяснялось: уборщица выдернула шваброй Ethernet-кабель из кассы, упал канал связи в магазине, у недавно открытого магазина некорректно прописали адреса конечных точек процессинга, и тому подобное. Я лениво достал ноутбук, удаленно подключился к своим серверам, стал смотреть текущий поток транзакций и увидел, что процессинг… работает! Транзакции идут, причем весьма мощным потоком. Проведя некоторое время в телефонных разговорах с техподдержкой, я понял, что процессинг просто не справляется с нагрузкой. К моей гордости он не упал (как любят делать в подобных ситуациях многие системы), но не мог обработать все прилетающие к нему транзакции (как мы потом посчитали, процессинг успевал обрабатывать около 2/3 от общего транзакционного потока).
Получилась «лотерея» для клиентов М.Видео — повезет/не повезет. У кого-то всё было хорошо, у кого-то — таймаут от процессинга. Но по внешним признакам техподдержка не смогла диагностировать, что процессинг хоть как-то, но всё-таки работает потому, что ⅓ от общего числа клиентов в тот день — это, извините, порядка 80 тыс. человек. Эта толпа «обиженных» клиентов создала столько инцидентов, что за считанные минуты перегрузились телефоны техподдержки, возникла целая лавина однотипных инцидентов из магазинов, разбросанных по все стране (что выглядело особенно угрожающе), и через 15 минут про ситуацию уже знала вся вертикаль управления компании вплоть до владельцев. Я оперативно аварийно повысил производительность системы, но не могу сказать ничего об их эффективности, потому что к 14 часам трафик естественным образом снизился, и проблема растворилась так же молниеносно, как и появилась. Мне до сих пор до конца не ясны некоторые нюансы сложившейся тогда социально-технической ситуации. Ниже я поделюсь тем, что удалось выяснить при разборе полетов.
Первым фактором, спровоцировавшим красочно описанную мной выше ситуацию, стала акция М.Видео с использованием карт малого номинала — 500 руб. Вот уже несколько лет акции с картами такого номинала в компании не проводятся. В 2011–2013 годах они были. Суть в том, что под такие акции выпускается больше карт, чем для акций, скажем, на 1000 рублевых картах. Соответственно, когда клиенты тратят выданные карты, процессинг нагружается больше. Вторым негативным фактором стал Международный Женский День. И вот этот фактор для меня до сих пор до конца неясен. Давайте рассуждать.
Любой, кто имеет отношение к обслуживанию сервисов, работающих 24/7/365, знает, что самое страшное время — Новый Год, а точнее период с 25 по 31 декабря. Это понятно и логично — люди затариваются подарками к празднику. Согласно статистике, Новый Год — самый популярный праздник в России. На опыте М.Видео могу с уверенностью сказать — абсолютная правда. Каждый год в декабре в М.Видео проводится мощная федеральная акция с подарочными картами, что еще больше увеличивает нагрузку на процессинг: к и без того повышенной активности покупателей добавляется активность, спровоцированная промо-акцией. Ничто не могло сравниться с новогодней нагрузкой второй половины декабря. А тут превышение, как мы потом посчитали, в 1,5 раза, да еще и в марте! Понятно, что тоже праздник. Понятно, что огромное количество галантных кавалеров пришли в магазины для приобретения подарков девушкам. Но почему повышенная нагрузка длилась столь недолго (пик держался с 12 до 14 часов 8 марта)? Мужская половина человечества не утруждала себя покупкой подарков заранее и все пошли прикупить презент как раз ко времени праздничного обеда? Почему в середине дня 23 февраля того же года не наблюдалось ничего подобного? Девушки больше любят получать в качестве подарков технику? Или они более ответственные и покупают подарки заранее?
У меня нет однозначного ответа на эти вопросы, поэтому я предлагаю вам порассуждать на эту тему самостоятельно (пишите свои варианты в комментариях). Я считаю, что основной причиной коллапса процессинговой системы стало сочетание малого номинала (а значит большого количества) подарочных карт во время промо-акции, и повышенной покупательской активности, связанной с праздником. Социально-психологические аспекты произошедшего мне непонятны до сих пор. Кроме 8 марта 2013 года, других подобных по масштабу и последствиям инцидентов за всю историю системы не случалось. Во многом благодаря масштабной переработке системы, затронувшей казавшиеся незыблемыми архитектурные принципы, лежавшие тогда в ее основе. Работа была проделана колоссальная. По сути была с нуля переписана продуктивная система, прошедшая длинный эволюционный путь и накопившая весьма приличную массу кода. Но результатом этой работы стала архитектурная платформа, в рамках которой система функционирует по сей день. И я благодарен судьбе за то, что в 2013 году появилась необходимость столь серьёзно переработать архитектуру. Потом это помогло избежать многих серьезных проблем и до сих пор позволяет мне гибко и быстро развивать систему. Как видите, нет худа без добра. Праздники не только опасны, но, бывает, и весьма полезны с технической точки зрения.
Вместо заключения
Очень не люблю, когда в длинных статьях в заключении развозят выводы из прочитанного на несколько страниц. Утомленный читатель, даже если и найдет силы добраться до конца, уж точно ничего не запомнит. Эта статья получилась длинной потому, что короче изложить довольно продолжительный жизненный путь системы у меня никак не получается. Это, конечно, можно сделать, но придется опускать подробности. А дьявол, как известно, в мелочах. Поэтому я не стал сокращать статью. В качестве компенсации за терпение и целеустремленность, никаких выводов здесь формулировать не буду. Я уверен, что каждый по ходу изложения обратил внимание на ситуации ему знакомые (с хорошей или плохой стороны) и/или интересные. Мне кажется, что процессинг М.Видео в течение своей жизни собрал довольно много показательных ситуаций, описание которых может кому-нибудь помочь. Собственно, это и есть главный мотиватор к написанию статьи.
Ну и, напоследок, хочу процитировать одного очень известного, правда не в IT-кругах, человека. Сэмюэлю Кольту, изобрета