Highload-системы: от первых опытов до мейнстрима
Сегодня разработчиков бизнес-приложений сложно удивить или испугать высокими нагрузками: с ними сталкивается практически любая система, рассчитанная на взаимодействие с большим количеством пользователей. Чаще такое встречается в решениях, предназначенных для обслуживания физических лиц, несколько реже – в B2B-решениях или внутренних корпоративных порталах, так как количество пользователей там, как правило, меньше. Тема высоконагруженных приложений стала настолько актуальной, что со временем появилась тематическая конференция Highload, которая сейчас пользуется большой популярностью: ее на регулярной основе посещают тысячи человек. Почему Highload стал мейнстримом и как он влияет на разработку – поясняет Степан Бочаров, ведущий руководитель группы компании IT_ONE.
С развитием интернета и распространением его в различных областях стали расти и потребности клиентов. В то же время развитие технологий открыло новые возможности: выросли скорости сетей, мощности процессоров, объемы оперативной памяти. На мой взгляд, такое наложение потребностей и возможностей привело к достаточно быстрому развитию высоконагруженных систем. Но такие потребности, когда нужно обрабатывать большое количество запросов или событий, не происходит с любым стартапом. Драйверами развития этого направления стали те компании, которые имели достаточно обширную базу клиентов – как правило, физических лиц. Имея большую клиентскую базу, они могли предлагать продукты, которые позволяли клиентам получать услуги быстрее и качественнее.
Например, мы видели, как в конце нулевых-начале десятых активно развивают свои цифровые продукты телеком-компании и банки. В определенный момент такой гигант, как Сбербанк, провел ребрендинг и стал себя позиционировать как ИТ-компания, а не как банк. Параллельно с развитием таких крупных компаний менялся и их бизнес-подход. На начальных этапах они, чтобы не содержать в штате большие отделы, заказывали разработку конкретного продукта ИТ-аутсорсерам, специализирующимся на разработке ПО. Но в дальнейшем потребностей становилось все больше, и у таких компаний стали выделяться собственные, достаточно крупные ИТ-подразделения. Иногда внутренняя разработка даже выводилась из оргструктуры основной компании в отдельную дочернюю компанию. В то же время цифровизироваться начали и другие направления бизнеса: объявления из газет перенеслись на интернет-платформы, произошла цифровизация взаимоотношений гражданина и государства и появился всем известный портал Госуслуги, у Яндекса появились дополнительные популярные продукты – Карты, Такси и другие.
Это было время больших трансформаций и развития как с точки зрения бизнеса, так и с точки зрения технологий. Выше я привел примеры бизнес трансформаций, ниже сосредоточусь на примерах технических изменений, в которых мне самому приходилось участвовать.
В своей профессиональной деятельности с высокими нагрузками я столкнулся, работая в сфере телекома. Проект был связан с управлением маркетинговыми кампаниями. Он стартовал до моего прихода и показал себя эффективным с точки зрения бизнеса. Как результат, со временем у заказчика появлялось больше потребностей, и проект обрастал функционалом. Когда я начал им заниматься, это была классическая реляционная БД и веб-приложение, работающее на Java. На тот момент еще не было активного разделения на фронтенд и бекенд разработку. Через приложение можно было управлять маркетинговыми кампаниями, запускать нотификацию по ним. Но все это работало по расписанию на основе расчета профиля абонента.
В какой-то момент у заказчика появилось желание получить больше интерактива и перейти на событийное взаимодействие с абонентом. Например, если у абонента заканчивались деньги на счете, можно было послать ему SMS с предложением пополнить баланс или воспользоваться «обещанным платежом», если исчерпан лимит. Это выглядит как простой пример, но событий, которые генерируются абонентом, может быть достаточно много. И если помножить их на количество абонентов, в результате получалась достаточно высокая нагрузка. Обрабатывать такой поток данных в онлайн-режиме с использованием реляционной БД выглядело не реалистичным. Было решено кешировать данные в ОЗУ. На тот момент не было такого большого количества in-memory хранилищ и, недолго выбирая, мы пришли к Redis.
На тот момент мажорная версия Redis была вторая. Т.е. проект был в начале своего развития и не обладал той широкой функциональностью, которую имеет сейчас. Да, это было in-memory хранилище, и первые проверки показали отличный результат. Время записи и чтения были просто на совершенно другом уровне по сравнению с реляционной БД, работающей с жестким диском. Но за все хорошее нужно платить. И вот, с чем мы столкнулись.
С появлением in-memory хранилища у нас появляется еще один уровень хранения, а это значит, что его нужно обслуживать. Так как основным хранилищем данных по абонентам остается реляционная БД, нужно озаботиться переносом данных оттуда в in-memory хранилище. Как результат, у нас для этих целей появляется отдельное приложение. И так как система развивается, это не ограничивается единоразовой активностью. Добавляются все новые источники данных, и в каждом таком случае нужно дорабатывать их загрузку в in-memory хранилище.
In-memory хранилища энергозависимые. В случае отключения электричества, все данные будут потеряны. Если бы данные только читались, то в случае сбоя можно было бы загрузить их заново и продолжить работу. Да, на время загрузки мы получаем период простоя, но все-таки это не столь критично. По статистике, данные гораздо чаще читаются чем записываются, но все же записываются. Тогда в случае сбоя мы уже не можем просто загрузить данные в in-memory хранилище и продолжить работу. Таким образом, появляется еще один компонент в обвязке in-memory хранилища — это приложение, которое будет записывать обновленные данные из in-memory хранилища в нашу энергонезависимую БД.
Redis однопоточный. На первый взгляд, это не выглядит сложностью: чтобы прочитать или записать данные в ОЗУ, нужны миллисекунды. Но, как оказалось, при высоких нагрузках это может быть проблемой. С развитием системы у бизнеса появлялись новые пожелания по развитию продукта, требовалось все больше данных для обработки, все больше событий приходилось обрабатывать, все больше становилось сценариев обработки. Нагрузка росла кратно. Кроме того, высокую нагрузку на in-memory хранилище создавали загрузчики данных из БД, и в момент их работы мы получали существенные задержки в обработке бизнес-запросов. Тут все решилось достаточно просто – вынесением работы загрузчиков на ночное время, когда поток бизнес-запросов кратно снижается. Но это только отсрочило неизбежное. В какой-то момент мы все же уперлись в потолок однопоточного хранилища.
А что нужно делать если один не справляется? Правильно: нужны помощники. Таким образом у нас появились несколько нод Redis. И это похоже на… кластер! Действительно мы осознали, что нам нужно не просто in-memory хранилище, а кластер. Но на тот момент Redis не предлагал кластерного решения и нам пришлось двигаться своим путем. Мы начали реализовывать собственную имплементацию кластера Redis. Это был долгий путь, на котором мы встречали проблемы, которые ранее не приходилось встречать в менее нагруженных приложениях. Например, нужно было решать вопросы шардирования данных, механизмы хранения для данных так, чтобы не случалось перекоса в сторону одной из нод.
Больным вопросом оказался вопрос масштабирования. Как я писал выше, с ростом потребностей бизнеса росло количество данных необходимых для обработки. Наше небольшое in-memory хранилище на одном хосте выросло до кластера в сотни гигабайт, расположенных на десятках машин. Все это происходило не разово, а растянуто по времени. В результате нам пришлось пережить несколько миграций данных по кластерам. Под это реализовывались процессы и инструменты миграции. Плюс к этому, кластер – это уже достаточно сложная система, которая требует инструментария для мониторинга и локализации проблем производительности.
Это был основной проект, на котором я был занят. Периодически мне приходилось переключаться на развитие новых инициатив, там мы пробовали новые подходы и технологии. В одной из версий Redis появилась поддержка кластера, и были проекты, в которых мы уже использовали его, а не собственную имплементацию. Также все больше появлялось альтернатив Redis. Были проекты с использованием Apache Ignite. Появился отечественный аналог в виде Tarantool. Каждая из таких систем заслуживает отдельной статьи. Думаю, что аналоги не появлялись сами по себе. Это был ответ на интенсивное развитие высоконагруженных приложений, которые требовали нового уровня скоростей работы с данными.
На сегодняшний день тема высоких нагрузок достаточно хорошо изучена и имеет набор шаблонов для решения самых распространенных проблем, часть которых мы рассматривали в предыдущей статье. Но прогресс не стоит не стоит на месте и сейчас мы наблюдаем широкое распространение решений на базе ИИ такие как распознавание образов на фото и видео, работа с LLM и многие другие. Более подробно говорить о необходимости каких-то концептуальных изменений в методологии разработки, связанных с внедрением нейросетей, можно будет уже в ближайшем будущем.