Showing posts with label балансировка нагрузки. Show all posts
Showing posts with label балансировка нагрузки. Show all posts

Sunday, October 20, 2013

Уменьшение нагрузки на оптимизирующий прокси

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

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


Если пользователь согласен с полным проецированием трафика то в первом запросе передаются также приватная информация и контент преимущественно отдается с кеширующей инфраструктуры или зеркал.

Tuesday, August 27, 2013

Почти идеальный виртуальный CDN

Почему почти? Нет в мире совершенства, всегда хочется еще чего-то или забываешь о чем-то.
Виртуальный - потому что нет его как такового только незримое улучшение каких-то характеристик.

Вот несколько неплохих характеристик виртуального CDN:
  • быть посредником между сайтом и конечным пользователем и перепроверять контент, который возвращает сайт пользователю, а действительно ли он поменялся? как поменялся? а можно немного раньше его перезапросить? Может пользователю захочется его загрузить? И заменять все заголовки на правильные полностью зависящие от результата и заголовков клиента;
  • выдавать правильный хеш от контента с адресом куда можно еще обратится про этот хеш;
  • эта отдельная часть может быть как внутри этого посредника, так и дублироваться на клиенте, где указывается хеш контента, откуда он получен и где еще можно поискать;
  • выдавать из каких частей состоит результат, может нам не нужны полный результат, а только его часть, так как все остальное у нас уже есть или у кого-то поближе.

И как результат не весь контент грузится с одного сайта, можно по заголовкам понять может мы это уже откуда-то грузили или можно параллельно погрузить.

Thursday, October 25, 2012

CDN, безопасность

​Продолжение предыдущего поста.
Для обеспечения возможности безопасной работы нужно обеспечить возможность подписывания пакетов ключом и размещения узла, обеспечивающего взаимосвязь классический протокол - пириговая сеть, в подконтрольном базовому сайту узле с возможностью иметь два канала: 
  • первый непосредственный для связи с базовым узлом. Максимально защищенный с возможность проверки корректности, этот канал необходим для передачи ключей и других данных для проверки и преобразования классический url в хеши;
  • и второй канал для передачи данных - полностью открытый, но можно проверить целостность пакетов по информации с первого канала.

Tuesday, October 23, 2012

​CDN, общие идеи

Это описание абстрактной реализации, 
не имеющей ничего общего с реальными реализациями.

Сеть доставки контента содержит три уровня: 
  • первый нацелен на получение обновления с сервера сайта, должен быть максимально ближний к исходному серверу на сетевом уровня, географически это не обязательно главное максимальная скорость и минимальная задержка получения данных; 
  • второй уровень содержит систему передачи данных между уровнями, основная цель быстрая доставка данных внутри сети между узлами первого уровня и узлами третьего уровня - обеспечивает максимальную скорость передачи данных между географически удаленными частями различных уровней; 
  • третий уровень узел ближайший к клиенту, ответственен за максимально быструю отдачу контента конечному пользователю. В общем случае наибольший объем трафика идет от первого уровня к третьему - но это не обязательно так как конечный клиент также может генерировать трафик. 


Общая логика работы: 
  • при получения запроса от клиента ближайший узел к клиенту ищет сервер который является наиболее близким к исходному узлу назначения; 
  • после нахождения наилучшего пути, узел с первого уровня получает контент с конечного узла и генерирует хеш от данных и другие идентифицирующие контент данные и передает на третий уровень; 
  • если у третьего уровня нет подобных данных он запрашивает данные с первого уровня, через второй уровень который может быть пиринговой сетью; 
  • все данные при передаче должны быть сжаты и по возможности очищены от не критичных для результата данных, таких как переводы строчек и пробелы. Если возможно то и от описания изображений вида даты создания которые не критичны для пользователя; 
  • внутри сети передачи и на конечных узлах данных идентифицируются по описателям характерным для сжатого контента с сохранением изначальных характеристик - для последующей идентификации изменения исходных данных; 
  • на узлах первого уровня контент хранится также в исходном в виде - чтобы избежать вероятности коллизий хеш функции и позволяет перепроверять данные, при последующем получении подобных; 
  • при новом запросе клиента - делается только дополнительный запрос на первый уровень и если изменений нет, то передается оригинальный заголовок. Данные разбиваются на две части заголовки запроса и контент запроса. Что позволяет кешировать и передавать их отдельно. 

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

Также  узел первого уровня должен иметь возможность помнить какие сервера третьего уровня обращались, что позволит если не прошел лимит времени сообщить о изменении контента и принудительной очистке.

Sunday, May 8, 2011

Еще пара мелких оптимизаций

Использование более удобный для кеширование url(пример для Apache):
  • создаем папочку с файлом .htaccess:
    RewriteEngine On
    RewriteRule ^/?(.*)/(.*)$ /$1?$2 [L]
  • И запрашиваем все файлы из нее по url вида имя папки/нужный ресурс/старый путь относительно корня/параметры вызова - в результате получим, что то подобное /img/avatar.sh?user=1 => /stat/img/avatar.sh/user=1.
И возможность заставить всех ходить через https без перенаправления - стоит пользователю один раз зайти через https - и в течении указаного в заголовке Strict-Transport-Security времени браузер обязан сам заменять все запросы к http на https без запроса к серверу. То есть человек один раз делает запрос на http - мы его перенаправляем на https, и уже на запрос по https мы ему указываем что в течении определенного времени делать запросы только на https.

Monday, September 7, 2009

Уникальные идентификаторы для контента

В принципе можно решать как общую задачу создания уникальных идентификаторов:
  • использовать данные генератора случайных чисел (не удобно так как не возможно четко контролировать результат);
  • использовать псевдослучайные значения, например время, процесс/поток с последующим преобразованием в символьное имя;
  • символьное имя очень полезно - так как позволяет лучше при отладке отличать идентификаторы (числа в любом виде хуже отображают отличия);
, а можно учитывать специфику:
  • имена должны поддерживаться файловой системой(запрет на использование спец символов);
  • максимально короткие эффективные имена(снижение затрат памяти), использование всего пространства допустимых символов,
  • близкие по времени создания и исходному значению имена должны быть максимально случайны по результату - то есть использовать максимально эффективный хеш-функцию - обычно достигается использованием хеш значений от псевдослучайных факторов времени создания, процесса/потока и идентификатора хранилища;
  • решение противоречивой в общем-то задачи:
    • максимального разброса имени контента для сохранения;
    • и возможности по имени определить максимально быстро наиболее вероятное хранилище в распределенной системе можно использовать 2 имени - внутреннее и внешнее;
    • внутреннее должно быть максимально эффективно дробить множество доступных вариантов размещения в локальной системе с разбиением на подкатологи с минимальной вероятностью превышения пределов на одновременное количество вложенных каталогов. Это ограничение возникает как из-за временных затрат при работе с большими каталогами, вытекающее иногда в невозможность добавления данных в каталог, и удобства конечного владельца системы, хоть и редко, но удобнее ходить по маленьким каталогам. Также при максимальном разбросе можно разместить часть каталогов на другом разделе и реализовать дешёвое подобие RAID.
    • внешнее - не противоречить правилам для протокола доступа, например не содержать спец символов специфичных для http и html разметки. Позволять легко определить максимально вероятное место расположения в распределенной системе для быстрого выявления не корректно отвечающей части, также при дублировании на другие ресурсы - можно легко удалить данные не специфичные узлу при окончании ресурсов.
Очень желательно, чтобы в внутреннем имени присутствовали хеш функция от размера данных (можно просто выделение остатка от деления на какое-то число с получением base64 + как подкаталог base64 от полного размера) и его контента (для снижение количества коллизий лучше сразу два хеш значения от контента). В результате можно быстро найти подобный контент найдя подобную запись в списке преобразований внутреннее имя <-> внешнее имя или, что должно работать гораздо быстрее при большом количестве разнообразного контента, присутствия такого каталога на диске. В дальнейшем можно проверить его содержимого на совпадение с добавляемыми данными. Как результат мы не будем забивать хранилище дубликатами и при желании сможем сообщать, что пользователь пытается снизить энтропию вселенной.

Friday, April 17, 2009

Пример архитектуры кэширования(Caching Architecture)

Общую структуру кэширования и получения контента можно представить в таком виде:

  • Красным цветом отображены наиболее критичные части без которых система не может функционировать в нормальном состоянии.
  • Синим цветом соответственно представлены все части отвечающие за стабильное(нормальное) состояние сервиса.
  • Зеленым цветом - наиболее производительный вариант работы.
Каждый овал может представлять как отдельный сервер, так и несколько овалов может быть размещено на одном сервере, кроме вариантов дублирования веток обработки.

Контент любого сервиса можно разделить на 3 составляющие: статический контент, медиа контент и динамический контент.

Статический контент


Статический контент - изменяется редко, и создается разработчиками ресурса и изменяется только при смене версии ресурса. И как следствие его желательно отдавать легковесным сервером с максимальной производительностью и поддержкой системных вызовов(writev, sendfile). Для запросов на эти файлы вебсервер должен выдавать последнюю дату изменения, при последующих запросах сервер выдает Not Changed.

Медиафайлы


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

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

Методы кэширования: при приходе запроса на получение файла без заголовков(HTTP_IF_MODIFIED_SINCE) - выдать файл с указанием времени создания(Last-Modified) для локального файла или указания даты формирования ответа для файла полученного с другого зеркала, и указания для дополнительных заголовков (Cache-Control: max-age=28800). При приходе заголовка (HTTP_IF_MODIFIED_SINCE), если файл с того времени не обновился выдается что контент не изменился(HTTP/1.x 304 Not Modified). Это позволяет дать возможность закешировать файл на месяц и более - причем первый месяц браузер не будет делать никаких запросов к серверу. Желательно иметь одно запасное синхронизируемое зеркало, чтобы при проблемах с основным на него можно было перевести запросы.

Динамические страницы


Запрос поступает на frontend сервер, для всех запросов которые могут попасть под кэшируемость, который запрашивает этот файл с Memcached. Если файл там присутствует, то он возвращается с указанием, что его можно в течении 15 секунд не запрашивать - это блокирует повторных запрос от браузера на это контент на 15 секунд (Cache-Control: max-age=15). Если контент в кэше отсутствует, то выполняется запрос к backend, который повторно запрашивает контент от кеша, так как исходный url может не совпадать с результирующим url идущим на обработку. При отсутствии данных в кеше или не кэшируемости запроса запрос перенаправляется в SlaveDb. Возвращенный от туда запрос при возможности кэширования сохраняется в кэше с указанием времени кэширования определяемого для этого url, для примера: 30 секунд главная страница, 90 - страницы второго уровня. В ответе для кэшируемых станиц указывается в значении max-age тоже время, что указывалось для времени хранения. Как следствие мы получаем, что все станицы кэшироватся в браузере пользователя первым подавшим запрос на полное время, все последующие до окончания времени кэширования на 15 секунд.

Вторая ветвь(зеленая) нужна для снижения нагрузки на slave, так как на всех slave должен быть одинаковый контент, то при разнесении запросов на несколько сервером мы должны получить ~2 увеличение скорости обработки. Memcached - один, так как при использовании 2 экземпляров для каждого slave приведет к дублированию контента на каждом.

Пример кода


function exitIfNotModifiedSince($last_modified) {
if(@array_key_exists("HTTP_IF_MODIFIED_SINCE",$_SERVER)) {
$if_modified_since=@strtotime(@preg_replace('/;.*$/','',$_SERVER["HTTP_IF_MODIFIED_SINCE"]));
if($if_modified_since >= $last_modified) {
header("HTTP/1.x 304 Not Modified");
header("Last-Modified: ".date("D, j M Y G:i:s T", $last_modified));
exit();
}
}
}


function dump_foto_content($photo) {
exitIfNotModifiedSince(strtotime("now")- 100000);
// send the right headers
header("Content-Type: ".$photo["mime"]);
header("Content-Length: ".strlen($photo["photo_data"]));
header("Last-Modified: ".date("D, j M Y G:i:s T"));
header("Cache-Control: max-age=28800");
echo $photo["photo_data"];
exit;
}


P.S.: Для разрешения кэширования на промежуточных серверах нужно добавить параметр:
header("Cache-control: public");

Sunday, April 5, 2009

Оптимизация времени кэширования

  1. Оптимизация времени кэширования под количество запросов, обычно пользователей загрузивших страницу можно разделить на 2 группы: зашедших на страницу с другой станицы или непосредственно на страницу и другую группу обновляющих станицу в ожидании изменений. Первой группе не столь важно сколько кэшируеться страница им более важна скорость получения страницы и можно использовать максимальное допустимое время кэширования. Для второй же группы нужно кэшировать минимальное время - их можно определить по referer и тому что у них будет стоять заголовок "if not modifined since" - используя эти особенности можно при приходе первого типа запроса использовать удвоенное время кэширования, а для вторых одинарное - в результате вторая группа получает всегда обновленной контент, а первая скорость(и при совпадении запросов обоих групп еще и более быстрое обновлении, но они этого не замечают так видят страницу первый раз).
  2. При появлении запроса с заголовками не изменилось ли что то ("if not modifined since"), если еще существует кэш этого запроса можно сравнивать указанный в запросе хеш с возвращенным после обработки и стараться возвратить не изменилось так как это позволит быстрее освободить ресурсы.
  3. При варианте, когда контент уже существует на диске и его расположение высчитывается скриптом, более разумно использовать не хеш, а дату изменения и стараться, если это возможно не выдавать, а перенаправлять пользователя на это контент, в результате мы получаем минимальное потребление памяти и скорость отработки близкую к отображению статики. Перенаправлять желательно даже, если результат находиться на другом ресурсе, меньше посредников быстрее ресурс освободиться.
  4. Очень желательно кэшировать результаты запросов не на самодельных скриптах кэширования, а использовать более распостраннённые системы кэширования написаные на компилируемых языках - так больше вероятность, что выдача будет максимально быстро отдаваться и не нужно тратить время на создание велосипеда и его тестирование. Как следствие лучше перенаправить на кэш или файловую систему, чем генерировать контент скриптом - так больше вероятность, что будет использована максимально эффективная стратегия отдачи контента.

Friday, April 3, 2009

Недостаток в коде модуля балансировки

Обнаружилась маленький недостаток в модуле балансировки - не контролируется количество поставленных в ожидание освобождения ресурсов (очередь на основе семафора) - при большом превышении количества запросов по отношению к ограничению - запрос может быть выполнен даже после того как клиент отсоединиться от сервера - время ожидание ничем не ограничено. То есть существует вероятность: что модуль при очень большом количестве запросов будет давать запросы ответы на которые пользователь уже не ждет. Этот недостаток не должен сильно повлиять не производительность системы - так как на DOS атаку он не был рассчитан, он предназначен только для выравнивания и снижения единовремменой пиковой нагрузки.

Saturday, January 24, 2009

Модуль балансировки

Выложил исходный код модуля балансировки под Apache. Создан он был года 3 назад для диплома, на новых версиях сервера может не работать, но как пример исходника модуля с комментариями я думаю пойдет.

Он позволяет:
  • перенаправлять запросы с одного сервера на другой;
  • ограничивает нагрузку на сервер (количеству соединений одновременно);
  • замена url в результирующем запросе (реализована только смена url);
  • фильтр обрабатываемых url;
  • скрытие источника трафика на сервер (замена описания клиента, и запоминание кукиесов).
Использовался для исследование балансировки нагрузки на сервера.