Автор материала, перевод которого мы сегодня публикуем, говорит, что он, в середине сентября 2019, наконец-то завершил проект, которым занимался уже год. Целью этого проекта было сокращение размеров манифеста, необходимого для инициализации асинхронного JavaScript-конвейера Wikipedia. А именно, размер манифеста составлял 36 Кб. Его нужно было уместить в менее чем 28 Кб, что соответствует двум 14-килобайтным фрагментам последовательности интернет-пакетов.
Результатом этого проекта стала ежедневная экономия 4.3 терабайт трафика.
Сначала размер манифеста превышал 36 Кб, а после оптимизации его размер стал меньше 28 Кб
На графике показано постепенное уменьшение размеров манифеста. Речь идёт о сжатых данных (то есть это — чистая нагрузка на сеть, которую создаёт передача этих данных с сервера в браузер).
Процесс оптимизации
Инициализационный манифест представлен данными, которые непросто оптимизировать. Основной объём его кода — это не что-то вроде функциональной логики, которая может быть оптимизирована традиционными средствами. Вместо этого почти весь манифест представлен чистыми данными. Эти данные автоматически генерируются системой доставки контента ResourceLoader. Они представляют собой реестр бандлов модулей. Система ResourceLoader используется в Wikipedia для работы с JavaScript, с CSS, с текстовыми ресурсами.
Реестр включает в себя метаданные для всего фронтенд-функционала, развёрнутого на Wikipedia. В манифесте перечисляются имена бандлов, их актуальные версии, тут описываются их зависимости от других подобных бандлов.
Я начал работу с поиска кода, который никогда не использовался на практике (T202154). Сюда входило обнаружение незавершённых или забытых фрагментов кода, связанных с устаревшими возможностями. Тут же было проведено и удаление неиспользуемого кода, обеспечивающего совместимость с браузерами, которые больше не проходили наш тест, обеспечивавший их попадание в группу современных браузеров (Grade A). Я, кроме того, подготовил документ, посвящённый производительности загрузки страниц. Этот документ играл роль справочника, позволяя разработчикам понимать воздействие изменений различных типов на различные стадии процесса загрузки страницы.
Сокращение количества модулей
Следующим шагом стало сотрудничество с командами инженеров Wikimedia Foundation и Wikimedia Deutschland. Нам нужно было выяснить то, какие возможности системы используют чрезмерное количество модулей. Например, поняв это, можно было бы объединить ранее разрозненные бандлы, из которых была построена некая функциональная возможность. Такие бандлы, даже в разрозненном состоянии, всегда загружались вместе. Это привело бы к тому, что в системе было бы меньше конечных точек, метаданные которых надо было бы хранить в реестре, формируемом ResourceLoader.
Вот некоторые интересные моменты, касающиеся применения этого подхода к оптимизации:
- У расширения WikiEditor теперь имеется на 11 модулей меньше, чем раньше. Ещё 31 модуль удалось убрать из UploadWizard.
- При оптимизации программы ContentTranslation удалось скомбинировать 24 модуля.
- В проекте MobileFrontend скомбинировано 25 модулей.
- 20 модулей убрали из RevisionSlider и TwoColConflict.
Очень важно и то, что был оптимизирован клиент Wikidata для Wikipedia. Эта часть работы и сама по себе была прямо-таки эпическим проектом (T203696). Вначале за реализацию этой возможности отвечали 248 отдельных модулей. После того, как удалось избавиться от более чем 200 модулей, их осталось всего 42.
На вышеприведённой диаграмме показаны те небольшие улучшения, которые были внесены в проект за год. Все они приближали нас к цели. Особо хочется отметить два больших падения размера манифеста. Одно такое падение случилось в первую неделю августа. Именно тогда была развёрнута улучшенная версия Wikidata. Второе падение размера можно наблюдать в самом конце графика. Оно случилось в середине сентября. Сейчас мне хотелось бы рассказать именно о нём.
Уменьшение размеров метаданных
То улучшение манифеста, которое пришлось на середину сентября, стало возможным благодаря двум глобальным изменениям, которые были направлены на более разумную организацию данных.
Первое улучшение заключается в том, что раньше метаданные схемы расширения EventLogging входили в состав главного манифеста. Этот механизм подвергли рефакторингу, сделав так, что теперь метаданные схемы включались в состав JS-бандла клиента EventLogging. В результате вклад в размер манифеста, вносимый ранее EventLogging, сократился более чем на 90%. А это означало, что критический путь теперь содержит на 2 Кб меньше данных! Это, кроме того, означало, что расширение возможностей EventLogging больше не приводило к росту размеров манифеста. При сборке подобных бандлов была задействована новая возможность ResourceLoader — Package Files. Эта возможность была представлена в феврале 2019, одной из причин интереса к ней является тот факт, что она могла помочь сократить число модулей в реестре. Package Files чрезвычайно упрощает процедуру комбинирования сгенерированных данных и JavaScript-кода в виде единого модуля.
Второе улучшение произошло тогда, когда мы уменьшили средний размер каждой записи реестра (T229245). Манифест содержит две записи для каждого модуля. Это — имя модуля и идентификатор (ID) его версии. На идентификатор версии раньше нужно было 7 байт данных. После размышлений над парадоксом дней рождения в контексте ResourceLoader мы решили, что спектр вероятности для ID версий можно безопасно снизить с 78 миллиардов до «всего лишь» 60 миллионов. Подробности об этом можно почитать в комментариях к коду. Но, если подвести итог этого улучшения, то можно сказать, что это позволило сэкономить 2 байта в описании каждого из 1100 модулей, которые всё ещё имеются в реестре. В результате размер манифеста удалось снизить ещё на 2-3 Кб.
Ниже — увеличенный фрагмент диаграммы, демонстрирующий последние несколько дней работы (эти показатели взяты из системы синтетического мониторинга, тут используются несжатые данные).
Изменение размеров манифеста на завершающем этапе работы над проектом
Изменение было зафиксировано системой мониторинга ResourceLoader. На скриншоте показана панель Startup manifest size, расположенная в общедоступном экземпляре Grafana. Здесь можно видеть, что размер несжатого потока данных уменьшился на 2.8 Кб.
Развёртывание системы, которое пришлось на середину сентября, привело к достижению изначальной цели, которая заключалась в сжатии манифеста до размеров, не превышающих 28 Кб. Реализация этого крупномасштабного проекта привела к тому, что инициализационный манифест был уменьшен на 9 Кб (речь идёт о сжатых данных). Года назад этот размер составлял 36.2 Кб, а после завершения проекта это уже было 27.2 Кб.
Ежеминутно на Wikipedia и родственных проектах набирается около 363000 просмотров страниц. В час — 21 миллион и 800 тысяч. Ежедневно — 523 миллиона (вот статистика по просмотрам страниц). Та версия системы, что была развёрнута в середине сентября, привела к экономии примерно 1.4 терабайта трафика в день. А если сравнивать то, что есть сегодня, с тем, что было год назад, то окажется, что ежедневно теперь экономится 4.3 терабайта трафика.
Что дальше?
Нам удалось уместить манифест инициализации Wikipedia в 28 Кб. Именно такой размер был выбран из-за того, что он представляет собой наименьший размер, кратный 14 Кб. Данные такого размера можно разместить во фрагментах последовательности интернет-пакетов, передаваемых браузеру.
Теперь перед нами стоит новая задача: не сдавать позиций. В последний год я пристально наблюдал за манифестом. Делал я это для того, чтобы убедиться в наших успехах и обнаружить потенциальные проблемы, тянущие нас назад. В итоге я автоматизировал этот процесс с помощью общедоступной панели мониторинга Grafana.
Если верить этой панели, то у нас есть ещё много возможностей по совершенствованию упаковки кода, и по решению задач, которые ещё сильнее, чем сейчас, облегчают создание бандлов. Надеюсь, эти грядущие улучшения нам пригодятся, а пока мы работаем над новыми возможностями системы, стремясь при этом соблюсти требования к уровню производительности проекта.
Уважаемые читатели! Доводилось ли вам принимать участие в оптимизации крупных интернет-проектов?
Автор: ru_vds