8 заметок с тегом system-design

System Design

Очереди сообщений

При работе с большими системами, которые состоят из множества компонентов, возникает вопрос: «Как интегрировать несколько приложений для работы друг с другом?». Для этого нужен надёжный, асинхронный и быстрый способ передачи данных, который также позволит передавать информацию в разных форматах.

Все эти свойства есть в системе обмена сообщениями. Они полезны когда:

  • Нужно отправить данные из точки А в точку Б.
  • Нужно интегрировать несколько систем.
  • Нужно масштабирование.
  • Нужна возможность мониторить потоки данных.
  • Нужна асинхронная обработка.
  • Нужна буферизация.

Концепт обмена сообщениями

Обмен сообщениями неновое изобретение. Он активно используется внутри операционной системы для обмена информацией между несколькими процессами (inter-process communication) и для обмена между несколькими потоками внутри процесса (inter-thread communication).

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

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

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

Также очереди работают по модели «издатель-подписчик». В ней издатель оправляет сообщение в очередь, а подписчик смотрит в очередь и извлекает интересные ему сообщения, после чего занимается их обработкой. Благодаря этой концепции, осуществляется асинхронная коммуникация.

Причины использовать очереди сообщений

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

Масштабирование
Очереди распределяют процессы обработки информации. Это дает возможность гибко реагировать на нагрузку и добавлять или убирать дополнительные обработчики.

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

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

Decoupling and coupling
С помощью очередей можно достичь двух противоположных целей.

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

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

Гарантированная доставка

Гарантированная доставка является одной из ключевых характеристик системы обмена сообщений. Всего есть три типа доставки:

  • at least once
  • at most once
  • exactly once

At least once
Самый простой способ доставки при котором обработчик получает одно и то же сообщение до тех пор, пока не удалит его из очереди или не подтвердит получение. Это значит что возможны ситуации, когда приложение обрабатывает одно сообщение несколько раз.

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

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

С другой стороны, такой подход гарантирует 100% получение сообщения. Даже если получатель сообщения упадёт, до того как подтвердит обработку, то он просто ещё раз его обработает после перезапуска.

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

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

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

Все они происходят из двух утверждений:

  • Отправители и получатели не идеальны
  • Сеть не идеальна.

Что порождает такие проблемы как:

  • Отправитель может забыть отправить сообщение
  • Сеть между отправителем и очередью может упасть
  • Сеть между очередью и получателем может упасть
  • База данных самой очереди может не сохранить сообщение
  • Подтверждение что сообщение обработано может не дойти до очереди и отправителя

Именно поэтому очень сложно гарантировать одноразовую доставку сообщения. Намного проще сделать систему устойчивой к дубликатам сообщений и использовать подход at-least-once.

Компоненты очереди сообщений

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

Сообщения — любые данные, которые нужно передать через очередь конвертируются в сообщение, которые состоят из двух частей:

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

Каналы (channels) — логические соединения между приложениями и системой очередей, которые предоставляют изолированную коммуникацию. Каналы позволяют передавать сообщение в одном из двух режимов:

  • point-to-point — протокол, который обеспечивает прямую коммуникацию между двумя приложениями.
  • publish-subscribe — протокол, в котором отправитель сообщения не знает конкретного получателя, а просто отправляет сообщение в очередь, на которую могут быть подписаны потребители.

Маршрутизатор (router) — помещает сообщения из каналов по разным очередям используя ключ маршрутизации из заголовков сообщения.

Очередь (queue) — хранилище для наших сообщений, которое может находиться как в оперативной памяти так и на диске.

Виды очередей

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

broadcast (fanout) exchange
В таком случае отправляется копия сообщения во все доступные очереди, ключ маршрутизации игнорируется.

direct exchange
Все сообщения имеют свой ключ маршрутизации, который определяет в какую очередь нужно положить сообщение. В дальнейшем сообщения будут переданы по принципу Round Robin подписанным обработчикам. Это значит что только один обработчик получит сообщение.

topic exchange (multicast)
Такие очереди подписаны на получение сообщений чей ключ подпадает под определенный паттерн. Если ключ маршрутизации подходит для нескольких очередей, то каждая получит по своей копии.

Обычно ключи маршрутизации стараются делать в иерархическом виде. Это достигается за счет разделения логических частей (слов) точками. Например вот так:

[region].[availability-zone].[service].[instance]

eu-east.az1.computer.homepc

Сами же паттерны создаются с использованием специальных символов:

  • * — заменитель только для одного слова.
  • # — заменитель для нескольких слов

Что позволяет сделать такие шаблоны:

  • *.*.computer.* — очередь, которая может обработать сообщения только от компьютеров без разницы где они находятся.
  • eu-east.# — очередь, которая может обрабатывать сообщения только из зоны eu-east

Протоколы

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

Спустя какое-то время появились три открытых стандарта, которые сейчас повсеместно используются:

Advanced Message Queuing Protocol (AMQP) — бинарный протокол, который проектировался для  взаимодействия между различными вендорами и стал заменой существующих проприетарных протоколов. Основными особенностями AMQP является надежности и совместимость.

  • Streaming Text Oriented Messaging Protocol (STOMP) — простой текстовый протокол обмена сообщениями, который очень похож на HTTP и работает поверх TCP.
  • MQTT (formerly MQ Telemetry Transport) — очень простой и легковесный протокол, который разрабатывался для минимального использования трафика и работы в нестабильной сети. Все эти качества идеально подошли для использования протокола для общения между устройствами.

Материалы

  • Message queues — отличная статья, которая описывает основные концепты работы очередей.
  • The Big Little Guide to Message Queues — большой гайд в котором описано про причины создания очередей их свойства и особенности работы, а также кратный разбор самых популярных реализаций.

Балансировка нагрузки

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

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

Помимо распределения нагрузки, балансировщики также выполняют дополнительные задачи, такие как обнаружение служб и проверка работоспособности. Иногда они работают в качестве API Gateway для маршрутизации трафика или его троттлинга. Например, отправлять запросы по специфичному URL на какой-то конкретный сервис и не давать пользователям делать больше указанного порога запросов в секунду.

Обнаружение служб

Это процесс, который позволяет определить набор сервером, на которые можно отправлять запросы. Для реализации этого подхода можно использовать несколько способов:

  • Файлы конфигурации.
  • DNS
  • Zookeper, Consul и т. д.

Проверка работоспособности

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

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

В активном режиме балансировщик периодически делает запросы на специальный эндпоинт, который проверяет состояние приложения. Их также можно разделить на несколько типов: liveness и readiness

Алгоритмы балансировки нагрузки

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

  • DNS
  • Sticky Session
  • Round Robin
  • Weighted Round Robin
  • Least Connection
  • IP Hash

DNS
Самый простой способ распределить запросы это использовать DNS, он позволяет работать клиентам с несколькими серверами и повысить их доступность.  Для этого достаточно зарегистрировать несколько серверов на одно доменное имя. Когда клиент запрашивает IP адрес, DNS возвращает список адресов серверов, который каждый раз начинается с другого адреса. Такой подход похож на работу алгоритма Round Robin.

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

Round Robin
Самый простой алгоритм. Балансировщик держит обычную очередь из серверов. Первый сервер в очереди обрабатывает запрос и помещается в конец очереди и так по кругу. Таким образом сервера равномерно нагружены.

Алгоритм отлично походит когда сервера в пуле имеют одинаковую мощность и время обработки запросов.

Weighted Round Robin
Тот же round robin, но имеет дополнительное свойство — вес сервера. С его помощью мы можем указать балансировщику сколько трафика отправлять на тот или иной сервер. Так сервера помощнее будут иметь больший вес и соответственно обрабатывать больше запросов чем другие сервера.

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

Алгоритм можно улучшить и учитывать не только количество соединений, но и среднее время. Тогда первым в списке будет сервер с наименьшим количеством подключений и наименьшим временем ответа. Такой алгоритм называется Least Response Time. Такой способ позволяет выровнять нагрузку если сервера отвечают с разной скоростью.

Hash
Такой способ использует в своей основе механизм хеширования. Он позволяет распределить запросы на основе хеша, для которого обычно используется IP адрес или URL. В таком случае запросы от одного и того же IP будут отправлены на один и тот же сервер. Тоже самое касается URL. Такой алгоритм обычно используют, когда сервер хранит какие-то локальные данные, которые нужны для ответа.

Примеры софтверных балансировщиков

  • HAProxy
  • nginx
  • AWS Route 53
  • AWS Elastic Load Balancer

Дополнительная информация

  • The power of two random choices. Автор предлагает отказаться от централизованной балансировки нагрузки и использовать балансировку на стороне клиента. Для этого информации и загруженности серверов сохраняется в каком-то кэше, который время от времени обновляется. Сами же клиенты будут случайным образом выбирать два сервера и отправлять запрос на менее загруженных из двух. Такой подход позволяет оптимально распределять нагрузку и избавиться от центрального балансировщика.
  • Introduction to modern network load balancing and proxying. Хорошая статья в которой описаны способы использования балансировщиков нагрузки и в чем разница между L4 и L7 балансировкой. Перевод на русский.
 Нет комментариев    133   2 мес   system-design

stateless и stateful сервисы

Пример stateful системы
Например наша система хранит в себе сессии пользователей, тем самым ответ на запрос пользователя зависит от состояния (сессии). При масштабировании сервиса, нам прийдется переносить все сессии на новый инстанс. Система стает сложной и не маневренной. Любой stateful сервис можно превратить в stateless, вынеся состояние в отдельный сервис и БД. Так мы можем вынести сессии во внешнее хранилище, сама система осталась stateful, но сам веб сервис stateless, тем самым мы можем просто его реплицировать.

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

Еще один пример
У нас есть интернет магазин — пока корзина пользователя хранится в памяти сервера, то это stateful. И у нас сразу возникают проблемы с масштабированием. Но когда мы выносим хранения корзины во внешний session storage — наш сервис становится stateless и мы можем спокойно его масштабировать, так как состояние хранится у нас в отдельном хранилище.

Очень советую почитать статью на RSND по данной теме.

Шардинг

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

Вертикальный шардинг

Вертикальный шардинг — это выделение таблицы или группы таблиц на отдельный сервер. Например, в приложении есть такие таблицы:

  • users — данные пользователей
  • photos — фотографии пользователей
  • albums — альбомы пользователей

Таблицу users Вы оставляете на одном сервере, а таблицы photos и albums переносите на другой. В таком случае в приложении Вам необходимо будет использовать соответствующее соединение для работы с каждой таблицей

Горизонтальный шардинг

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

  • На нескольких серверах создается одна и та же таблица (только структура, без данных).
  • В приложении выбирается условие, по которому будет определяться нужное соединение (например, четные на один сервер, а нечетные — на другой).
  • Перед каждым обращением к таблице происходит выбор нужного соединения.

Совместное использование

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

Key-value базы данных

Следует отметить, что большинство Key-value баз данных поддерживает шардинг на уровне платформы. Например, Memcache. В таком случае, Вы просто указываете набор серверов для соединения, а платформа сделает все остальное

Итог

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

P.S.

Помните, процесс масштабирования данных — это архитектурное решение, оно не связано с конкретной технологией. Не делайте ошибок наших отцов — не переезжайте с известной Вам технологии на новую из-за поддержки или не поддержки шардинга. Проблемы обычно связаны с архитектурой, а не конкретной базой данных

Ссылки

  1. Вертикальный шардинг
  2. Шардинг и репликация
 Нет комментариев    314   2019   system-design

Репликация данных

Репликация — одна из техник масштабирования баз данных. Состоит эта техника в том, что данные с одного сервера базы данных постоянно копируются (реплицируются) на один или несколько других. Для приложения появляется возможность использовать не один сервер для обработки всех запросов, а несколько. Таким образом появляется возможность распределить нагрузку с одного сервера на несколько.

Существует два основных подхода при работе с репликацией данных:

  1. Репликация Master-Slave;
  2. Репликация Master-Master.

Master-Slave репликация

В этом подходе выделяется один основной сервер базы данных, который называется Мастером. На нем происходят все изменения в данных (любые запросы INSERT/UPDATE/DELETE). Слейв сервер постоянно копирует все изменения с Мастера. С приложения на Слейв сервер отправляются запросы чтения данных. Таким образом Мастер сервер отвечает за изменения данных, а Слейв за чтение.

Несколько Слейвов

Преимущество этого типа репликации в том, что Вы можете использовать более одного Слейва. Обычно следует использовать не более 20 Слейв серверов при работе с одним Мастером.
Тогда из приложения выбирает случайным образом один из Слейвов для обработки запросов, тем самым распределяя нагрузку на БД.

Выход из строя

При выходе из строя Слейва, достаточно просто переключить все приложение на работу с Мастером. После этого восстановить репликацию на Слейве и снова его запустить.
Если выходит из строя Мастер, нужно переключить все операции (и чтения и записи) на Слейв. Таким образом он станет новым Мастером. После восстановления старого Мастера, настроить на нем реплику, и он станет новым Слейвом.

Master-Master репликация

В этой схеме, любой из серверов может использоваться как для чтения так и для записи.

«Ручная» репликация

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

Итог

Репликация используется в большей мере для резервирования баз данных и в меньшей для масштабирования. Master-Slave репликация удобна для распределения запросов чтения по нескольким серверам. Подход ручной репликации позволит использовать преимущества репликации для технологий, которые ее не поддерживают. Зачастую репликация используется вместе с шардингом при решении вопросов масштабирования.

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

 Нет комментариев    262   2019   system-design

Кэширование

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

Кэширование очень активно используют во множестве систем. Например:

  • Внутренний кэш баз данных.
  • DNS кэш внутри нашего компьютера или браузера.
  • Кэш статического контента в браузере.
  • CDN также является своего рода кэшем.

В любом приложении есть операции, которые долго выполнялись, но результат которых можно сохранить на какое-то время. Это позволит меньше выполнять таких операций и отдавать заранее сохранённые данные.

Что можно кэшировать?

  • Запросы в базу данных.
  • Пользовательские сессии.
  • Медленные операции внутри приложения (расчеты, какие-то итоговые данные и т. д.)
  • Запросы к внешним системам.

Алгоритм работы

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

Стратегии кэширования

Cache Aside

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

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

Плюсы:

  • Отлично подходит для тяжелых операций чтения.
  • Обычно система устойчива к отказу кэша. Если он упадет всегда можно пойти напрямую в базу данных.
  • Возможно использовать разные структуры данных для кэша и базы данных. Особенно полезно когда нам нужно закешировать результат какой-то сложной выборки

Минусы:

  • Из-за того что запись идет напрямую в базу данных, данные в кэше могут стать не консистентными. Для этого нужно использовать TTL (время жизни данных в кэше) или инвалидировать кэш, когда нужно гарантированно отдавать актуальные данные.



Read Through

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

Плюсы:

  • Отлично работает с тяжелыми операциями чтения.
  • Данные всегда в консистентном виде.

Минусы:

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



Write Through

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

Лучше всего использовать эту стратегию вместе с read-through подходом. В таком случае мы получаем плюсы двух стратегий.

Плюсы:

  • Гарантирует полною консистентность данных.
  • Отлично работает с тяжелыми операциями записи.

Минусы:

  • Добавляет дополнительную задержку для операций записи.



Write Back

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

Плюсы:

  • Позволяет сильно оптимизировать сложные операции записи.
  • Данные всегда в консистентном виде.

Минусы:

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

Алгоритмы вытеснения

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

  • LRU (Least recently used) — алгоритм, который находит и вытесняет данные, которые не использовались дольше всех.
  • MRU (Most Recently Used) — вытесняются последние используемые данные.
  • LFU (Least Frequently Used) — вытесняются редко запрашиваемые данные.

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

Проблемы с кэшированием

В процессе создания и работы кэширующей системы может возникнуть набор разные проблем и вопросы, такие как:

  • Деление данных между кэширующими серверами.
  • Параллельные запросы на обновление данных.
  • “Холодный” старт приложения.

Деление данных между кэширующими серверами
Для повышения надежности и производительности системы кеширования приходится разделять ее на несколько серверов. Поэтому возникает вопрос как делить данные между серверами.

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

Проблема такого подхода заключается в том, что в случае падения сервера мы теряем почти 80% данных из-за изменения месторасположения ключей.

Вариант 2. Логическое разделение данных на основе какого-то признака. Например мы можем разделять данные на основании пользователя. Так данные одного пользователя будут лежать рядом на одном сервере.
Примеры проблем и их решения отлично описаны в статье “Проблемы при работе с кэшем и способы их решения”

Параллельные запросы на обновление данных

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

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

Решение 2. Фоновое обновление кэша. Приложение всегда читает данные из кеша и никогда не ходит в базу данных. Данные в кеше обновляет специальный скрипт или программа, которая работает в фоне. В таком случае никогда не наступит параллельного обновления кеша. Но возникает проблема с временем реакции на изменение данных в БД.

Решение 3. Вероятностное обновление данных. Обновляем не только данные, которых нет в кэше, но и с какой-то вероятностью те что уже есть. Это позволит обновить данные, до того как они протухнут и будут удалены.

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

«Холодный» старт приложения
В момент запуска приложения данных в кэше может не быть. Как только пойдут запросы от пользователей все они пойдут массово в базу данных и начнуть одновременно обновлять кэш. Такая ситуация может привести к резкому падению производительности всей системы.

Решение. Можно прибегнуть к технике «прогревания» кеша. В таком случае при старте приложения мы также наполняем кэш данными, которые активно используются.

Итого

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

Ссылки

  1. Кэширование данных
  2. Обзор кэширования от amazon
  3. Кэширование и производительность веб-приложений
  4. 11 видов кэширования для современного сайта
  5. Тяжелое кэширование
  6. Проблемы при работе с кэшем и способы их решения
  7. Проблема одновременного перестроения кэшей
 1 комментарий    254   2019   system-design

Кластеризация

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

Виды кластеров

  1. Отказоустойчивые кластеры (High-availability clusters, HA)
  2. Кластеры с балансировкой нагрузки (Load balancing clusters)
  3. Вычислительные кластеры (High performance computing clusters, HPC)
  4. Системы распределенных вычислений

Отказоустойчивые кластеры

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

Подтипы отказоустойчивых кластеров

  1. С холодным резервом
  2. С горячим резервом
  3. С модульной избыточностью

Холодный резерв
Один сервер находится в пассивном режиме и ждет падения основного сервера

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

Модульная избыточность
Два сервера обрабатывают один и тот же запрос. Необходимо, когда нам нужно гарантированно обработать запрос и получить результат (результат берется любой).

Кластеры распределения нагрузки

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

Вычислительные кластеры

Кластеры используются в вычислительных целях, в частности в научных исследованиях. Для вычислительных кластеров существенными показателями являются высокая производительность процессора в операциях над числами с плавающей точкой (flops) и низкая латентность объединяющей сети, и менее существенными — скорость операций ввода-вывода, которая в большей степени важна для баз данных и web-сервисов. Вычислительные кластеры позволяют уменьшить время расчетов, по сравнению с одиночным компьютером, разбивая задание на параллельно выполняющиеся ветки, которые обмениваются данными по связывающей сети.

Типовые задачи для расчетных кластеров

  1. решение задач механики жидкости и газа, теплопередачи и теплообмена, электродинамики, акустики;
  2. моделирование аэрогазодинамических процессов;
  3. моделирование физико-химических процессов и реакций;
  4. моделирование сложного динамического поведения различных механических систем;
  5. решение задач цифровой обработки сигналов, финансового анализа, разнообразных математических задач, визуализации и представления данных
  6. анализ и расчет статической и динамической прочности;
  7. газодинамика, термодинамика, теплопроводность и радиочастотный анализ;
  8. моделирование задач любой степени геометрической сложности;
  9. рендеринг анимации и фотореалистичных VFX эффектов

Системы распределенных вычислений

Такие системы не принято считать кластерами, но их принципы в значительной степени сходны с кластерной технологией. Их также называют grid-системами. Главное отличие — низкая доступность каждого узла, то есть невозможность гарантировать его работу в заданный момент времени, поэтому задача должна быть разбита на ряд независимых друг от друга процессов. Такая система, в отличие от кластеров, не похожа на единый компьютер, а служит упрощенным средством распределения вычислений. Состоит из множества ресурсов разных типов.

Пример
Кластер в CERN представляет из себя иерархический грид, который имеет 3 слоя:

  • Нулевой — собирает информацию с датчиков и осуществляет первичное хранение информации
  • Tier 1 — хранит копии данных в разных точках мира
  • Tier 2 — преимущественно обладают высокой вычислительной мощностью — обрабатывают информацию.

Достоинства

  1. Эффективная утилизация ресурсов.
  2. Обновления без остановки
  3. Увеличение производительности
  4. Отказоустойчивость (круглосуточная работа)
  5. Абсолютная масштабируемость

Недостатки

  1. Синхронизация между приложениями — необходимо обеспечить синхронизацию данных между серверами в кластере.
  2. Цена
  3. Сложность в управлении
  4. Необходимость адаптации приложения для работы в кластере (веб-ферме).

Ссылки

  1. Википедия: Кластер (группа компьютеров)
  2. Кластеризация
  3. Кластерные вычислительные системы
  4. Кластерные архитектуры
  5. Википедия: Серверная ферма
  6. Отказоустойчивые кластеры (кластеры высокой доступности)
 Нет комментариев    294   2019   system-design

Pipeline архитектура

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

Составляющие

  1. Фильтр — преобразует или фильтрует данные, которые он получает через каналы, с которыми он связан. Фильтр может иметь любое количество входных каналов и любое количество выходных каналов.
  2. Канал — это соединитель, который передает данные от одного фильтра к другому. Это направленный поток данных, который обычно реализуется буфером данных для хранения всех данных до тех пор, пока следующий фильтр не успеет их обработать.
  3. Продюсер — является источником данных. Это может быть статический текстовый файл или устройство ввода с клавиатуры, постоянно создающее новые данные.
  4. Приемник или потребитель является целью данных. Это может быть другой файл, база данных или экран компьютера.

Примеры

UNIX приложения, выход одной программы можно передать на вход в другую программу.

$ ps aux | grep [k]de | gawk ’{ print $2}’

выводит на экран список процессов, которые содержат в имени kde


Компиляторы

Когда следует использовать этот шаблон

  1. Процесс обработки, требуемый приложением, можно легко разделить на ряд независимых этапов.
  2. У этапов обработки, которые выполняются приложением, разные требования к масштабируемости.
  3. Требуется определенная гибкость, чтобы изменять порядок шагов обработки, выполняемых приложением, или добавлять и удалять шаги.
  4. Система будет работать эффективнее, если распределить шаги обработки между несколькими серверами.
  5. Чтобы свести к минимуму последствия сбоя на шаге при обработке данных, требуется надежное решение

Проблемы и рекомендации

При выборе схемы реализации этого шаблона следует учитывать следующие моменты.

  1. Сложность — повышенная гибкость, которую обеспечивает этот шаблон, может также вызвать сложности, особенно если фильтры в конвейере распределяются между разными серверами.
  2. Надежность — используйте инфраструктуру, которая гарантирует сохранность данных, передаваемых между фильтрами в конвейере.
  3. Идемпотентность — свойство объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом. Если после получения сообщения происходит сбой фильтра в конвейере и операция переносится на другой экземпляр фильтра, часть операции может быть уже выполнена. Тем самым продолжение выполнения должно вернуть нам такой же результат.
  4. Повторяющиеся сообщения — если сбой фильтра в конвейере происходит после публикации сообщения для следующего этапа конвейера, может запуститься другой экземпляр фильтра и опубликовать копию этого сообщения в конвейере. Это может привести к передаче следующему фильтру двух экземпляров одного сообщения.

Достоинства

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

Недостатки

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

Ссылки

  1. Pipeline Architecture
  2. YouTube: 101 способ приготовления RabbitMQ и о pipeline-архитектуре
  3. Текст: 101 способ приготовления RabbitMQ и о pipeline-архитектуре
  4. Принципы и приёмы обработки очередей
  5. Pipes and Filters pattern
  6. Pipe-And-Filter
  7. Pipes and Filters
 Нет комментариев    1135   2019   system-design