Как стать автором
Обновить

Сложное решение простых проблем HighLoad WEB-сервисов

Время на прочтение 4 мин
Количество просмотров 6.9K


Ключевой задачей высоконагруженных WEB-систем является способность обработать большое число запросов. Решить эту проблему можно по-разному. В этой статье я предлагаю рассмотреть необычный метод оптимизации запросов к backend через технологию content-range (range). А именно — сократить их количество без потери качества системы путем эффективного кеширования.

Для начала, предлагаю изучить статью, где весьма емко и доходчиво изложена преамбула технологии с примером для S2S. Далее, желательно познакомиться с моей первой статьей об использовании этой технологии для оптимизации работы с market-data на проекте криптобиржи.

В этой статье, я хочу показать, что данная технология может быть использована шире, чем продемонстрировала первая статья. Напомню, там трейдинговая информация (свечи) получаются range-запросами к статическим файлам, которые заранее готовятся специальным сервисом. Теперь, я хочу рассмотреть запросы к полноценному backend на примере той же market-data, и для тех же свечей, без потери ключевых профитов.

Итак, что планируется достичь:

  1. Оптимизировать запросы к backend (уменьшить их количество);
  2. Повысить скорость доставки контента конечному пользователю;
  3. Оптимизировать трафик.

Еще раз, особо выделю то, что технология range является стандартом (RFC 2616). Она нативно поддерживается браузерами и они способны кешировать полученные порции данных. Следовательно, очередной запрос из браузера, при наличии актуального кеша запрашиваемой порции, реализуется на клиенте, не потревожив ваши сервера.

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

Таким образом, чтобы состоялся реальный запрос к серверу, запросу необходимо преодолеть два эшелона кеширования, каждый из которых снижает объем запросов к конечному серверу. Конечно, финальным “редутом”, на пути запроса, может стать ваш сервер со своим кешем.

Из особенностей использования технологии range нужно учесть, что она работает с порциями байтов. Т.е. с бинарными данными. И запрашивать мы можем именно интервалы байт. Отвечать должны, соответственно — бинарным блоком.

Думаю, вводных достаточно. Давайте перейдем к частному случаю, и уже на примере разберемся как мы можем все это “счастье” использовать в частной задаче — запрос свечей за заданный интервал с заданной экспозицией.

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

moment: int32 // Момент времени
min: float64 // Минимальная цена
max: float64 // Максимальная цена
open: float64 // Цена открытия
close: float64 // Цена закрытия
volume: float64 // Объем
average: float64 // Средняя цена

Таким образом, наша структура займет 52 байта. Примем ее как квант — минимальный бинарный блок.

Далее, реализуем контроллер, который будет принимать GET запросы и парсить заголовок range. При этом, мы будем переводить запрашиваемый интервал в кванты путем простого деления без остатка, т.е. например, запрос с интервалом:

Range: 5200-52000

Должен нами интерпретироваться в размерности нашего кванта как:

Range: 100-1000

По сути, это будет offset и limit нашего запроса к БД.

С определением экспозиции совсем просто, мы ее можем поместить в url. К примеру:

/api/v1/candles/7m

Т.е. мы будем запрашивать свечи с экспозицией 7 минут. Естественно, мы предполагаем, что это параметр может меняться по желанию frontend.

Теперь, зная требуемую экспозицию, номер первой свечи и номер последней свечи, которую запрашивает frontend, мы можем выполнить соответствующий запрос к БД.

В целом, очень напоминает классическую задачу с пагинацией.

Остались мелочи. Каждая строка результата запроса конвертируется в бинарную структуру (тот самый квант) и полученный бинарный массив выводится как результат запроса, а в заголовок ответа отдается content-range:

Content-Range: [запрошенный интервал] / [[количество записей в БД] * [размер кванта]]

Стоп. А как же фрон сможет запросить нужный временной интервал, да еще и в байтовом интервале? Откуда он знает какие-то там номера свечей? Тут тоже все придумано. Range поддерживает относительное смещение, например,

Range: -52

Запросит 52 байта с конца. Т.е. последнюю свечу. Теперь, зная последний момент времени последней свечи, зная, из ответа, общий размер “файла”, можно вычислить общее количество свечей, а отсюда и определить байтовый интервал для запроса нужной временной экспозиции.

Если вам вдруг захотелось задать вопрос — зачем такие сложности? Прошу вернуться к поставленным целям. Данная технология “замаскировала” аналитические запросы к БД в бинарные файлы для CDN и браузера. Это позволяет большую часть повторяющихся запросов переложить на CDN и конечного клиента.

Возможно, возникнет еще вопрос — а почему бы не использовать простое кеширование GET запросов? Хорошо. Давайте разбираться. Если мы выполним вот такой запрос в классическом REST:

GET /api/v1/candles/7m?from=01-03-2018&to=31-03-2018

Мы получим уникальный кэш для этого запроса. Выполнив следующий запрос:

GET /api/v1/candles/7m?from=15-03-2018&to=20-03-2018

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

Так вот, в случае выше предложенной реализации (range), второй запрос не сформирует отдельного кэша, а использует уже полученные данные из первого запроса. И не полезет на сервер. А это, экономия размера кешей и уменьшение количества обращений к серверу.

Есть ли минусы у данной технологии? Да. Они очевидны:

  1. Эта технология плохо подходит для меняющихся со временем данных, т.к. базируется на тотальном кешировании.
  2. CDN CloudFlare кэширует файлы только целиком. Это значит, что если конечный клиент запросит интервал скажем, с 1 по 100 байт, то CloudFlare реально запросит с сервера весь файл. Т.е. в нашем случае, он загрузит все свечи с определенной экспозицией. Положит у себя и будет уже раздавать сам. Это можно было бы считать даже плюсом, если бы не ограничения по месту. И если у вас могут формироваться “тяжелые” ответы, а параметров множество, то… В общем понятно, что место кончится. Возможно, мы так и не смогли его правильно настроить. Но пока результат таков.
  3. Требуется с умом управлять кешами. Для этого есть достаточные механизмы, но они требуют тюнинга.
  4. Frontend должен уметь парсить бинарные данные и иметь на борту что-то аля dataset для работы с range запросами.

Я бы сформулировал целесообразность реализации этой стратегии так — когда она вам понадобится, вы поймете. Если сейчас есть сомнения, полезно знать о ней, но не стоит заморачиваться.
Теги:
Хабы:
+6
Комментарии 11
Комментарии Комментарии 11

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн