Б Бёрнс - Распределенные системы. Паттерны проектирования
- Название:Распределенные системы. Паттерны проектирования
- Автор:
- Жанр:
- Издательство:Питер
- Год:2019
- ISBN:978-5-4461-0950-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Б Бёрнс - Распределенные системы. Паттерны проектирования краткое содержание
Распределенные системы. Паттерны проектирования - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
равномерное распределение.
Для шардированного сервиса первостепенное значение имеют детерминированность и равномерность хеш-функции. Детерми-Глава 6. Шардированные сервисы 115
нированность важна, так как обеспечивает то, что определенный запрос R всегда будет попадать на один и тот же шард сервиса. Равномерность хеш-функции обеспечивает равномерное рас-пределение нагрузки между шардами.
К счастью, библиотеки современных языков программирования включают целый ряд качественных хеш-функций. Диапазон зна-чений этих функций зачастую существенно превышает количе-ство шардов в системе. Чтобы сузить этот диапазон, необходимо
воспользоваться оператором взятия остатка от деления. Возвра-щаясь к нашему сервису из десяти шардов, нетрудно догадаться, что функция шардирования будет иметь следующий вид:
Shard = hash ( Req ) / 10.
Оператор взятия остатка от деления не нарушает свойств детер-минированности и равномерности хеш-функции. Выбор ключа
Может показаться заманчивым просто взять встроенную хеш-функцию языка программирования и применить ее ко всему объекту. Однако получившаяся в результате этого функция шардирования не будет идеальной.
Чтобы лучше разобраться в этом, рассмотрим запрос с тремя полями:
время запроса;
IP-адрес клиента;
путь HTTP-запроса (например, /some/page.html ). Очевидно, что при простом хешировании запроса целиком за-просы {12:00, 1.2.3.4, /some/file.html} и {12:01, 5.6.7.8, /some/file.html} будут соответствовать разным шардам. 116Часть II. Паттерны проектирования обслуживающих систем Шардирующая функция выдает разные результаты, поскольку IP-адреса и временные метки запросов не совпадают. Но в боль-шинстве случаев ответ на HTTP-запрос не зависит ни от адре-са клиента, ни от временной метки запроса. Следовательно, намного лучше использовать шардирующую функцию вида shard(request.path) , а не хешировать весь запрос. Если в ка-честве ключа шардирования использовать путь запроса, то оба запроса попадут на один и тот же шард и второй запрос уже будет обслужен из кэша.
Иногда IP-адрес важен для запросов, возвращаемых интерфейс-ной частью. IP-адрес клиента может, скажем, применяться для определения страны, в которой находится пользователь. Это по-зволяет возвращать разный контент (например, на разных языках) разным пользователям. В таких случаях применение шардирую-щей функции от HTTP-пути может приводить к ошибкам — за-прос с французского IP-адреса может быть обслужен из англо-язычного кэша. Такая шардирующая функция будет слишком общей , поскольку группирует запросы с неидентичными ответами. Ставить номер шарда в зависимость одновременно от IP-адреса и HTTP-пути — тоже не лучший подход.
Два запроса с разных французских IP-адресов могут попасть на разные шарды, что снижает эффективность шардирования. Такая функция шардирования слишком специфична , поскольку может распределять запросы с идентичными ответами в разные группы. В таком случае лучше использовать следующую функ-цию шардирования:
shard ( country ( request.ip ), request.path ) Она сначала определяет страну по IP-адресу, затем использует ее в качестве части ключа. Запросы из Франции будут адресо-ваны одному шарду, а запросы из Америки — другому. Глава 6. Шардированные сервисы 117
При проектировании шардированной системы критически важ-но корректно определить ключ шардирования. Для этого нужно хорошо понимать, какие запросы могут быть адресованы вашей системе.
Консистентные хеш-функции
Первоначальная настройка шардов в новой распределенной системе довольно проста — достаточно настроить соответству-ющие шарды и шардированные сервисы. А что случится, если вы захотите изменить количество шардов в шардированной системе? Повторное шардирование — часто довольно затрат-ный процесс.
Чтобы разобраться, почему это так, вернемся к ранее рассмо-тренному примеру с шардированным кэшем. Оркестратор кон-тейнеров позволит без труда увеличить кэш с 10 до 11 экзем-пляров. Но каков будет эффект от изменения шардирующей функции с hash(Req) % 10 на hash(Req) % 11 ? Когда вы приме-ните новую шардирующую функцию, значительная часть за-просов уйдет на другие шарды, нежели те, что были назначены предыдущей функцией. Это существенно увеличит процент кэш-промахов в шардированном кэше до тех пор, пока шарды не заполнятся ответами на вновь сопоставленные с ними за-просы. Применение новой функции шардирования к шарди-рованному кэшу в худшем случае приведет к кэш-промахам в 100 % вариантов.
Чтобы решить подобную проблему, многие шардирующие функ-ции прибегают к использованию консистентных хеш-функций . Эти хеш-функции устроены таким образом, что при количестве ключей K и увеличении количества шардов до N гарантированно окажется перенаправлено не более K / N запросов. Например, при использовании консистентной хеш-функции для шардирования 118Часть II. Паттерны проектирования обслуживающих систем
кэша из рассматриваемого примера переход с 10 шардов на 11 вы-зовет перенаправление менее 10 % запросов ( K / 11). Это гораздо лучше, чем потерять весь шардированный сервис. Практикум. Построение консистентного шардированного прокси-сервера Первый вопрос, которым стоит задаться при шардировании HTTP-запросов, — какой ключ использовать в шардиру ющей функции? Есть несколько подходов, но в общем случае не-плохо подойдет путь HTTP-запроса, совмещенный с пара-метрами запроса и всем тем, что делает запрос уникальным. И это без учета cookies и языка/страны (например, en-us). Если ваш сервис позволяет пользователю выполнять тон-кую настройку параметров, их значения также стоит сделать частью ключа.
В качестве шардирующего прокси может выступать nginx. worker_processes 5;
error_log error.log;
pid nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 1024;
}
http {
# Определяем именованный «обработчик», который можно будет # указать в директиве proxy ниже
upstream backend {
# Хешируем URI-адрес запроса с использованием # консистентной хеш-функции
hash $request_uri consistent
server web-shard-1.web;
server web-shard-2.web;
Глава 6. Шардированные сервисы 119
server web-shard-3.web;
}
server {
listen localhost:80;
location / {
proxy_pass http://backend;
}
}
}
Обратите внимание, что в качестве ключа мы используем пол-ный URI запроса, а также указываем ключевое слово con sistent , чтобы nginx задействовал консистентную хеш-функцию. Шардирование реплицированных сервисов
В большей части примеров в этой главе описывается шар-дирование кэша. Кэш, безусловно, не единственный сервис, которому шардирование пойдет на пользу. Шардирование подойдет для любого сервиса, в котором хранится больше данных, чем может поместиться на одной машине. В отличие от предыдущих примеров, ключ и функция шардирования являются не частью HTTP-запроса, а частью пользователь-
Читать дальшеИнтервал:
Закладка: