Распределенные системы. Паттерны проектирования - [27]
(10 × 100 все еще равно 1000). Однако, поскольку каждый эк-земпляр кэша работает со своей отдельной частью данных, мы можем хранить там 50 % данных (10 × 10 из 200 Гбайт). Десяти-кратное увеличение объема кэшируемых данных означает, что кэш-память используется гораздо более эффективно, поскольку каждый элемент данных попадает только в один кэш. Роль кэша в производительности системы В главе 5 мы обсудили, как использовать кэш с целью оптими-зации производительности для конечного пользователя и со-кращения задержек. Не была, однако, рассмотрена роль кэша в производительности, надежности и стабильности приложения. Проще говоря, важно задать себе следующий вопрос: если кэш откажет, как это повлияет на ваших пользователей и на работу сервиса в целом?
Когда мы обсуждали реплицированный кэш, этот вопрос был менее актуален, так как кэш масштабировался горизонтально, то есть отказ одного из экземпляров приводил бы только к крат-ковременным неисправностям. Аналогичным образом рассмо-тренный кэш поддерживал масштабирование в связи с вырос-шей нагрузкой, не влияя при этом на конечных пользователей. В случае с шардированным кэшем все оказывается несколько иначе. Поскольку конкретный пользователь или запрос всегда соответствует одному и тому же шарду, в случае его отказа кэш-промахи будут происходить до тех пор, пока шард не бу-дет восстановлен. Учитывая временность нахождения данных в кэше, такие кэш-промахи не являются проблемой сами по себе — система должна знать, где взять данные. Однако извле-чение данных в отсутствие кэша происходит намного медлен-нее, что означает снижение производительности для конечных пользователей.
106 Часть II. Паттерны проектирования обслуживающих систем Производительность кэша выражается в виде коэффициента попадания запросов . Коэффициент попадания — доля запросов, ответ на которые содержится в кэше. В конечном итоге коэффи-циент попадания характеризует общую максимальную нагрузку на распределенную систему и влияет на производительность и мощность системы в целом.
Представьте, что уровень обработки запросов вашего приложе-ния поддерживает обработку 1000 запросов в секунду. При превышении этого показателя система начинает воз-вращать HTTP-ошибки с кодом 500. Если вы добавите кэш с 50%-ной вероятностью попадания, количество обрабатыва-емых запросов возрастет до 2000 в секунду. Так происходит потому, что из 2000 запросов одна половина может быть обслу-жена кэшем, а другая — уровнем обработки запросов. В данном примере кэш довольно критичен для работы сервиса, поскольку в случае его отказа уровень обработки запросов окажется пере-гружен и половина запросов завершится ошибкой. Именно по-этому имеет смысл оценить емкость сервиса в 1500 запросов секунду, а не в полные 2000. Это позволит удержать сервис в стабильном состоянии даже при отказе половины экземпляров кэша.
Производительность системы, однако, не ограничивается коли-чеством обрабатываемых в единицу времени запросов. Произ-водительность, с точки зрения конечного пользователя, также определяется задержкой выполнения запросов. Получить ре-зультат из кэша, как правило, гораздо быстрее, чем сформиро-вать его с нуля. Следовательно, кэш повышает не только коли-чество одновременно обрабатываемых запросов, но и скорость их обработки. Почему? Представьте, что система обслуживает запрос пользователя за 100 миллисекунд. Добавим кэш с ве-роятностью попадания 25 %, который возвращает результат за 10 миллисекунд. Средняя задержка обработки запроса, таким Глава 6. Шардированные сервисы 107
образом, уменьшилась до 77,5 миллисекунд. Кэш не только увеличивает количество обрабатываемых в секунду запросов, но и ускоряет выполнение каждого отдельного запроса, поэтому замедление обработки запросов в результате отказа части экзем-пляров кэша или развертывания новой его версии беспокоит нас не слишком сильно. Однако в некоторых случаях влияние на производительность окажется настолько велико, что запросы начнут скапливаться в очередях и часть из них будет отклонять-ся по истечении времени ожидания. Никогда не будет лишним выполнять нагрузочное тестирование сервиса как при наличии, так и при отсутствии кэша, чтобы понять его влияние на общую производительность системы.
Наконец, нужно думать не только об отказах. Если вы хотите об-новить или повторно развернуть шардированный кэш, не полу-чится просто развернуть новую копию сервиса и рассчитывать на то, что он сразу же возьмет на себя нагрузку. Развертывание новой версии шардированного кэша в общем случае приведет к временной потере производительности. Другим, более слож-ным решением будет репликация шардов. Реплицированный и шардированный кэш Иногда система оказывается настолько зависимой от кэша в плане задержек или нагрузки, что потеря даже одного шарда в результате отказа или в процессе обновления оказывается неприемлемой.