Написать пост

Как ускорить загрузку сайта со стороны бэкенда

Разбор нескольких технологических решений, которые могут ускорить загрузку ваших проектов.

6К открытий6К показов

Скорость загрузки страниц влияет на ранжирование сайта поисковиками, на процент отказов и на его конверсию. Поэтому при разработке важно измерять и оптимизировать этот показатель. Меня зовут Фаррух, я тимлид в IT-продакшне Extyl. Мы разрабатываем b2b-сервисы, порталы и личные кабинеты для крупного бизнеса. В этом материале я расскажу, какие технологические решения мы используем, чтобы ускорить загрузку своих проектов.

Скорость загрузки любого сайта складывается из двух составляющих — скорость отдачи страницы бэкендом с загрузкой всех вспомогательных элементов и скорость отрисовки внешней части сайта в браузере клиента.

Если мы говорим о сайтах, написанных на PHP, то скорость генерации страницы при хорошей архитектуре будет 100 мс, но допустима и более медленная загрузка — до 400 мс с последующей оптимизацией кешированием с помощью cache-buster’а, который увеличит скорость до 20-30 мс. С одного домена можно параллельно загружать только шесть файлов. Поэтому файлы нужно не только уменьшать в размере, но и сокращать их количество. Например, элементы дизайна — стрелки, кнопки и прочее — рекомендуется объединять в один файл (технология CSS-спрайтов).

Также рекомендуем использовать услуги CDN-провайдеров. Они помогают без особых затрат расположить файлы на разных серверах, что увеличит количество параллельно загружаемых файлов.

TTFB — Time to First Byte (время до получения первого байта) — это показатель задержки в передаче данных между браузером и сервером; степени загрузки сервера; и скорости генерации контента движком сайта. Хорошее значение TTFB не обязательно означает то, что демонстрирующий его сайт можно счесть быстрым, но плохой показатель TTFB гарантированно указывает на проблемы с производительностью проекта.

В Extyl мы выбрали для себя предельное время TTFB в 200 мс. Такой показатель вполне достижим для большинства приложений.

Чтобы понимать, как работает код и быстро вносить изменения, разработчик должен проводить мониторинг и нагрузочное тестирование на протяжении всех этапов разработки.

TIG (Telegraf, Influx, Grafana)

 

Как ускорить загрузку сайта со стороны бэкенда 1

Мониторинг сайта мы проводим на стеке TIG (Telegraf, Influx, Grafana) — это базовый набор компонентов для быстрого развертывания системы мониторинга. Опытный разработчик может сделать это за час.

После настройки мониторинга мы получаем доступ к полноценной статистике использования ресурсов сервера и скорости работы всех узлов системы.

Яндекс.Танк

Еще один популярный и доступный инструмент тестирования — это Яндекс.Танк. Он позволяет проводить нагрузочные тестирования и анализ производительности веб-сервисов и приложений. Благодаря данным, которые предоставляет Яндекс.Танк, разработчик видит, как работает его приложение под любой нагрузкой.

Как ускорить загрузку сайта со стороны бэкенда 2
Как ускорить загрузку сайта со стороны бэкенда 3

 

Архитектура

Чаще всего разработка веб-приложения ведется с учетом масштабирования, поэтому минимальная конфигурация, которую мы рекомендуем, — два сервера.

В базовом варианте это веб-сервер и сервер БД. Если у вас распределенная на несколько серверов инфраструктура, и веб-сервер и БД лежат на разных серверах, то храните кэш ближе к серверу, где находится веб-сервер, желательно на нем же —  чтобы избежать сетевой задержки.

У нас практически всегда есть свободная ОЗУ на веб-сервере и мы можем разместить кэш-сервер на нем. Связь с ним по сокету дает прирост до 30% относительно обмена c локалхостом, и кратный прирост скорости в сравнении с кэш-сервером, находящимся на другом хосте.

База данных

База данных всегда будет самой медленной частью сайта, поэтому рекомендуется уменьшать количество запросов к ней или разбивать на части большие запросы и частично кэшировать их результат.

Основная база данных на наших проектах — это PostgreSQL. У PostgreSQL много сильных сторон, но ее основное преимущество — подход Not-Only-SQL. Для примера возьмём достаточно частый запрос вывода данных по связи many-to-many. В тестовой БД более миллиона записей в таблице news и около 300 тысяч тегов.

Сравним выборки по JSONB с индексом GIN и базового алгоритма.

JSONB — разновидность формата JSON. Немного более сложная, но хорошо покрываемая индексами GIN.

Индекс GIN — это обобщенный инвертированный индекс, который содержит записи для всех отдельных слов (лексем) с компактным списком мест их вхождений. При поиске нескольких слов можно найти первое, а затем воспользоваться индексом и исключить строки, в которых дополнительные слова отсутствуют.

Выберем все новости, которые содержат выбранный тег, как мы это делаем обычно.

			explain analyze
select * from news
where id in (select news_id from news_tag where tag_id = 14)
limit 20
		
Как ускорить загрузку сайта со стороны бэкенда 4
Как ускорить загрузку сайта со стороны бэкенда 5

Теперь посмотрим тоже самое на jsonb и gin индексах:

			select * from news
where json_custom_new @> '{"14": "#здоровье"}'
and active = true
limit 20
		
Как ускорить загрузку сайта со стороны бэкенда 6
Как ускорить загрузку сайта со стороны бэкенда 7

Мы видим уменьшение времени выборки с 5 мс до 0,6 мс, а это почти в 10 раз быстрее.

Усложним запрос. Теперь мы хотим получить все новости в которых встречаются 2 тега:

			explain analyze
select * from "news"
where exists (select * from "tags
	      inner join "news_tag" on "tags"."id" = "news_tag"."tag_id"
              where "news"."id" = "news_tag"."news_id" and "id" in (14,632))
and active = true
limit 20
		
Как ускорить загрузку сайта со стороны бэкенда 8
Как ускорить загрузку сайта со стороны бэкенда 9

И тоже самое на jsonb и gin:

			explain analyze
select * from news
where json_custom_new @> '{"14": "#здоровье","632": "#партпроект"}'
and active = true
limit 20
		
Как ускорить загрузку сайта со стороны бэкенда 10
Как ускорить загрузку сайта со стороны бэкенда 11

Мы видим для jsonb и gin скорость выборки не особенно изменилась. А для оригинального SQL скорость выборки упала еще на порядок, деградация будет еще более заметна под нагрузкой. Даже на относительно простых операциях мы получаем прирост производительности до 3-х порядков.

Также мы рекомендуем дробить индексы на отдельные более мелкие. Например, поделить каталог товаров по разделам. На запросах типа exists, как в предыдущем примере, мы можем уменьшить время выборки с 600 мс до 50 мс

Покрывающие индексы

Когда данные, достаточные для ответа, хранятся в индексе, можно лишний раз не обращаться к таблице, а ответить, используя только данные из индекса. За счет этого скорость выборки или фильтрация возрастает, но, разумеется, и сами индексы станут больше, так что злоупотреблять этим не нужно.

			CREATE INDEX news_id_index_section_11_news
    ON public.news USING btree
    (start_date DESC NULLS LAST)
    INCLUDE(end_date, section_id)
    TABLESPACE pg_default
    WHERE section_id = 11 AND active = true AND deleted_at IS NULL;
		

Таким образом, можно выиграть еще 30-40% на выборках.

Денормализация

Мы можем намеренно привести структуру базы данных в состояние, не соответствующее критериям нормализации. Обычно его проводят с целью ускорения операций чтения из базы за счет добавления избыточных данных. При использовании jsonb можно легко денормализовать данные и получать их все единоразово.

Как ускорить загрузку сайта со стороны бэкенда 12

Это упрощает код и ускоряет выборки из БД.

Итог

  • Нужно следить за показателями скорости.
  • Проверять их динамику под нагрузкой.
  • Оптимизировать базу данных.
  • Сокращать количество одновременно загружаемых файлов.
Следите за новыми постами
Следите за новыми постами по любимым темам
6К открытий6К показов