Архитектура распределённых приложений

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

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

1.1 Принципы построения распределенных веб-систем

Что именно означает создание и управление масштабируемым веб-сайтом или приложением? На примитивном уровне это просто соединение пользователей с удаленными ресурсами через Интернет. А ресурсы или доступ к этим ресурсам, которые рассредоточены на множестве серверов и являются звеном, обеспечивающим масштабируемость веб-сайта.

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

  • Доступность: длительность работоспособного состояния веб-сайта критически важна по отношению к репутации и функциональности многих компаний. Для некоторых более крупных онлайновых розничных магазинов, недоступность даже в течение нескольких минут может привести к тысячам или миллионам долларов потерянного дохода. Таким образом, разработка их постоянно доступных и эластичных к отказу систем и является и фундаментальным деловым и технологическим требованием. Высокая доступность в распределенных системах требует внимательного рассмотрения избыточности для ключевых компонентов, быстрого восстановления после частичных системных отказов и сглаженного сокращения возможностей при возникновении проблем.
  • Производительность: Производительность веб-сайта стала важным показателем для большинства сайтов. Скорость веб-сайта влияет на работу и удовлетворенность пользователей, а также ранжирование поисковыми системами - фактор, который непосредственно влияет на удержание аудитории и доход. В результате, ключом является создание системы, которая оптимизирована для быстрых ответов и низких задержек.
  • Надежность: система должна быть надежной, таким образом, чтобы определенный запрос на получение данных единообразно возвращал определенные данные. В случае изменения данных или обновления, то тот же запрос должен возвращать новые данные. Пользователи должны знать, если что-то записано в систему или храниться в ней, то можно быть уверенным, что оно будет оставаться на своем месте для возможности извлечения данных впоследствии.
  • Масштабируемость: Когда дело доходит до любой крупной распределенной системы, размер оказывается всего лишь одним пунктом из целого списка, который необходимо учитывать. Не менее важным являются усилия, направленные на увеличение пропускной способности для обработки больших объемов нагрузки, которая обычно и именуется масштабируемость системы. Масштабируемость может относиться к различным параметрам системы: количество дополнительного трафика, с которым она может справиться, насколько легко нарастить ёмкость запоминающего устройства, или насколько больше других транзакций может быть обработано.
  • Управляемость: проектирование системы, которая проста в эксплуатации еще один важный фактор. Управляемость системы приравнивается к масштабируемости операций «обслуживание" и «обновления». Для обеспечения управляемости необходимо рассмотреть вопросы простоты диагностики и понимания возникающих проблем, легкости проведения обновлений или модификации, прихотливости системы в эксплуатации. (То есть, работает ли она как положено без отказов или исключений?)
  • Стоимость: Стоимость является важным фактором. Она, очевидно, может включать в себя расходы на аппаратное и программное обеспечение, однако важно также рассматривать другие аспекты, необходимые для развертывания и поддержания системы. Количество времени разработчиков, требуемое для построения системы, объем оперативных усилий, необходимые для запуска системы, и даже достаточный уровень обучения - все должно быть предусмотрено. Стоимость представляет собой общую стоимость владения.

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

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

1.2 Основы

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

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

Пример: Приложение хостинга изображений

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

Вообразите систему, где пользователи имеют возможность загрузить свои изображения на центральный сервер, и при этом изображения могут запрашиваться через ссылку на сайт или API, аналогично Flickr или Picasa. Для упрощения описания давайте предположим, что у этого приложения есть две основные задачи: возможность загружать (записывать) изображения на сервер и запрашивать изображения. Безусловно, эффективная загрузка является важным критерием, однако приоритетом будет быстрая доставка по запросу пользователей (например, изображения могут быть запрошены для отображения на веб-странице или другим приложением). Эта функциональность аналогична той, которую может обеспечить веб-сервер или граничный сервер Сети доставки контента (Content Delivery Network, CDN). Сервер CDN обычно хранит объекты данных во многих расположениях, таким образом, их географическое/физическое размещение оказывается ближе к пользователям, что приводит к росту производительности.

Другие важные аспекты системы:

  • Количество хранимых изображений может быть безгранично, таким образом, масштабируемость хранения необходимо рассматривать именно с этой точки зрения.
  • Должна быть низкая задержка для загрузок/запросов изображения.
  • Если пользователь загружает изображение на сервер, то его данные должны всегда оставаться целостными и доступными.
  • Система должна быть простой в обслуживании (управляемость).
  • Так как хостинг изображений не приносит большой прибыли, система должна быть экономически эффективной.

Другая потенциальная проблема с этим дизайном состоит в том, что у веб-сервера, такого как Apache или lighttpd обычно существует верхний предел количества одновременных соединений, которые он в состоянии обслужить (значение по умолчанию - приблизительно 500, но оно может быть намного выше), и при высоком трафике записи могут быстро израсходовать этот предел. Так как чтения могут быть асинхронными или использовать в своих интересах другую оптимизацию производительности как gzip-сжатие или передача с делением на порции, веб-сервер может переключить чтения подачи быстрее и переключиться между клиентами, обслуживая гораздо больше запросов, чем максимальное число соединений (с Apache и максимальным количеством соединений, установленном в 500, вполне реально обслуживать несколько тысяч запросов чтения в секунду). Записи, с другой стороны, имеют тенденцию поддерживать открытое соединение на протяжении всего времени загрузки. Так передача файла размером 1 МБ на сервер могла занять больше 1 секунды в большинстве домашних сетей, в результате веб-сервер сможет обработать только 500 таких одновременных записей.


Рисунок 1.2: Разделение чтения и записи

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

Преимущество этого подхода состоит в том, что мы в состоянии решить проблемы независимо друг от друга - при этом нам не придется думать о необходимости записи и получении новых изображений в одном контексте. Обе из этих служб все еще используют глобальный корпус изображений, но при использовании методов соответствующих определенной службе, они способны оптимизировать свою собственную производительность (например, помещая запросы в очередь, или кэшируя популярные изображения - более подробно об этом речь пойдет далее). Как с точки зрения обслуживания, так и стоимости каждая служба может быть масштабирована независимо по мере необходимости. И это является положительным фактором, поскольку их объединение и смешивание могло бы непреднамеренно влиять на их производительность, как в сценарии, описанном выше.

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

К примеру, Flickr решает эту проблему чтения-записи, распределяя пользователи между разными модулями, таким образом, что каждый модуль может обслуживать только ограниченное число определенных пользователей, и когда количество пользователи увеличиваются, больше модулей добавляется к кластеру (см. презентацию масштабирования Flickr,
http://mysqldba.blogspot.com/2008/04/mysql-uc-2007-presentation-file.html). В первом примере проще масштабировать аппаратные средства на основе фактической нагрузки использования (число чтений и записей во всей системе), тогда как масштабировние Flickr просиходит на основе базы пользователей(однако, здесь используется предположение равномерного использования у разных пользователей, таким образом, мощность нужно планировать с запасом). В прошлом недоступность или проблема с одной из служб приводили в нерабочее состояние функциональность целой системы (например, никто не может записать файлы), тогда недоступность одного из модулей Flickr будет влиять только на пользователей, относящихся к нему. В первом примере проще выполнить операции с целым набором данных - например, обновляя службу записи, чтобы включить новые метаданные, или выполняя поиск по всем метаданным изображений - тогда как с архитектурой Flickr каждый модуль должен был быть подвергнут обновлению или поиску (или поисковая служба должна быть создана, чтобы сортировать те метаданные, которые фактически для этого и предназначены).

Что касается этих систем - не существует никакой панацеи, но всегда следует исходить из принципов, описанных в начале этой главы: определить системные потребности (нагрузка операциями «чтения» или «записи» или всем сразу, уровень параллелизма, запросы по наборам данных, диапазоны, сортировки, и т.д.), провести сравнительное эталонное тестирование различных альтернатив, понять условия потенциального сбоя системы и разработать комплексный план на случай возникновения отказа.

Избыточность

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

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

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

.

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

.

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


Рисунок 1.3: Приложение хостинга изображений с избыточностью

Сегментирование

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

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

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

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

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


Рисунок 1.4: Приложение хостинга изображений с избыточностью и сегментированием

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

Другая потенциальная проблема возникает в форме
несогласованности (неконсистетности) .Когда различные сервисы выполняют считывание и запись на совместно используемом ресурсе, потенциально другой службе или хранилище данных, существует возможность возникновения условий «состязания» - где некоторые данные считаются обновленными до актуального состояния, но в реальности их считывание происходит до момента актуализации - и таком случае данные неконсистентны. Например, в сценарии хостинга изображений, состояние состязания могло бы возникнуть в случае, если бы один клиент отправил запрос обновления изображения собаки с изменением заголовка «Собака» на «Гизмо», в тот момент, когда другой клиент считывал изображение. В такой ситуации неясно, какой именно заголовок, «Собака» или «Гизмо», был бы получен вторым клиентом.

.

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

1.3. Структурные компоненты быстрого и масштабируемого доступа к данным

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

Самые простые веб-приложения, например, приложения стека LAMP, схожи с изображением на .


Рисунок 1.5: Простые веб-приложения

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

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


Рисунок 1.6: Упрощенное веб-приложение

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

Для рассмотрения данного раздела давайте предположим, что у Вас есть много терабайт (ТБ) данных, и Вы позволяете пользователям получать доступ к небольшим частям этих данных в произвольном порядке. (См. .)
Схожей задачей является определение местоположения файла изображения где-нибудь на файловом сервере в примере приложения хостинга изображений.


Рисунок 1.7: Доступ к определенным данным

Это особенно трудно, потому что загрузка терабайтов данных в память может быть очень накладной и непосредственно влияет на количество дисковых операций ввода-вывода. Скорость чтения с диска в несколько раз ниже скорости чтения из оперативной памяти - можно сказать, что доступ к памяти с так же быстр, как Чак Норрис, тогда как доступ к диску медленнее очереди в поликлинике. Эта разность в скорости особенно ощутима для больших наборов данных; в сухих цифрах доступ к памяти 6 раз быстрее, чем чтение с диска для последовательных операций чтения, и в 100,000 раз - для чтений в случайном порядке (см. «Патологии Больших Данных», http://queue.acm.org/detail.cfm?id=1563874).). Кроме того, даже с уникальными идентификаторами, решение проблемы нахождения местонахождения небольшой порции данных может быть такой же трудной задачей, как и попытка не глядя вытащить последнюю конфету с шоколадной начинкой из коробки с сотней других конфет.

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

Кэши

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

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


Рисунок 1.8: Размещение кэша на узле уровня запроса

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


Рисунок 1.9: Системы кэшей

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

Глобальный кэш

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

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


Рисунок 1.10: Глобальный кэш, где кэш ответственен за извлечение



Рисунок 1.11: Глобальный кэш, где узлы запроса ответственны за извлечение

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

Распределенный кэш

Данные индексы часто хранятся в памяти или где-нибудь очень локально по отношению к входящему запросу клиента. Berkeley DB (BDB) и древовидные структуры данных, которые обычно используются, чтобы хранить данные в упорядоченных списках, идеально подходят для доступа с индексом.

Часто имеется много уровней индексов, которые служат картой, перемещая вас от одного местоположения к другому, и т.д., до тех пор пока вы не получите ту часть данных, которая вам необходима. (См. )


Рисунок 1.17: Многоуровневые индексы

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

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

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

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

И это ключевой момент в крупномасштабных системах, потому что даже будучи сжатыми, эти индексы могут быть довольно большими и затратными для хранения. Предположим, что у нас есть много книг со всего мира в этой системе, - 100,000,000 (см. запись блога «Внутри Google Books»)- и что каждая книга состоит только из 10 страниц (в целях упрощения расчетов) с 250 словами на одной странице: это суммарно дает нам 250 миллиардов слов. Если мы принимаем среднее число символов в слове за 5, и каждый символ закодируем 8 битами (или 1 байтом, даже при том, что некоторые символы на самом деле занимают 2 байта), потратив, таким образом, по 5 байтов на слово, то индекс, содержащий каждое слово только один раз, потребует хранилище емкостью более 1 терабайта. Таким образом, вы видите, что индексы, в которых есть еще и другая информация, такая, как наборы слов, местоположение данных и количества употреблений, могут расти в объемах очень быстро.

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

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

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

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


Рисунок 1.18: Балансировщик нагрузки

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

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


Рисунок 1.19: Множественные балансировщики нагрузки

Как и прокси, некоторые балансировщики нагрузки могут также направлять запросы по-разному, в зависимости от типа запроса. Они также известны как реверсивные (обратные) прокси.

Управление данными, специфичными для определенного сеанса пользователя, является одной из проблем при использовании балансировщиков нагрузок. На сайте электронной коммерции, когда у Вас есть только один клиент, очень просто позволить пользователям помещать вещи в свою корзину и сохранять ее содержимое между визитами (это важно, так как вероятность продажи товара значительно возрастает, если по возвращении пользователя на сайт, продукт все еще находится в его корзине). Однако если пользователь направлен к одному узлу для первого сеанса, и затем к другому узлу во время его следующего посещения, то могут возникать несоответствия, так как новый узел может не иметь данных относительно содержимого корзины этого пользователя. (Разве вы не расстроитесь, если поместите упаковку напитка Mountain Dew в Вашу корзину, и, когда вернетесь, ее там уже не будет?) Одно из решений может состоять в том, чтобы сделать сеансы «липкими», так чтобы пользователь был всегда направлен к тому же узлу. Однако использование в своих интересах некоторых функций надежности, таких как автоматическая отказоустойчивость, будет существенно затруднено. В этом случае корзина пользователя всегда будет иметь содержание, но если их липкий узел станет недоступным, то будет необходим особый подход, и предположение о содержании корзины не будет больше верно (хотя, стоит надеяться, что это предположение не будет встроено в приложение). Конечно, данную проблему можно решить при помощи других стратегий и инструментов, как описанных в этой главе, таких как службы, так и многих других (как кэши браузера, cookie и перезапись URL).

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

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

Очереди

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


Рисунок 1.20: Синхронный запрос

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

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


Рисунок 1.21: Использование очередей для управления запросами

Очереди входа. Механизм работы очереди очень прост: задача приходит, попадает в очередь, и затем «рабочие» принимают следующую задачу, как только у них появляется возможность обработать ее. (См. .) Эти задачи могут представлять собой простые записи в базу данных или что-то столь же сложное как генерация изображения предварительного просмотра для документа. Когда клиент отправляет запросы постановки задач в очередь, ему больше не требуется ожидать результатов выполнения; вместо этого запросы нуждаются только в подтверждении факта их получения должным образом. Это подтверждение может позже служить ссылкой на результаты работы, когда клиент затребует их.

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

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

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

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

Исторически первыми получила широкое распространение файл-серверная архитектура, поскольку ее логика проста и перевести на такую архитектуру уже находящиеся в эксплуатации ИС –проще всего. Затем она была трансформирована в архитектуру сервер-клиент, которую можно трактовать как ее логическое продолжение. Современные системы, используемые в глобальной сети INTERNET в основном относятся к архитектуре распределенных объектов (см. Рис. III 15 )


ИС можно представить состоящую из следующих составных частей (Рис. III‑16)

III.03.2. a Файл-серверные приложения.

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


Плюсы:

Плюсы файл-серверной архитектуры:

Простота организации;

Не противоречит необходимым требованиям к БД к поддержанию целостности и надежности.

Перегрузка сети;

Непредсказуемость реакции на запрос.

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

III.03.2. b Клиент-серверные приложения.

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


В модели «тонкий клиент” вся работа приложения и управление данны­ми выполняются на сервере. Пользовательский интерфейс в этих системах "переселяется" на персональный компьютер, а само программное приложение выполняет функции сервера, т.е. выполняет все процессы приложения и управляет данными. Модель тонкого клиента можно также реализовать там, где клиенты компьютеры или рабочие станции. Сетевые устройства запускают Internet-броузер и пользовательский интерфейс, реализованный внутри системы.

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

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

III.03.2. c Двух- и трехуровневые архитектура клиент-сервер.

Все рассмотренные выше архитектуры являются двухуровневыми. В них различается уровень клиента и уровень сервера. Строго говоря, ИС состоит из трех логических уровней:

· Уровень пользователя;

· Уровень приложения:

· Уровень данных.

Поэтому в двухуровневой модели, где задействованы только два уровня, возникает проблема с масштабируемостью и производительностью, если выбрана модель тонкий клиент, либо проблемы связанные с управлением системы, если взята модель толстый клиент. Избежать этих проблем можно, если применять модель, состоящую из трех уровней, где два из них сервера(Рис. III‑21).

Сервер данных

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

Таблица III‑5 Применение разных типов архитектур

Архитектура Приложение
Двухуровневая тонкий клиент 1 Наследуемые системы, в которых не целесообразно разделять выполнение приложения и управление данными. 2 Приложения с интенсивными вычислениями, но малыми объемами управления данными. 3 Приложения с большими объемами данных, но малым количеством вычислений.
Двухуровневый толстый клиент 1 Приложения, где пользователю требуется интенсивная обработка данных, то есть визуализация данных. 2 Приложения с относительно постоянным набором функций пользователя, применяемых к среде с хорошо отлаженным системным управлением.
Трехуровневый сервер-клиент 1 Большие приложения с сотами и тысячами клиентов 2 Приложения, в которых часто меняются и данные и методы их обработки. 3 Приложения, в которых выполняются интеграции данных из многих источников.

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

III.03.2. d Архитектура распределенных объектов.

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

Диспетчер драйвер ODBC
Драйвер 1
Драйвер К
БД 1
БД К
Работа с SQL

Архитектура ODBC включает компоненты:

1. Приложение (например, ИС). Оно выполняет задачи: запрашивает соединение с источником данных, посылает SQL – запросы к источнику данных, описывает область хранения и формат для SQL – запросов, обрабатывает ошибки и оповещает о них пользователя, осуществляет фиксацию или откат транзакций, запрашивает соединение с источником данных.

2. Диспетчер устройств. Он загружает драйвера по требованию приложений, предлагает единый интерфейс всем приложениям, причем интерфейс администратора ODBC одинаков и независим то того, с какой СУБД приложение будет взаимодействовать. Диспетчер драйверов, поставляемый Microsoft, является динамически загружаемой библиотекой DLL.

3. Драйвер зависит от СУБД. Драйвер ODBC – это динамическая библиотека DLL, которая реализует функции ODBC и взаимодействует с источником данных. Драйвер – это программа, которая обрабатывает запрос какой-то функции специфично для СУБД (может модифицировать запросы в соответствии с СУБД) и возвращает результат приложению. Каждая СУБД, поддерживающая технологию ODBC, должна предоставить разработчикам приложений драйвер для этой СУБД.

4. Источник данных содержит управляющую информацию, задаваемую пользователем, информацию об источнике данных и используется для доступа к конкретной СУБД. При этом используются средства ОС и сетевой платформы.

Динамическая модель

Эта модель предполагает много аспектов, для представления которых на языке UML используется как минимум 5 диаграмм см. пп. 2.04.2- 2.04.5.

Рассмотрим аспект управления. Модель управления дополняет структурные модели.

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

Можно выделить два основных типа управления в программных системах.

1. Централизованное управление.

2. Управление, основанное на событиях.

Централизованное управление может быть:

· Иерархическим - по принципу «вызов-возврат» (именно так чаще всего работает учебные программы)

· Модель диспетчера , которая применяется для параллельных систем.

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

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

Примером такого управления является организация приложений в ОС Windows.

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

Пользовательский интерфейс

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

III.03.4. a Психофизические особенности человека, связанные с восприятием и обработкой информации.

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

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

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

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

Краткосрочная память - самое узкое место в системе обработки информации человека. Ее емкость равна 7±2 несвязанных объекта. Невостребованная информация хранится в ней не более 30 секунд. Чтобы не забыть какую-нибудь важную для нас информацию, мы обычно повторяем ее про себя, обновляя информацию в краткосрочной памяти. Таким образом, при проектировании интерфейсов следует иметь в виду, что подавляющему большинству сложно, например, запомнить и ввести на другом экране числа, содержащие более пяти цифр.

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

III.03.4. b Основные критерии оценки интерфейсов

Многочисленные опросы и обследования, проводимые ведущими фирмами по разработке программного обеспечения, показали, что пользователи ценят в интерфейсе:

1)простоту освоения и запоминания - конкретно оценивают время освоения и продолжительность сохранения информации и памяти;

2)скорость достижения результатов при использовании системы, которая определяется количеством вводимых или выбираемых мышью команд и настроек;

3)субъективную удовлетворенность при эксплуатации системы (удобство работы, утомляемость и т. д.).

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

С этой точки зрения на сегодняшний день наилучшими характеристиками для пользователей-профессионалов обладают интерфейсы со свободной навигацией, а для пользователей-непрофессионалов - интерфейсы прямого манипулирования. Давно замечено, что при выполнении операции копирования файлов при прочих равных условиях большинство профессионалов используют оболочки типа Far, а непрофессионалы - «перетаскивание объектов» Windows.

III.03.4. c Типы интерфейсов пользователя

Различают следующие типы пользовательских интерфейсов:

Примитивные

Со свободной навигацией

Прямого манипулирования.

Интерфейс примитивный

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

Интерфейс Меню.

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

  • Поль М. Дюваль, Стивен М. Матиас III, Эндрю Гловер. Построение программного обеспечения при каждом изменении (Документ)
  • Соловьев В.И. Стратегия и тактика конкуренции на рынке программного обеспечения (Документ)
  • Описание - Технологии создания и методика оценки программного обеспечения (Документ)
  • Канер Сэм, Фолк Джек, Нгуен Кек Енг. Тестирование программного обеспечения. Фундаментальные концепции менеджмента бизнес-приложений (Документ)
  • Тамре Луиза. Введение в тестирование программного обеспечения (Документ)
  • Ответы к ГОСам по АСУ в 2009 году (Шпаргалка)
  • Стандарты по единой системе программной документации (Стандарт)
  • n1.doc

    11. Архитектура распределенных систем

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


    • знать основные преимущества и недостатки распределенных систем;

    • иметь представление о различных подходах, используемых при разработке архитектур клиент/сервер;

    • понимать различия между архитектурой клиент/сервер и архитектурой распределенных объектов;

    • знать концепцию брокера запросов к объектам и принципы, реализованные в стандартах CORBA.

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

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

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

    2. Встроенные системы, предназначенные для работы на одном процессоре либо на интегрированной группе процессоров. К ним относятся системы управления бытовыми устройствами, различными приборами и др.

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

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

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

    3. Параллельность. В распределенных системах несколько процессов могут одновременно выполняться на разных компьютерах в сети. Эти процессы могут (но не обязательно) взаимодействовать друг с другом во время их выполнения.

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

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

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

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

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

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

    Непредсказуемость. Как известно всем пользователям Web-сети, реакция распределенных систем на определенные события непредсказуема и зависит от полной загрузки системы, ее организации и сетевой нагрузки. Так как все эти параметры могут постоянно меняться, время, затраченное на выполнение запроса пользователя, в тот или иной момент может существенно различаться.
    При обсуждении преимуществ и недостатков распределенных систем в книге определяется ряд критических проблем проектирования таких систем (табл. 11.1). В этой главе основное внимание уделяется архитектуре распределенного ПО, так как я полагаю, что при разработке программных продуктов наиболее значимым является именно этот момент. Если вас интересуют другие темы, обратитесь к специализированным книгам по распределенным системам.
    Таблица 11.1. Проблемы проектирования распределенных систем


    Проблема проектирования

    Описание

    Идентификация ресурсов

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

    Коммуникации

    Универсальная работоспособность Internet и эффективная реализация протоколов TCP/IP в Internet для большинства распределенных систем служат примером наиболее эффективного способа организации взаимодействия между компьютерами. Однако там, где на производительность, надежность и прочее накладываются специальные требования, можно воспользоваться альтернативными способами системных коммуникаций

    Качество системного сервиса

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

    Архитектура программного обеспечения

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

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

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

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

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

    11.1. Многопроцессорная архитектура

    Самой простой распределенной системой является многопроцессорная система. Она состоит из множества различных процессов, которые могут (но не обязательно) выполняться на разных процессорах. Данная модель часто используется в больших системах реального времени. Как вы узнаете из главы 13, эти системы собирают информацию, принимают на ее основе решения и отправляют сигналы исполнительному механизму, который изменяет системное окружение. В принципе все процессы, связанные со сбором информации, принятием решений и управлением исполнительным механизмом, могут выполняться на одном процессоре под управлением планировщика заданий. Использование нескольких процессоров повышает производительность системы и ее способность к восстановлению. Распределение процессов между процессорами может переопределяться (присуще критическим системам) или же находиться под управлением диспетчера процессов.

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

    Рис. 11.1. Многопроцессорная система управления движением транспорта
    Системы ПО, одновременно выполняющие множество процессов, не обязательно являются распределенными. Если в системе более одного процессора, реализовать распределение процессов не представляет труда. Однако при создании многопроцессорных программных систем не обязательно отталкиваться только от распределенных систем. При проектировании систем такого типа, по существу, используется тот же подход, что и при проектировании систем реального времени, которые рассматриваются в главе 13.

    11.2. Архитектура клиент/сервер

    В главе 10 уже рассматривалась концепция клиент/сервер. В архитектуре клиент/сервер программное приложение моделируется как набор сервисов, предоставляемых серверами, и множество клиентов, использующих эти сервисы . Клиенты должны знать о доступных (имеющихся) серверах, хотя могут и не иметь представления о существовании других клиентов. Как видно из рис. 11.2, на котором представлена схема распределенной архитектуры клиент/сервер, клиенты и серверы представляют разные процессы.


    Рис. 11.2. Система клиент/сервер
    В системе между процессами и процессорами не обязательно должно соблюдаться отношение "один к одному". На рис. 11.3 показана физическая архитектура системы, которая состоит из шести клиентских машин и двух серверов. На них запускаются клиентские и серверные процессы, изображенные на рис. 11.2. В общем случае, говоря о клиентах и серверах, я подразумеваю скорее логические процессы, чем физические машины, на которых выполняются эти процессы.

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

    Самой простой архитектурой клиент/сервер является двухуровневая, в которой приложение состоит из сервера (или множества идентичных серверов) и группы клиентов. Существует два вида такой архитектуры (рис. 11.5).
    1. Модель тонкого клиента. В этой модели вся работа приложения и управление данными выполняются на сервере. На клиентской машине запускается только ПО уровня представления.

    2. Модель толстого клиента. В этой модели сервер только управляет данными. На клиентской машине реализована работа приложения и взаимодействие с пользователем системы.


    Рис. 11.3. Компьютеры в сети клиент/сервер

    Рис. 11.4. Уровни программного приложения
    Тонкий клиент двухуровневой архитектуры – самый простой способ перевода существующих централизованных систем (см. главу 26) в архитектуру клиент/сервер. Пользовательский интерфейс в этих системах "переселяется" на персональный компьютер, а само программное приложение выполняет функции сервера, т.е. выполняет все процессы приложения и управляет данными. Модель тонкого клиента можно также реализовать там, где клиенты представляют собой обычные сетевые устройства, а не персональные компьютеры или рабочие станции. Сетевые устройства запускают Internet-броузер и пользовательский интерфейс, реализованный внутри системы.


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

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

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


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

    Появление языка Java и загружаемых аплетов позволили разрабатывать модели клиент/сервер, которые находятся где-то посередине между моделями тонкого и толстого клиента. Часть программ, составляющих приложение, можно загружать на клиентской машине как аплеты Java и тем самым разгрузить сервер. Интерфейс пользователя строится посредством Web-броузера, который запускает аплеты Java. Однако Web-броузеры от различных производителей и даже различные версии Web-броузеров от одного производителя не всегда выполняются одинаково. Более ранние версии броузеров на старых машинах не всегда могут запустить аплеты Java. Следовательно, такой подход можно использовать только тогда, когда вы уверены, что у всех пользователей системы установлены броузеры, совместимые с Java.

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


    Рис. 11.7. Трехуровневая архитектура клиент/сервер
    Архитектура ПО, построенная по трехуровневой модели клиент/сервер, не требует, чтобы в сеть были объединены три компьютерных системы. На одном компьютере-сервере можно запустить и выполнение приложения, и управление данными как отдельные логические серверы. В то же время, если требования к системе возрастут, можно будет относительно просто разделить выполнение приложения и управление данными и выполнять их на разных процессорах.

    Банковскую систему, использующую Internet-сервисы, можно реализовать с помощью трехуровневой архитектуры клиент/сервер. База данных расчетов (обычно расположенная на главном компьютере) предоставляет сервисы управления данными, Web-сервер поддерживает сервисы приложения, например средства перевода денег, генерацию отчетов, оплату счетов и др. А компьютер пользователя с Internet-броузером является клиентом. Как показано на рис. 11.8, эта система масштабируема, так как в нее относительно просто добавить новые Web-серверы при увеличении количества клиентов.

    Использование трехуровневой архитектуры в этом примере позволило оптимизировать передачу данных между Web-сервером и сервером базы данных. Взаимодействие между этими системами не обязательно строить на стандартах Internet, можно использовать более быстрые коммуникационные протоколы низкого уровня. Обычно информацию от базы данных обрабатывает эффективное промежуточное ПО, которое поддерживает запросы к базе данных на языке структурированных запросов SQL.

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


    Рис. 11.8. Распределенная архитектура банковской системы с использованием Internet -сервисов
    Разработчики архитектур клиент/сервер, выбирая наиболее подходящую, должны учитывать ряд факторов. В табл. 11.2 перечислены различные случаи применения архитектуры клиент/сервер.
    Таблица 11.2. Применение разных типов архитектуры клиент/сервер


    Архитектура

    Приложения

    Двухуровневая архитектура тонкого клиента

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

    Приложения с интенсивными вычислениями, например компиляторы, но с незначительным объемом управления данными.

    Приложения, в которых обрабатываются большие массивы данных (запросы), но с небольшим объемом вычислений в самом приложении

    Двухуровневая архитектура толстого клиента

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

    Приложения с относительно постоянным набором функций на стороне пользователя, применяемых в среде с хорошо отлаженным системным управлением

    11.3. Архитектура распределенных объектов

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

    Более общим подходом, применяемым в проектировании распределенных систем, является стирание различий между клиентом и сервером и проектирование архитектуры системы как архитектуры распределенных объектов. В этой архитектуре (рис. 11.9) основными компонентами системы являются объекты, предоставляющие набор сервисов через свои интерфейсы. Другие объекты вызывают эти сервисы, не делая различий между клиентом (пользователем сервиса) и сервером (поставщиком сервиса).


    Рис. 11.9. Архитектура распределенных объектов
    Объекты могут располагаться на разных компьютерах в сети и взаимодействовать посредством промежуточного ПО. По аналогии с системной шиной, которая позволяет подключать различные устройства и поддерживать взаимодействие между аппаратными средствами, промежуточное ПО можно рассматривать как шину программного обеспечения. Она предоставляет набор сервисов, позволяющий объектам взаимодействовать друг с другом, добавлять или удалять их из системы. Промежуточное ПО называют брокером запросов к объектам. Его задача – обеспечивать интерфейс между объектами. Брокеры запросов к объектам рассматриваются в разделе 11.4.

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

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

    Гибкость и масштабируемость системы. Для того чтобы справиться с системными нагрузками, можно создавать экземпляры системы с одинаковыми сервисами, которые будут предоставляться разными объектами или разными экземплярами (копиями) объектов. При увеличении нагрузки в систему можно добавить новые объекты, не прерывая при этом работу других ее объектов.

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

    2. Как гибкий подход к реализации систем клиент/сервер. В этом случае логическая модель системы – это модель клиент/сервер, в которой клиенты и серверы реализованы как распределенные объекты, взаимодействующие посредством программной шины. При таком подходе легко заменить систему, например двухуровневую на многоуровневую. В этом случае ни сервер, ни клиент не могут быть реализованы в одном объекте, однако могут состоять из множества небольших объектов, каждый из которых предоставляет определенный сервис.
    Примером системы, которой подходит архитектура распределенных объектов, может служить система обработки данных, хранящихся в разных базах данных (рис. 11.10). В этом примере любую базу данных можно представить как объект с интерфейсом, предоставляющим доступ к данным "только чтение". Каждый из объектов-интеграторов занимается определенными типами зависимостей между данными, собирая информацию из баз данных, чтобы попытаться проследить эти зависимости.

    Объекты-визуализаторы взаимодействуют с объектами-интеграторами для представления данных в графическом виде либо для составления отчетов по анализируемым данным. Способы представление графической информации рассматриваются в главе 15.


    Рис. 11.10. Архитектура распределенной системы обработки данных
    Для такого типа приложений архитектура распределенных объектов подходит больше, чем архитектура клиент/сервер, по трем причинам.
    1. В этих системах (в отличие, например, от системы банкоматов) нет одного поставщика сервиса, на котором были бы сосредоточены все сервисы управления данными.

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

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

    11.4. CORBA

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

    В настоящий момент для поддержки распределенных объектных вычислений существует два основных стандарта промежуточного ПО.
    1. CORBA (Common Object Request Broker Architecture– архитектура брокеров запросов к общим объектам). Это набор стандартов для промежуточного ПО, разработанный группой OMG (Object Management Group – группа по управлению объектами). OMG является консорциумом фирм-производителей программного и аппаратного обеспечения, в числе которых такие компании, как Sun, Hewlett-Packard и IBM. Стандарты CORBA определяют общий машинонезависимый подход к распределенным объектным вычислениям. Разными производителями разработано множество реализаций этого стандарта. Стандарты CORBA поддерживаются операционной системой Unix и операционными системами от Microsoft.

    2. DCOM (Distributed Component Object Model – объектная модель распределенных компонентов). DCOM представляет собой стандарт, разработанный и реализованный компанией Microsoft и интегрированный в ее операционные системы. Данная модель распределенных вычислений менее универсальна, чем CORBA и предлагает более ограниченные возможности сетевых взаимодействий. В настоящий момент использование DCOM ограничивается операционными системами Microsoft.
    Здесь я решил уделить внимание технологии CORBA, поскольку она более универсальна. Кроме того, я считаю, что, вероятно, CORBA, DCOM и другие технологии, например RMI (Remote Method Invocation – вызов удаленного метода, технология построения распределенных приложений на языке Java), будут постепенно сближаться друг с другом и это сближение будет базироваться на стандартах CORBA. Поэтому нет необходимости в еще одном стандарте. Различные стандарты будут только помехой в дальнейшем развитии.

    Стандарты CORBA определены группой OMG, которая объединяет более 500 компаний, поддерживающих объектно-ориентированные разработки. Роль OMG – создание стандартов для объектно-ориентированных разработок, а не обеспечение конкретных реализаций этих стандартов. Эти стандарты находятся в свободном доступе на Web-узле OMG. Группа занимается не только стандартами CORBA, но также определяет широкий диапазон других стандартов, включая язык моделирования UML.

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

    2. Стандартные объекты, которые определены группой OMG для специфических задач. Во время написания книги множество специалистов занимались разработкой стандартов объектов в области финансирования, страхования, электронной коммерции, здравоохранения и многих других.

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

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


    Рис. 11.11. Структура распределенного приложения, основанного на стандартах CORBA
    Стандарты CORBA описывают четыре основных элемента.
    1. Модель объектов, в которой объект CORBA инкапсулирует состояния посредством четкого описания на языке IDL (Interface Definition Language – язык описания интерфейсов).

    2. Брокер запросов к объектам (Object Request Broker– ORB), который управляет запросами к сервисам объектов. ORB размещает объекты, предоставляющие сервисы, подготавливает их к получению запросов, передает запрос к сервису и возвращает результаты объекту, сделавшему запрос.

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

    4. Совокупность общих компонентов, построенных на верхнем уровне основных сервисов. Они могут быть как вертикальными, отражающими специфику конкретной области, так и горизонтальными универсальными компонентами, используемыми во многих программных приложениях. Эти компоненты рассматриваются в главе 14.
    В модели CORBA объект инкапсулирует атрибуты и сервисы как обычный объект. Вместе с тем в объектах CORBA еще должно содержаться определение различных интерфейсов, описывающих глобальные атрибуты и операции объекта. Интерфейсы объектов CORBA определяются на стандартном универсальном языке описания интерфейсов IDL. Если один объект запрашивает сервисы, предоставляемые другими объектами, он получает доступ к этим сервисам через IDL-интерфейс. Объекты CORBA имеют уникальный идентификатор, называемый IOR (Interoperable Object Reference – ссылка на взаимодействующий объект). Когда один объект отправляет запросы к сервису, предоставляемому другим объектом, используется идентификатор IOR.

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

    На рис. 11.12 показано, как объекты ol и о2 взаимодействуют посредством брокера запросов к объектам. Вызывающий объект (ol) связан с заглушкой (stub) IDL, которая определяет интерфейс объекта, предоставляющего сервис. Конструктор объекта ol при запросе к сервису внедряет вызовы в заглушку своей реализации объекта. Язык IDL является расширением C++, поэтому, если вы программируете на языках C++, С или Java, получить доступ к заглушке совсем просто. Перевод описания интерфейса объекта на IDL также возможен и для других языков, например Ada или COBOL. Но в этих случаях необходима соответствующая инструментальная поддержка.

    Рис. 11.12. Взаимодействие объектов посредством брокера запросов к объектам
    Объект, предоставляющий сервис, связан с остовом (skeleton) IDL, который связывает интерфейс с реализацией сервисов. Иными словами, когда сервис вызывается через интерфейс, остов IDL транслирует вызов к сервису независимо от того, какой язык использовался в реализации. После завершения метода или процедуры остов транслирует результаты в язык IDL, так что они становятся доступными вызывающему объекту. Если объект одновременно предоставляет сервисы другим объектам или использует сервисы, которые предоставлены еще где-то, ему требуются и остов IDL, и заглушка IDL. Последняя необходима всем используемым объектам.

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

    Такая ситуация проиллюстрирована на рис. 11.13. В данном примере, если объект ol или о2 отправляет запросы к сервисам, предоставляемым объектами о3 или о4, то необходимо взаимодействие связанных с этими объектами брокеров. Стандарты CORBA поддерживают взаимодействие "брокер-брокер", которое обеспечивает брокерам доступ к описаниям интерфейсов IDL, и предлагают разработанный группой OMG стандарт обобщенного протокола взаимодействия брокеров GIOP (Generic Inter-ORB Protocol). Данный протокол определяет стандартные сообщения, которыми могут обмениваться брокеры при выполнении вызовов удаленного объекта и передаче информации. В сочетании с протоколом Internet низкого уровня TCP/IP этот протокол позволяет брокерам взаимодействовать через Internet.

    Первые варианты CORBA были разработаны еще в 1980-х годах. Ранние версии CORBA просто были связаны с поддержкой распределенных объектов. Однако со временем стандарты развивались, становились более расширенными. Подобно механизмам взаимодействия распределенных объектов, стандарты CORBA сейчас определяют некоторые стандартные сервисы, которые можно использовать для поддержки объектно-ориентированных приложений.


    Рис. 11.13. Взаимодействие между брокерами запросов к объектам
    Сервисы CORBA являются средствами, которые необходимы во многих распределенных системах. Эти стандарты определяют примерно 15 общих служб (сервисов). Вот некоторые из них.
    1. Служба имен, которая позволяет объектам находить другие объекты в сети и ссылаться на них. Служба имен является сервисом каталогов, который присваивает имена объектам. При необходимости объекты через эту службу могут находить идентификаторы IOR других объектов.

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

    3. Служба транзакций, которая поддерживает элементарные транзакции и откат назад в случае ошибок или сбоев. Эта служба является отказоустойчивым средством (см. главу 18), обеспечивающим восстановление в случае ошибок во время операции обновления. Если действия по обновлению объекта приведут к ошибкам или сбою системы, данный объект всегда можно вернуть назад к тому состоянию, которое было перед началом обновления.
    Считается, что стандарты CORBA должны содержать определения интерфейсов для широкого диапазона компонентов, которые могут использоваться при построении распределенных приложений. Эти компоненты могут быть вертикальными или горизонтальными. Вертикальные компоненты разрабатываются специально для конкретных приложений. Как уже отмечалось, разработкой определений этих компонентов занято множество специалистов из различных сфер деятельности. Горизонтальные компоненты универсальны, например компоненты пользовательского интерфейса.

    Во время написания этой книги спецификации компонентов были уже разработаны, но еще не согласованы. С моей точки зрения, вероятно, именно здесь наиболее слабое место стандартов CORBA, и, возможно, потребуется несколько лет, чтобы достичь того, что в наличии будут и спецификации, и реализации компонентов.
    КЛЮЧЕВЫЕ ПОНЯТИЯ
    Все большие системы в той или иной степени являются распределенными, в которых программные компоненты выполняются на интегрированной в сеть группе процессоров.

    Распределенным системам присущи следующие черты: использование ресурсов, открытость, параллельность, масштабируемость, устойчивость к ошибкам и прозрачность.

    Системы клиент/сервер являются распределенными. Такие системы моделируются как набор сервисов, предоставляемых сервером клиентским процессам.

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

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

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

    Стандарты CORBA представляют собой набор стандартов для промежуточного ПО, поддерживающего архитектуру распределенных объектов. К ним относятся определения модели объектов, брокера запросов к объектам и общих сервисов. В настоящее время существует несколько реализаций стандартов CORBA.
    Упражнения
    11.1. Объясните, почему распределенные системы всегда более масштабируемы, чем централизованные. Какой вероятный предел масштабируемости программных систем?

    11.2. В чем основное отличие между моделями толстого и тонкого клиента в разработке систем клиент/сервер? Объясните, почему использование Java как языка реализации сглаживает различия между этими моделями?

    11.3. На основе модели приложения, изображенной на рис. 11.4, рассмотрите возможные проблемы, которые могут возникнуть при преобразовании системы 1980-х годов, реализованной на мейнфрейме и предназначенной для работы в сфере здравоохранения, в систему архитектуры клиент/сервер.

    11.4. Распределенные системы, базирующиеся на модели клиент/сервер, разрабатывались с 1980-х годов, но только недавно такие системы, основанные на распределенных объектах, были реализованы. Приведите три причины, почему так получилось.

    11.5. Объясните, почему использование распределенных объектов совместно с брокером запросов к объектам упрощает реализацию масштабируемых систем клиент/сервер. Проиллюстрируйте свой ответ примером.

    11.6. Каким образом используется язык IDL для поддержки взаимодействия между объектами, реализованными на разных языках программирования? Объясните, почему такой подход может вызвать проблемы, связанные с производительностью, если между языками, которые используются при реализации объектов, имеются радикальные различия.

    11.7. Какие базовые средства должен предоставлять брокер запросов к объектам?

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

    • Перевод

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

    До моей работы в Uber у меня не было опыта работы с распределёнными системами. Я получил традиционное образование в Computer Science, после чего с десяток лет занимался full-stack разработкой. Поэтому, пусть я и мог рисовать различные диаграммы и рассуждать о компромиссах (tradeoffs ) в системах, к тому моменту я недостаточно хорошо понимал и воспринимал концепции распределённости - такие, например, как согласованность (consistency ), доступность (availability ) или идемпотентность (idempotency ).

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

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

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

    SLA

    В больших системах, которые обрабатывают миллионы событий в день, некоторые вещи просто по определению обязаны пойти не по плану. Вот почему прежде, чем погружаться в планирование системы, нужно сделать самый важный шаг - принять решение о том, что для нас означает «здоровая» система. Степень «здоровья» должна быть чем-то таким, что на самом деле можно измерить. Общепринятым способом измерения «здоровья» системы являются SLA (service level agreements ). Вот некоторые из самых распространённых видов SLA, с которыми мне доводилось сталкиваться на практике:
    • Доступность (Availability) : процент времени, который сервис является работоспособным. Пусть существует искушение достичь 100% доступности, достижение этого результата может оказаться по-настоящему сложным занятием, да ещё вдобавок и весьма дорогостоящим. Даже крупные и критичные системы вроде сети карт VISA, Gmail или интернет-провайдеров не имеют 100% доступности - за годы они накопят секунды, минуты или часы, проведённые в даунтайме. Для многих систем, доступность в четыре девятки (99.99%, или примерно 50 минут даунтайма в год) считается высокой доступностью. Для того, чтобы добраться до этого уровня, придётся изрядно попотеть.
    • Точность (Accuracy) : является ли допустимой потеря данных или их неточность? Если да, то какой процент является приемлимым? Для системы платежей, над которой я работал, этот показатель должен был составлять 100%, поскольку данные терять было нельзя.
    • Пропускная способность/мощность (Capacity) : какую нагрузку должна выдерживать система? Этот показатель обычно выражается в запросах в секунду.
    • Задержка (Latency) : за какое время система должна отвечать? За какое время должны быть обслужены 95% и 99% запросов? В подобных системах обычно многие из запросов являются «шумом», поэтому задержки p95 и p99 находят более практическое применение в реальном мире.
    Почему SLA нужны при создании крупной системы платежей? Мы создаём новую систему, заменяющую существующую. Чтобы убедиться в том, что мы всё делаем правильно, и что наша новая система будет «лучше», чем её предшественница, мы использовали SLA, чтобы определить наши ожидания от неё. Доступность была одним из самых важных требований. Как только мы определили цель, нам было необходимо разобраться с компромиссами в архитектуре, чтобы достичь этих показателей.

    Горизонтальное и вертикальное масштабирование

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

    Горизонтальное масштабирование заключается в добавлении большего количества машин (или узлов) в систему для увеличения пропускной способности (capacity ). Горизонтальное масштабирование - это самый популярный способ масштабирования распределённых систем.

    Вертикальное масштабирование - это по сути «купить машину побольше/посильнее» - (виртуальная) машина с большим числом ядер, лучшей вычислительной мощностью и большей памятью. В случае с рапределёнными системами, вертикальное масштабирование обычно менее популярно, поскольку оно может быть более дорогостоящим, чем масштабирование горизонтальное. Однако, некоторые известные большие сайты, вроде Stack Overflow, успешно масштабировались вертикально для соответствия нагрузке.

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

    Согласованность (consistency)

    Доступность любой из систем важна. Распределённые системы часто строятся из машин, чья доступность по отдельности ниже, чем доступность всей системы. Пусть наша цель построить систему с доступностью в 99.999% (даунтайм составляет примерно 5 минут/год). Мы используем машины/ноды, которые в среднем имеют доступность в 99.9% (они находятся в даунтайме примерно 8 часов/год). Прямым путём достижения нужного нам показателя доступности является добавление ещё нескольких таких машин/узлов в кластер. Даже если некоторые из узлов будут «в дауне», другие будут продолжать оставаться в строю и общая доступность системы будет выше, чем доступность её индивидуальных компонентов.

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

    Согласованность - это концепция, на осознание которой у меня ушло больше всего времени, прежде чем я понял её и оценил по достоинству. Существует несколько видов согласованности , самым широко используемым в распределённых системах является сильная согласованность (strong consistency ), слабая согласованность (weak consistency ) и согласованность в конечном счёте (eventual consistency ). Вы можете прочитать полезный практический разбор преимуществ и недостатков каждой из моделей в данной статье . Обычно, чем слабее требуемый уровень согласованности, тем быстрее может работать система - но тем вероятнее, что она вернет не самый последний набор данных.

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

    Хорошо иллюстрирует это вывод списка недавних транзакций: они могут быть реализованы при помощи согласованности в конечном счёте (eventual consistency ) - то есть, последняя транзакция может появиться в некоторых частях системы лишь некоторое время спустя, но благодаря этому запрос списка вернет результат с меньшей задержкой или потребует меньше ресурсов для выполнения.

    Долговечность данных (data durability)

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

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

    Почему долговечность данных имеет значение при построении платёжной системы? Если данные являются критическими (например, это платежи), то мы не можем позволить себе терять их во многих из частей нашей системы. Распределённые хранилища данных, которые мы построили, должны были поддерживать долговечность данных на уровне кластера - так что даже если инстансы будут «падать», завершенные транзакции будут сохраняться. В наши дни, большинство распределённых сервисов хранения данных - вроде Cassandra, MongoDB, HDFS или Dynamodb - все поддерживают долговечность на различных уровнях и все могут быть сконфигурированы для предоставления долговечности уровня кластера.

    Сохранность сообщений (message persistence) и долговечность (durability)

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

    В случае распределенных систем, обмен сообщениями (messaging ) обычно выполняется при помощи некоторого распределенного сервиса сообщений - RabbitMQ, Kafka или других. Эти брокеры сообщений могут поддерживать (или настроены так, что станут поддерживать) различные уровни надежности доставки сообщений.

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


    Почему сохранность и долговечность сообщений имеют значение при построении крупных платёжных систем? У нас были сообщения, которые мы не могли позволить себе потерять - например, сообщение о том, что человек инициировал платёж по оплате поездки. Это означало, что система обмена сообщениями, которую нам предстояло использовать, должна была работать без потерь: каждое сообщение должно было быть единожды доставлено. Однако, создание системы которая доставляет каждое сообщение ровно один раз нежели хотя бы один раз - это задачи, значительно различающиеся по своей трудности. Мы решили реализовать систему обмена сообщениями, которая доставляет хотя бы единожды, и выбрали шину сообщений (messaging bus ), поверх которой мы решили её построить (мы остановили свой выбор на Kafka, создав кластер без потерь, который требовался в нашем случае).

    Идемпотентность

    В случае с распределёнными системами, может пойти не так всё, что угодно - соединения могут отваливаться посередине или запросы могут выпадать по тайм-ауту. Клиенты будут часто повторять эти запросы. Идемпотентная система гарантирует, что чтобы ни произошло, и сколько бы раз конкретный запрос ни выполнялся, действительное выполнение этого запроса происходишь всего один раз. Хороший пример - это осуществление платежа. Если клиент создает запрос на оплату, запрос успешен, но если клиент попадает в тайм-аут, то клиент может повторить тот же самый запрос. В случае с идемпотентной системой, с человека, производящего оплату, не будут дважды списаны деньги; а вот для не-идемпонетной системы это вполне возможное являение.

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

    Существует множество способов достижения идемпотентности, и каждый конкретный выбор будет зависеть от ограничений системы и типа производимой операции. Проектирование идемпотентных подходов это достойный вызов для разработчика - достаточно взглянуть на посты Бена Надела, в которых он рассказывает о различных стратегиях, которые он использовал , которые включают в себя и распределённые блокировки, и ограничения (constraints ) базы данных. Когда вы проектируете распределённую систему, идемпотентность может легко оказаться одной из частей, которую вы упустили из своего внимания. В нашей практике мы сталкивались со случаями, в которых моя команда «погорела» на том, что не убедилась в наличии корректной идемпотентности для некоторых ключевых операций.

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

    Шардинг и кворум

    Распределённые системы часто должны хранить гораздо больше данных, чем может позволить себе один отдельный узел. Так как же нам сохранить набор данных на нужном количестве машин? Самой популярной техникой для этого является шардинг . Данные горизонтально партиционируются при помощи некоего хеша, присвоенного партиции. Пусть многие распределённые базы данных сегодня реализуют шардинг у себя «под капотом», он сам по себе является интересной темой, которую стоит изучить - особенно решардинг . У Foursquare в 2010 году был 17-часовой даунтайм из-за попадания на краевой случай шардинга, после чего компания поделилась , проливающим свет на корень проблемы.

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

    Почему кворум и шардинг имеют смысл при построении крупной платёжной системы в Uber? Обе эти концепции являются простыми и используются практически повсеместно. Я познакомился с ними тогда, когда мы настраивали репликацию в Cassandra. Cassandra (и другие распределённые системы) использует кворум и местный кворум (local quorum ) для того, чтобы обеспечить согласованность между кластерами.

    Модель акторов

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

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

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

    Схематически такую архитектуру можно представить, как показано на рис. 5.6.

    Рис. 5.6. Архитектура распределенных систем

    Более 95 % данных, используемых в управлении предприятием, могут быть размещены на одном персональном компьютере, обеспечив возможность его независимой работы. Поток исправлений и дополнений, создаваемый на этом компьютере, ничтожен по сравнению с объемом данных, используемых при этом. Поэтому если хранить непрерывно используемые данные на самих компьютерах, и организовать обмен между ними исправлениями и дополнениями к хранящимся данным, то суммарный передаваемый трафик резко снизится. Это позволяет понизить требования к каналам связи между компьютерами и чаще использовать асинхронную связь, и благодаря этому создавать надежно функционирующие распределенные информационные системы, использующие для связи отдельных элементов неустойчивую связь типа Интернета, мобильную связь, коммерческие спутниковые каналы. А минимизация трафика между элементами сделает вполне доступной стоимость эксплуатации такой связи. Конечно, реализация такой системы не элементарна, и требует решения ряда проблем, одна из которых своевременная синхронизация данных.

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

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

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

    Распределенные системы с репликацией

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

    Рис. 5.7. Архитектура распределенных систем с репликацией

    Распределенные системы с элементами удаленного исполнения

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

      использование данных из сущностей, которые хранятся на удаленном сервере (узле);

      использование данных из сущностей, хранящихся на разных серверах (узлах) частично;

      использование обособленного функционала, на выделенном сервере (узле).

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

    Рис. 5.8. Архитектура распределенных систем с удаленным исполнением