Мне довелось поработать (fb) в интернет издании Лента.ру. Пройти путь от разработчика до технического директора. Успешно реализовать полноценный перезапуск. Попутно занимаясь подобными проектами меньшего масштаба. Теперь мы с командой занимаемся подготовкой перезапускаинтернет газеты Ведомости (fb).
Расскажу о разработке проектов медиа изданий. Галопом по Европам, зацепимся за основные темы. К вам, дорогие читатели, просьба набросать вопросы, которые необходимо раскрыть более детально. Например мой коллега планирует написать о развёртывании системы, отказоустойчивой схеме работы сайта.
Технологии
Один из вопросов, который интересует руководство издания – на каком языке будет вестись разработка. Возникает вопрос сугубо из практических соображений – стоимость разработчиков. Ответы на этот вопрос довольно просты.
Во-первых, выбор языка основывается на том, как хорошо его знают ведущие разработчики. Если у вас есть разработчики, и они владеют языком А, то глупо требовать от них знания языка Б. Заменить ведущих разработчиков – задача не простая.
Во-вторых, есть на рынке популярные языки: PHP, Python, Ruby и остальные, менее популярные. Есть некоторое заблуждение, что одни, дешевле других, или разработчиков одного языка, проще найти, чем разработчиков другого. Заблуждение в том, что измерить уровень профессионализма между разработчиками разных языков очень сложно. Всё становится запутанным, когда сравнивают опыт и желаемое вознаграждение каждого. В результате имеем: подходящего разработчика одинаково сложно найти для любого языка программирования. Их либо много, но все они низкой квалификации, или они много просят, или они специалисты другого профиля и т.д.
Есть ещё один фактор в выборе платформы для разработки. Обычно издания входят в состав какого-то немаленького холдинга. И в зависимости от степени развитости корпоративной культуры, изданию будет навязываться соответствующее решение.
В своё время Лента.ру переходила с Perl на Ruby, тогда как в Рамблере практиковали Python. Сейчас Ведомости переходят с PHP на Ruby, при этом PHP нам не навязывали.
Выбор сопутствующих инструментов, таких как операционная система или база данных, обычно никого не волнует.
В конечном счёте для издания не важно на каком языке будет написан проект, какие библиотеки и сервисы он будет использовать. Важнее, что команда, которая делает проект, владеет инструментом на профессиональном уровне.
Постановка задачи
Процесс полного перезапуска — дело долгое. Но это не повод расслабляться в начале, и работать на пределе под конец. Руководители определяются с целями, которые они хотят достичь, задачами, которые хотят решить. Коллективы редакций – это десятки людей. А численность всего штата издания легко может перевалить за сотню. Если перезапуск подразумевает существенные изменения, это значит что очень большому количеству людей нужно будет изменить подход к работе.
Чтобы сделать что-то хорошее, нужно абстрагироваться от текущего состояния, смоделировать идеальный мир, и уже после этого, строить стратегию перехода из одного состояния в другое. Иначе можно топтаться вокруг старого колодца. Эту задачу решает главный редактор и руководство издания. Анализируя статистику, изучая лучшие практики и ставя перед собой амбициозные цели, они формируют концепцию.
В результате дизайнеры получают задачу визуализации нового лица издания. Разработчики продумывают стратегию воплощения идеи. Сложность задачи в том, что помимо прочего необходимо создать инструмент каждому отделу – редакции, маркетингу, службе поддержки. То есть, помимо создания публичного сайта в разном представлении, нужно создать систему управления для редакции, коммерческого отдела, службы маркетинга и поддержки.
Реальность такова, что в публичном сайте будет продумана каждая деталь главным редактором и прорисована дизайнером. Создание систем управления контентом частенько даётся на откуп разработчикам. Тут конечно не полная самодеятельность: сбор требований, описание сценариев работы – всё в лучших традициях умных книжек. Но простора для фантазий очень много.
Пазл
При создании проекта медиа издания удобно строить сервис-ориентированную архитектуру. Это позволят заниматься параллельной разработкой независимых частей проекта. Главное иметь общую картину и зафиксировать интерфейс взаимодействия между сервисами. Компоненты системы могут использовать общий код, обращаться друг к другу по какому-то протоколу поверх TCP соединения, использовать общее хранилище данных.
Публичный сайт практически всегда стоит отделить от всех внутренних сервисов. Для работы сайта нужно приложение генерации HTML страниц или JSON для API. В зависимости от архитектуры проекта, приложение может напрямую соединяться с классической базой данных (MySQL, PostgreSQL, MongoDB…) или же использовать сервис прослойку. Такое приложение можно легко масштабировать. Все внутренние сервисы, в том числе системы управления контентом, можно закрыть по IP адресам, что добавляет плюс в пользу безопасности.
Выбор базы данных основывается на том, какие структуры данных вам необходимо хранить и извлекать.
Например в Ленте.ру для публичного сайта мы использовали MongoDB. Нам нужно было получать документы со сложной древовидной структурой. При этом основной базой данных у нас была MySQL (позже мигрировали на PostgreSQL). В основной базе всё хранилось в нормализованном виде. В MongoDB данные были в удобном для использования виде. Для синхронизации между базами мы использовали фоновый сервис, который следил за изменившимися данными, формировал для них новое представление и записывал в MongoDB. Сервис основывался на очереди в Redis, куда попадали сообщения об изменениях.
В случае с Ведомостями мы пошли иным путём. В PostgreSQL помимо классических структур данных, есть внутренние типы: array, hstore, jsonb. Благодаря им можно упростить хранение связей между ассоциированными сущностями, динамические атрибуты, сложных древовидных структур. Таким образом мы получаем в лице одного сервиса нормализованные данные, при это они представлены в удобном для публичного сайта виде, конечно с некоторым компромиссом по отношению к MongoDB.
Система управления редакционным контентом (CMS) является основным инструментом редакции. С её помощью создаётся контент. Осуществляется управление и организация редакционным процессом. Формируется картина дня на публичном сайте. С публичным сайтом они делят только базу данных. Это самостоятельное приложение, доступ к которому осуществляется только через авторизацию. Ещё лучше, если доступ ограничен определенным списком IP адресов. Именно с этой системы начинается разработка проекта.
К сервису сбора статистики предъявляются особенные требования по производительности. Для начала ответим на вопрос: “зачем он нужен?”. Частенько редакции необходимо собрать статистические данные в разрезе параметров, которых нет в сторонних сервисах. Например в Ведомостях практикуется доступ по подписке. Соответственно есть запрос на сбор данных определенной группы пользователей. Информацию о статусе подписки сторонним сервисам мы не передаём. При этом нам нет необходимости строить полноценную замену открытым метрикам. Только минимальный функционал, покрывающий запросы аналитиков.
Такой сервис так же разбивается на компоненты: сбор событий в промежуточную очередь, обработка и запись в нормализованную базу данных, выборка агрегированных данных. Для двух первых компонент мы используем Golang, для промежуточной очереди – Redis, для нормализованных данных – PostgreSQL, для выборки агрегированных данных – Ruby.
Сервис хранения медиа контента так же вынесен в независимое приложение. В его задачи входит принять файл, сохранить его на диск, вернуть структуру данных, описывающую необходимую мета информацию: путь, размер, тип. Если мы работаем с изображениями, то сервис должен заниматься генерацией разных по геометрическим размерам версий. Некий аналог описывался в хабра статье. Касательно медиа контента есть несколько моментов.
Первый – управление доступностью к определенным файлам. Вы можете опубликовать заметку, в которой используются какие-то изображения. В один прекрасный момент вам может понадобиться скрыть изображение по ссылке, но не удалять его из внутреннего фото-банка. В Ленте мы использовали символьные ссылки. Если файл публичный – для него создавалась ссылка. Если файл надо скрыть, в том числе при скрытии связанной заметки, удалялась символьная ссылка. В Ведомостях разделение на публичные и закрытые изображение реализуется через права доступа к файлам.
Второй – сеть доставки контента. Когда то в Ленте видео пользователям раздавали прямо со своих серверов. И вот настал момент, когда показом интересного ролика в хорошем качестве мы забили свой гигабит, и наш сайт начал тормозить. Само собой правильное решение – использовать CDN, благо сегодня это вполне доступная по цене услуга. В качестве теста одно время мы использовали сторонний CDN сервис и для статических изображений. Но в данном вопросе практическая польза оценивалась слишком дорого, и финансисты нам отказали в таком удовольствии.
Третий – масштабирование изображений. В зависимости от контекста использования изображения масштабируют в несколько версий. Специфика медиа изданий подразумевает, что есть отдельный человек – бильд редактор, который следит за тем, какими получились изображения в результате ресайза и кропа. И если ему что-то не нравится, у него должен быть инструмент, который позволяет заменить определенную версию изображения. Иначе вы в фото-галерее “Мисс Мира” в превью версиях можете получить изображения дам с отрезанными головами.
Медиа контент это так же аудио и видео. Работу по конвертации ролика в разное качество лучше возложить на профессиональную видео-платформу.
Полезно иметь отдельный сервис авторизации для пользователей сайта. Часто он тесно связан с системой комментирования.
Процесс разработки
Ранее я писал, что нужно уделить должное внимание проектированию. При это нужно не бояться писать код. Невозможно предусмотреть всё, сделать хорошую систему с чистого листа. Нужно итерационно развивать систему. Написали задуманный функционал, проанализировали, будьте готовы переписать вновь. Это нормально. Время, которое вы тратите на написание кода много меньше того, которое тратите на обдумывание. Ваш код не высечен на скале.
Короткий абзац: системы контроля версий. Почему-то ещё актуально акцентировать на этом внимание.
Современный подход в разработке предполагает написание тестов. Сложность в том, что в изданиях с наследием у руководителей сложилось некое представление о скорости разработки. И тут приходите вы, с модными технологиями, девизом, что сейчас станет проще. А в результате похожие задачи делаются либо такое же время как и раньше, а то и дольше. Вы понимаете, что тесты – дело благое, и пытаетесь донести эту истину главному редактору. Скорее всего у вас ничего не получится. Редакции нужен продукт, а тесты нужны разработчикам. То, что для качества продукта нужно тратить время на написание тестов – просто данность.
Не изменяйте своё рабочее окружение в активной фазе очередного этапа разработки. С выходом обновлений операционной системы у разработчиков, любителей быть на острие волны новых версий, частенько может потеряться день другой. Это как здоровье солдата в армии. Вы нужны в работоспособном состоянии, ваша рабочая станция не должна выходить из строя, только потому, что вчера вышла новая версия вашей любимой ОС.
Немного странного. Помимо основной деятельности нужно находить время на работу по сторонним проектам. С коварной целью: обкатывать новые технологии и практики. Не всегда есть возможность использовать в боевой системе различные интересные решения. Делайте это в небольших сторонних проектах.
Динамические языки программирования позволяют широко использовать метапрограммирование. Это может существенно усложнить жизнь в будущем как вам, так и вашим коллегам. Старайтесь по возможности предпочесть простой код магическим заклинаниям.
Мониторинг и профилирование
Редакция использует различные метрики для анализа успешности своей деятельности. Разработчики должны заранее позаботиться об инструментах профилирования и мониторинга своих приложений. Это очень опасное занятие – запускать систему без отслеживания состояния. Речь не только о показателях потребления оперативной памяти и процессорного времени. Для создания хорошего приложения необходимо отслеживать весь стек выполнения программы. Потратьте время на настройку такого окружения.
Выборки из базы данных могут меняться по мере изменения требований к проекту. И снова профилирование приходит на помощь – вы быстро узнаете, что нужно оптимизировать.
Подготовьте к нагрузочному тестированию данные, максимально приближенные к реальным. Запустите тестирование на длительный период времени и изучите слабые стороны вашего приложения.
Процесс переезда
Переезд со старой платформы на новую завязан на редакции и архиве. Редакция должна перестроить свою процессы, освоиться в новой системе управления контентом. перенос архива должен быть с сохранением ссылочной целостности.
Для редакции есть три этапа. На первом этапе они тестируют CMS в свободном режиме. В это время может что-то ломаться, по требованию изменяться. Второй этап начинается после чистового импорта всего контента в новую платформу. При этом новый сайт ещё публично не доступен. Редакция работает в двух системах – старой и новой. Связано это с тем, что чаще всего нет обратной совместимости в структуре старого и нового контента. Обычно этот период длится неделю. И уже с момента публичного перезапуска наступает третий этап, когда все счастливы, редакция работает на новой платформе. Старый сайт прекращает свою работу.
Переезд архива готовится довольно длительное время. С каждым прогоном импорта возникают некоторые баги, после исправления которых импорт начинается с начала. У заметок может измениться адресация. При этом хорошим тоном считается, чтобы переходы по старым ссылкам инициировали редирект на новый адрес. Чтобы это реализовать, нужно заранее готовить таблицу маршрутизации. Она понадобится и в будущем. Бывают ситуации, когда необходимо изменить адрес страницы, при этом надо, чтобы переходы по старому адресу также приводили к редиректу на новый. Вы просто делаете у заметки список ассоциированных адресов, один из которых маркируется как главный.
Мобильная версия
Мы совершили ошибку, пусть и вынужденную, когда перезапускали Ленту.ру без браузерной мобильной версии сайта. Но это был осознанный риск, и мы оперативно исправились, кроме того выпустили аж две версии – pda и mobile. Первая была предназначена для старых телефонов, с минимумом изображений. Такие телефоны мы называли “алконокия”. Вторая для смартфонов с большими дисплеями, аля сами знаете что. Со временем мы стали акцентировать внимание на мобильной версии, реализовав автоматический редирект с десктопной версии.
Помимо реализации автоматического редиректа, мы реализовали возможность запоминать выбор версии. То есть, если вы зашли с телефона, вас перекинуло на мобильную версию, а вам оно не надо, вы выбираете десктопную. Теперь при каждом следующем заходе вас никуда автоматически не отправят.
Так же неплохо показать пользователю сообщение о том, что мы его автоматически перенаправили на другую версию.
Эту логику мы реализовали на стороне nginx. С помощью страшного регулярного выражения определялся тип устройства – мобильное или нет и выставляли флаг $ismobile = 1
. Смотрели на значение cookie с именем view_version, которая определяла сохраненное значение о предпочитаемой версии. При первом заходе на сайт это значение не определено. Ниже пример кода, который определял, делать редирект или нет:
if ( $ismobile = 1) { set $mobile_rewrite 1;}
if ( $cookie_view_version = 'm' ) { set $mobile_rewrite 1; }
if ( $cookie_view_version = 'www' ) { set $mobile_rewrite 0; }
Соответственно, если значение переменной $mobile_rewrite
равно единице, то делаем редирект на мобильную версию, попутно выставляя одноразовую cookie, которая служила триггером для отображения информационного сообщения.
Настройка сервисов
В продолжении конфигурации веб-сервера можно отметить несколько моментов. Пока основным протоколом передачи данных в вебе является HTTP/1.1, актуально использовать несколько доменов для раздачи статики. Если вы используете кастомные шрифты на сайте или делаете вызовы к API со страницы клиента, то не забывайте указывать корректные CORS заголовки в настройках соответствующего веб-сервера.
При построение сервисно-ориентированной архитектуры может получиться, что некоторые ваши внутренние сервисы не защищены авторизацией приложения. Как пример – отдельный сервис загрузки изображений. Доступ к нему должны иметь только авторизованные редакторы. При этом у вас есть отдельный сервис авторизации для тех же редакторов. Сервис авторизации примитивен – получает заголовки, и отвечает положительно или отрицательно. С помощью модуля ngx_http_auth_request_module мы можем на каждый запрос к сервису загрузки изображений делать подзапрос к сервису авторизации. Живой пример конфигурации можно посмотреть здесь.
There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton
Для названия хостов на серверах в Ленте мы использовали марки сигарет. Для Ведомостей выбираем из названия звёздных систем. Приложениям имена выбирали среди видов птиц. Например петух у нас занимался генерацией статики в старых версиях. В Ведомостях талисманом выступает большая рыба – big fish. Акулы бизнеса.
Проекты медиа изданий в России не являются высоко-нагруженными. Последний пик посещаемости в Ленте весной был около 20 миллионов просмотров в сутки. Довольно просто построить систему, которая выдерживает такие нагрузки без кэширования. Мы практикуем таки использовать кэш, на короткий интервал времени – несколько десятков секунд. Это снимает с нас проблему инвалидации кэша. Исправление опечаток на сайте выходит с задержкой меньше минуты. При этом это позволяет использовать такую замечательную опцию в nginx, как proxy_cache_lock
. Из десяти одинаковых запросов к веб-серверу, только один будет отправлен на бэкенд. Это позволяет равномерно распределить нагрузку на приложение.
Визуализация небольшой DDoS атаки:
Резервное копирование
Само собой нужно делать бэкапы данных. При этом удобно иметь горячий резерв и периодически выполняемый полный бэкап.
Горячий резерв спасёт вас, когда нужно восстановить максимально свежую версию данных. Самый простой способ – простая репликация в режиме реального времени.
В случае, если шальным движением из данных будет удалён важный кусок данных, восстановить часть из них можно из ежесуточного бэкапа.
Люди
Будьте внимательны. Со временем некоторые процессы превращаются в рутину. Естественным образом возникает желание автоматизировать что-то. По завершению очередного этапа разработки, оглядываешься назад, а руки уже чешутся сделать лучше. Надо стараться терпеливо разбираться в каждой ситуации. Останавливаться, пробовать по другому смотреть на свою работу. Может получиться, что те задачи, которые кажутся вам важными, таковыми не являются. И наоборот.
Планируйте свою работу. Уделяйте достаточно времени проектированию. Нет необходимости на скорую руку собирать прототип с помощью вашего любимого фреймворка только потому, что вам доставляет это удовольствие, и вы знаете, чем займётесь в ближайшие пару часов или дней. Не успеете оглянуться, а вы уже проделаете кучу работы, которую с большой вероятностью надо переделать или и вовсе выкинуть.
Будьте дружелюбны и терпеливы. Работая в коллективе, важно уметь общаться с коллегами. Чаще всего над проектом работает больше чем один человек. А это значит, что у вас будут формироваться отношения между коллегами. От того, насколько вы хорошо относитесь другу к другу, зависит результат всей ваше работы. Это и профессиональные, и личные отношения. Напряжение будет расти по мере приближения даты сдачи проекта. И слаженность работы команды зависит не только от Васи и Пети, но и от вас.
У вас в команде должен выработаться формат профессиональной коммуникации. Самый простой пример – постановка и выполнение задачи. Вы должны внятно формулировать задачи. Казалось бы, очевиднейший пункт. А всё равно грабли стабильно попадают в лицо. То, что у вас в голове есть мысль, не значит, что она летает и в голове коллеги. Задачу, пересказ которой занимает несколько минут, в два слова описать ну очень сложно. Старайтесь выразить свою мысль словами “на бумаге”. А вот уже после того, как коллега прочитает ваш опус – поговорите! Обсудите задачу, убедитесь, что вашу мысль правильно поняли. В обратную сторону принцип тот же. Если вы закончили задачу, расскажите про это. Вы себе не можете представить, сколько времени это вам сбережёт.
Позиционирование отдела
Хотелось бы немного отметить роль разработчиков в издании. Нужно понимать, что разработка по отношению к редакции – некий обслуживающий персонал. Наша задача – дать удобный инструмент. Недопустимо надменно относиться к редакторам, которые не понимают, почему вот так резко вместо связи “один к одному” нельзя сделать связь “один ко многим”. Ну загрузили они вместо картинки видео файл. Система не должна валиться с ошибками от некорректного пользовательского ввода. Если вы ждёте число, а вам прилетела строка – так значит сами виноваты, что допустили такое, а не редактор инвалид. Попробуйте за день написать десяток другой новостей без копи-паста, с анализом источников для подтверждения фактов.
Речь не о том, чтобы выполнять все прихоти редакции. Просто надо с терпением относиться к желаниям и хотелкам коллег – делаете ведь общее дело.
Итог
Перезапуск медиа издания мало чем отличается от других. Всё так же важна сплоченность команды. Вы должны быть на шаг впереди редакции, предугадывая тот новый функционал, который они захотят воплотить в жизнь. Проектируем – делаем, проектируем – переделываем. Чревато недооценивать роль мониторинга состояния серверов, приложения, клиентской части. После перезапуска приходится уделять много внимания анализу поведения вашей новой платформы. Доводите дело до конца.
С нетерпением будем ждать ваших вопросов, быть может для продолжения.
Автор: Kavkaz