You are on page 1of 53

ТЕМА 3.

РОЗПОДІЛЕНІ СИСТЕМИ УПРАВЛІННЯ ПРОЦЕСАМИ

План
3.1. Поняття процесу. Визначення та структура
3.2. Потоки виконання. Визначення та структура
3.3. Стан процесів та потоків виконання
3.4. Реалізація потоків виконання
3.4.1. Потоки виконання в нерозподілених системах
3.4.2. Потоки виконання в розподілених системах
3.5. Особливості побудови розподіленої системи управління процесами на
основі моделі «клієнт-сервер»
3.6. Перенесення коду
3.6.1. Підходи до перенесення коду
3.6.2. Моделі перенесення коду
3.6.3. Перенесення і локальні ресурси
3.6.4. Перенесення коду в гетерогенних системах
3.6.5. Огляд перенесення коду в D'Agent
3.7. Програмні агенти
3.7.1. Програмні агенти в розподілених системах
3.7.2. Технологія агентів
3.7.3. Мови взаємодії агентів

3.1. Поняття процесу. Визначення та структура


Комп’ютерна програма являє собою пасивну сукупність інструкцій, в
той час як процес – це безпосереднє виконання цих інструкцій.
Для виконання програм операційна система створює декілька
віртуальних процесорів, окремо для кожної програми. Аби відстежувати ці
віртуальні процесори, операційна система підтримує таблицю процесів
(process table), яка містить записи для збереження значень регістрів
процесора, карт пам'яті, відкритих файлів, облікових записів користувачів,
привілеях і тому подібне. Процес (process) часто визначають як виконувану
програму, тобто програму, яка в даний час виконується на одному з
віртуальних процесорів операційної системи. Слід зазначити, що операційна
система приділяє величезну увагу гарантіям того, аби ці незалежні процеси
спеціально або ненавмисно не порушили правильну роботу інших процесів.
Іншими словами, той факт, що ряд процесів спільно використовують один і
той же процесор та інші апаратні ресурси, є прозорим. Зазвичай для того,
щоб так само відділяти процеси один від одного, операційній системі
потрібна апаратна підтримка.
Прозорість паралельної роботи обходиться досить дорого. Так,
наприклад, кожного разу при створенні процесу, операційна система повинна
створювати абсолютно незалежний адресний простір. Виділення пам'яті
вимагає ініціалізації сегменту пам'яті, наприклад, шляхом обнуління
сегменту даних, копіювання відповідної програми в сегмент коду і
розміщення її в стек тимчасових даних. Перемикання процесора між двома
процесами – також досить дорога операція. Окрім збереження контексту
процесора (у який входять значення регістрів, лічильник програми, вказівник
на стек і т. п.) операційна система повинна також змінити регістри блоку
управління пам'яттю (Memory Management Unit, MMU) і оголосити
некоректним вміст кеша трансляції адрес, наприклад асоціативного буфера
сторінок (Translation Lookaside Buffer, TLB). Крім того, якщо операційна
система підтримує більше процесів, ніж може одночасно поміститися в
оперативній пам'яті, перед дійсним перемиканням з одного процесу на іншій
може виникнути потреба підкачки (swapping) процесів між оперативною
пам'яттю і диском.
Процес складається з трьох сегментів: сегменту коду, сегменту ресурсів
і сегменту виконання (рис. 3.1).
Сегмент коду – це частина, що містить набір інструкцій, які
виконуються в ході виконання програми.
Сегмент ресурсів містить посилання на зовнішні ресурси, необхідні
процесу, такі як файли, принтери, пристрої, інші процеси і тому подібне.
Сегмент виконання використовується для зберігання поточного стану
процесу, включаючи закриті дані, стек і лічильник програми.

Сегмент виконання
(поточний стан, стек,
лічильник)

Сегмент ресурсів
(посилання на файли,
пристрої, інші процеси)

Сегмент коду (набір


інструкцій, що
виконуються в ході
програми)

Рис. 3.1. Структура процесу

3.2. Потоки виконання. Визначення та структура


Незважаючи на те, що процеси є будівельними блоками розподілених
систем, практика показує, що надмірне дроблення на процеси негативно
впливає на продуктивність системи. Натомість, дроблення у вигляді
декількох потоків виконання (threads) в одному процесі значно спрощує
побудову розподілених програмних систем і дозволяє добитися кращої
продуктивності. Далі буде розглянуто роль потоків виконання в розподілених
системах.
Будь-який потік складається з двох компонентів (рис. 3.2):
- об'єкту ядра, через який операційна система управляє потоком. Там же
зберігається статистична інформація про потік (додаткові потоки
створюються також ядром);
- стека потоку, який містить параметри всіх функцій і локальні змінні,
необхідні потоку для виконання коду.
Процес 1 Процес 1 Процес 1
Процес

Потік Потік

Ядро Ядро

Рис. 3.2. Структура потоку виконання


Головна відмінність процесів від потоків, полягає в тому, що процеси
ізольовані один від одного, використовують різні адресні простори, а потоки,
можуть використовувати один і той же простір (усередині процесу) при
цьому, виконуючи дії не заважаючи один одному.
Потік виконання дуже схожий на процес, в тому сенсі, що він також
може розглядатися як програма, що виконується на віртуальному
процесорі. Проте на відміну від процесу не слід намагатися досягти високої
міри прозорості паралельного виконання потоків, оскільки це призводить до
падіння продуктивності. Проте система потоків виконання зазвичай
забезпечує лише той мінімум інформації, який дозволяє спільно
використовувати процесор для різних потоків виконання. Зокрема, контекст
потоку виконання (thread context) іноді містить просто контекст процесора і
деяку іншу інформацію, необхідну для управління потоком виконання.
Інформація, що не є абсолютно необхідною для управління
багаточисельними потоками, зазвичай ігнорується. З цієї причини завдання
захисту даних в потоках виконання одного процесу від несанкціонованого
доступу покладається на розробників прикладної програми.
В подібному підході є два аспекти. По-перше, висока продуктивність
багатопотокових програмних засобів досяжна з набагато меншими
зусиллями, ніж в разі їх однопоточного аналога. Насправді багатопотокові
системи зазвичай дають виграш в продуктивності. По-друге, оскільки потоки
виконання одного процесу не захищаються автоматично один від одного,
розробка багатопотокових програмних засобів вимагає додаткових зусиль.

3.3. Стан процесів та потоків виконання


У багатозадачній (багатопроцесорній) системі процес може знаходитися
в одному з трьох основних станів:
- виконання - активний стан процесу, під час якого процес володіє всіма
необхідними ресурсами і безпосередньо виконується процесором;
- очікування - пасивний стан процесу, процес заблокований, не може
виконуватися через свої внутрішні причини; він чекає здійснення
деякої події, наприклад, завершення операції вводу-виводу, одержання
повідомлення від іншого процесу, звільнення якого-небудь
необхідного йому ресурсу;
- готовність - також пасивний стан процесу, але в цьому випадку процес
заблокований у зв'язку з зовнішніми по відношенню до нього
обставинами: процес має всі необхідні для нього ресурси, він готовий
виконуватися, однак процесор зайнятий виконанням іншого процесу.
У ході життєвого циклу кожен процес переходить з одного стану в
інший відповідно до алгоритму планування процесів, реалізованим у даній
операційній системі. Типовий граф станів процесу показано на рис.3.3.

Виконання

Очікування
Готовність

Рис. 3.3. Типовий граф станів процесів


У стані виконання у однопроцесорній системі може знаходитися тільки
один процес, а в кожному зі станів очікування і готовності - кілька процесів,
які утворюють відповідні черги процесів в стані готовності і очікування.
Життєвий цикл процесу починається зі стану готовність, коли процес
готовий до виконання і чекає своєї черги. При активізації процес переходить
у стан виконання і знаходиться в ньому до тих пір, поки або він сам звільнить
процесор, перейшовши в стан очікування якої-небудь події, або буде
насильно "витиснутий" із процесора, наприклад, внаслідок вичерпання
відведеного даному процесу кванта процесорного часу . В останньому
випадку процес повертається в стан готовність. У цей же стан процес
переходить зі стану очікування, після того, як очікувана подія відбудеться.

3.4. Реалізація потоків виконання


Існує два підходи щодо реалізації потоків виконання: статичний і
динамічний.
При статичному підході питання щодо кількості потоків виконання
вирішується вже на стадії написання програми або на стадії
компіляції; кожному потоку виконання призначається фіксований стек. Цей
підхід простий, але негнучкий.
Більш загальним є динамічний підхід, який дозволяє створювати і
видаляти потоки виконання оперативно по ходу виконання. Системний
виклик для створення потоку виконання зазвичай міститься в потоці головної
програми у вигляді покажчика на процедуру із зазначенням розміру стека, а
також інших параметрів, наприклад, диспетчерського пріоритету. Виклик
зазвичай повертає ідентифікатор потоку виконання, який можна
використовувати в подальших викликах, пов'язаних з цим потоком. У цій
моделі процес починається з одного потоку, але може створювати їх ще, коли
необхідно.
Завершуватися потоки можуть одним із двох способів: за власною
ініціативою, коли завершується робота потоку, та ззовні. У багатьох
випадках, наприклад, при конвеєрній моделі, потоки виконання створюються
відразу ж після старту процесу і ніколи не знищуються.

3.4.1. Потоки виконання в нерозподілених системах


Найбільш важлива перевага випливає з того факту, що процеси з одним
потоком виконання цілком блокуються при будь-якому блокуючому
системному викликі.
Приклад.
Як ілюстрацію розглянемо будь-яке програмне забезпечення, наприклад, електронні
таблиці. Уявимо, що користувач хоче постійно змінювати значення комірки в
інтерактивному режимі. Важливою властивістю електронних таблиць є підтримка
функціональних залежностей між різними елементами таблиці або різними таблицями.
Таким чином, кожного разу при модифікації комірки, всі комірки, пов'язані з нею,
автоматично оновлюються. Після того, як користувач змінить значення однієї з комірок,
внесена ним зміна викличе значний об'єм обчислень. Якщо працювати лише з одним
потоком виконання, під час очікування введення даних ці обчислення виявляться
неможливими. Так само нелегко буде організувати введення даних під час виконання
процесу обчислень. Найпростішим рішенням було б створити як мінімум два потоки
виконання – один для підтримки роботи з користувачем, інший для оновлення таблиць.

Багатопотокова структура часто використовується при побудові великих


програмних комплексів. Подібні програмні комплекси часто розробляються у
вигляді наборів спільно працюючих програм, кожна з яких виконується
окремим процесом. Цей підхід типовий для середовища UNIX. Кооперація
між програмами реалізується у вигляді міжпроцессної взаємодії (через
механізми Interproccessing Cooperation – IPC). Для UNIX-систем ці механізми
зазвичай включають канали (поіменовані), черги повідомлень і спільно
використовувані сегменти пам'яті. Основною оборотною стороною
механізмів IPC є необхідність інтенсивного перемикання контекстів,
продемонстрована трьома точками на рис.3.4.
Оскільки IPC вимагає втручання в ядро, процес зазвичай вимушений
спочатку перемкнутися з призначеного для користувача режиму в режим
ядра (точка S1). Це вимагає зміни карти пам'яті в блоці MMU, а також
скидання буфера TLB. У ядрі відбувається перемикання контексту процесу
(точка S2), після чого другий процес може бути активізований черговим
перемиканням з режиму ядра в призначений для користувача режим (точка
S3). Останнє перемикання знов потрубує зміни карти пам'яті в блоці MMU і
скидання буфера TLB.

Процес А Процес Б

S1 S3

Операційна система

S2
S2

Рис. 3.4. Перемикання контекстів в результаті виклику IPC


У розробників є особлива причина використовувати потоки виконання:
багато програмних комплексів просто легко розробляти, структурувавши їх у
вигляді набору взаємозв'язаних потоків виконання.
Приклад
Розглянемо прикладну програму, що вимагає виконання декількох (більш менш
незалежних) завдань. У випадку текстового редактора в окремі потоки можна виділити
обробку введення користувача, перевірку орфографії і граматики, оформлення
зовнішнього вигляду документа, створення індексу і тому подібне.

3.4.2. Потоки виконання в розподілених системах


Важливою властивістю потоків виконання є зручна реалізація блокуючих
системних викликів, які відбуваються без блокування всього процесу на час
виконання потоку. Ця властивість потоків виконання особливо приваблива в
розподілених системах, оскільки вона значно спрощує представлення
взаємодії як одночасну підтримку значної кількості логічних з'єднань.

Багатопотокові клієнти
Щоб добитися високої міри прозорості розподілу, розподілені системи,
які працюють в глобальних мережах, можуть потребувати маскування
великих затримок повідомлень, курсуючих між процесами. Цикл затримки в
глобальних мережах легко може досягати порядка сотень мілісекунд, а часом
і секунд.
Традиційний спосіб приховати затримки зв'язку – ініціювавши
взаємодію, відразу розпочати виконання іншої задачі.
Приклад.
Типовим прикладом вживання цієї методики є web-браузери. У багатьох випадках
web-документ, що міститься у файлі формату HTML, містить, окрім тексту, набір
зображень, значків і тому подібне Для здобуття елементів web-документу браузер
відкриває з'єднання TCP/IP, читає дані, що поступають, і перетворить їх в компоненти
візуального представлення. Установка з'єднання, так само як і читання даних, є
блокуючими операціями. При роботі з повільними комунікаціями відчуваються
незручності, пов'язані з тим, що час, потрібний для завершення кожній з операцій, може
бути досить тривалим. Web-браузер зазвичай спочатку отримує сторінку HTML-кода, а
потім показує її. Для того, щоб по можливості приховати затримки зв'язку, деякі браузери
починають показувати дані у міру їх отримання. Коли текст з механізмами прокрутки стає
доступним користувачеві, браузер продовжує отримання останніх файлів, необхідних для
правильного відображення сторінки, таких як картинки. Таким чином, для того, щоб
побачити сторінку, користувач не повинен чекати отримання всіх її компонентів (рис. 3.5).

Рис. 3.5. Поетапне завантаження елементів сторінки Web-браузером


В результаті, web-браузер виконує декілька завдань одночасно. Зрозуміло, що
розробка браузера у вигляді багатопотокового клієнта дуже спрощує роботу з ним. Як
тільки отримується основний файл HTML, активізуються окремі потоки виконання, які
відповідають за дозавантаження інших частин сторінки. Кожен з потоків виконання
створює окреме з'єднання з сервером і отримує від нього дані. Встановлення з'єднання і
читання даних з сервера може бути запрограмоване з використанням стандартних
(блокуючих) системних викликів. Це передбачає, що блокуючі виклики не в змозі
припинити основний процес. Код кожного з потоків виконання однаковий і в основному
нескладний. В результаті користувач, хоча і помічає затримку в показі картинок сповна
може переглядати документ.

Використання багатопотокових web-браузерів, які в змозі відкривати


декілька з'єднань, дає також і інший виграш. У попередньому прикладі були
створені декілька з'єднань з одним і тим же сервером. Якщо цей сервер
сильно завантажений або просто повільний, не можливо отримати значне
підвищення продуктивності в порівнянні з послідовним (одного за другим)
завантаженням файлів.
Проте у багатьох випадках web-сервери можуть бути репліковані на
декілька машин, при цьому кожен з серверів міститиме однаковий набір web-
документів. Репліковані сервери знаходяться в одному і тому ж місці і мають
одне і те ж ім'я. Під час активації запиту на web-сторінці цей запит
передається одному з серверів, зазвичай з використанням алгоритму
циклічного обслуговування або іншого алгоритму вирівнювання
навантаження.
За наявності багатопотокового клієнта з'єднання можуть бути
встановлені з різними репліками, що приведе до паралельної передачі даних,
а це ефективно сприятиме тому, що web-документ буде показаний повністю
значно швидше, ніж в разі нереплікованого серверу. Цей підхід спрацьовує,
лише якщо клієнт в змозі обробити істинно паралельні потоки вхідних даних.
В цьому випадку потоки виконання ідеально підходять для обробки потоків
даних.
Багатопотокові сервери
Хоча багатопотокові клієнти володіють серйозними перевагами, основні
переваги багатопоточності в розподілених системах забезпечуються з боку
сервера. Практика показує, що багатопоточність не лише істотно спрощує
код сервера, але й робить набагато простішою розробку тих серверів, в яких
для досягнення високої продуктивності потрібне паралельне виконання
декількох програмних комплексів. У число таких входять і мультипроцесорні
системи. Навіть зараз, коли мультипроцесорні комп'ютери активно
випускаються у вигляді робочих станцій загального призначення,
використання для паралельної обробки багатопоточності не втратило своєї
актуальності.
Приклад.
Щоб відчути переваги потоків виконання для написання кодів серверів, розглянемо
організацію файлового сервера, який періодично виявляється блокованим через
очікування доступу до диска. Файловий сервер зазвичай чекає вхідного запиту на операції
з файлами, після чого обробляє отриманий запит і повертає відповідь. Одна з можливих і
особливо популярних організацій показана на рис. 3.6. Тут один з потоків виконання,
диспетчер, прочитує запити на файлові операції, які надходять. Запити посилаються
клієнтами з вказівкою кінцевої точки даного сервера. Після перевірки запиту сервер
вибирає (тобто блокує) робочий потік виконання, який знаходиться в стані очікування, і
передає запит йому.

Потік – Робочий Робочий Робочий


диспетчер потік потік потік

Запит з мережі

Рис. 3.6. Багатопотоковий сервер, організований за схемою диспетчер - робочий потік

Робочий потік здійснює блокуюче читання з локальної файлової системи, що


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

Структура з диспетчером – не єдиний шлях організації багатопотокового


серверу. У моделі "команда" всі потоки виконання еквівалентні, кожен
отримує і обробляє свої власні запити (рис. 3.7). Іноді завдання приходять, а
потрібний потік зайнятий, особливо, якщо кожен потік спеціалізується на
виконанні особливого виду робіт. У цьому випадку може створюватися черга
незавершених робіт. При такій організації потоки виконання повинні
спочатку переглядати чергу робіт.

Робочий Робочий Робочий Робочий


потік потік потік потік

Запит з мережі

Рис. 3.7. Багатопотоковий сервер, організований за схемою «команда»


Потоки виконання можуть бути також організовані у вигляді конвеєра
(рис. 3.8). У цьому випадку перший потік породжує деякі дані і передає їх
для обробки наступному потоку виконання і т.д. Незважаючи на те, що ця
організація і не підходить для файлового сервера, для інших завдань,
наприклад, задач типу "виробник-споживач", це рішення є ефективним.

Робочий Робочий Робочий Робочий


потік потік потік потік

Запит з мережі

Рис. 3.8. Багатопотоковий сервер, організований за схемою «конвейер»


Слід розглянути, як файловий сервер міг би вести запис у відсутності
потоків виконання. Одна з можливостей – діяти так, ніби файловий сервер
працює з єдиним потоком виконання. Основний цикл файлового сервера
отримує запит, перевіряє його і передає на виконання раніше, ніж отримає
наступний. Поки сервер чекає закінчення дискових операцій, він не обробляє
інші запити. Таким чином, запити інших клієнтів не обробляються. Крім
того, якщо файловий сервер працює на виділеній машині, процесор під час
дискових операцій просто нічим не зайнятий. В результаті обробляється
значно менша кількість запитів в секунду, ніж можливо. Виходячи з цього,
потоки виконання забезпечують значне підвищення продуктивності, і це не
дивлячись на те, що вони запускаються на виконання по черзі.
Таким чином, спостерігаються такі можливі архітектури –
багатопотоковий і однопоточний файловий сервер. Можливо також, що
потоки виконання відсутні взагалі, але тільки у тому разі, коли падіння
продуктивності із-за використання однопоточної архітектури робить її
використання можливим. Інша можливість полягає у використанні сервера як
великого кінцевого автомата (рис. 3.9).

Запит перевіряє єдиний потік виконання, якщо він не


задовольняється за допомогою кеша, то відбувається звернення до
файлової системи

Потік виконує запис поточного стану запиту в таблицю і очікує


отримання нового повідомлення.

Якщо це відповідь від диску, з таблиці виймається необхідна


інформація, формується відповідь клієнту. Інакше починається
нова робота.

Рис. 3.9. Алгоритм роботи кінцевого автомату


Після надходження запиту його перевіряє єдиний потік виконання.
Добре, якщо він може бути задоволений шляхом звернення до кеша, інакше
відбувається звернення до дискової системи.
Проте замість блокування потік виконання записує стан поточного
запиту в таблицю і переходить до стану очікування і отримання нового
повідомлення. Нове повідомлення може бути як запитом на здійснення нової
операції, так і відповіддю на попередній запит від дискової підсистеми. Якщо
це новий запит, починається нова робота. Якщо це відповідь від диска, з
таблиці витягується відповідна інформація, відповідь формується і
передається клієнтові. Згідно цієї схеми, сервер має бути в змозі здійснювати
неблокуючі виклики send і receive.
У подібній архітектурі модель “послідовних процесів” відсутня. Стан
обчислень для кожного повідомлення, яке приймається і відправляється,
повинен повністю зберігатися і витягуватися з таблиці. В результаті потоки
виконання і їх стеки моделюються складним чином. Процес, який протікає в
кінцевому автоматі, полягає в сприйнятті подій і в залежності від їх типу
реакції на ці події.
Потоки виконання роблять можливим одночасне збереження ідеї
послідовних процесів, які здійснюють блокуючі системні виклики (як при
викликах RPC для роботи з диском), і паралельної роботи. Блокуючі системні
виклики спрощують програмування, а паралельність підвищує
продуктивність. Однопоточні сервери зберігають простоту блокуючих
системних викликів, але програють в продуктивності. Підхід,
використовуваний в кінцевих автоматах, дозволяє завдяки паралелізму
добитися високої продуктивності, але через наявність неблокуючих викликів
важко програмується. Ці підходи підсумовані в таблиці 3.1.
Таблиця 3.1
Три способи побудови сервера

Модель Характеристики

Потоки виконання Паралельність, блокуючі системні виклики

Відсутність паралелізму, блокуючі системні


Однопоточний процес
виклики

Кінцевий автомат Паралелізм, неблокуючі системні виклики

3.5. Особливості побудови розподіленої системи управління


процесами на основі моделі «клієнт-сервер»
Основне завдання більшості клієнтів – служити передавальною ланкою
між користувачем і віддаленим сервером. Підтримка інтерфейсу,
призначеного для користувача – основна функція більшості клієнтів. У
багатьох випадках інтерфейс між користувачем і віддаленим сервером
відносно простий і вбудований в апаратуру клієнта.
Приклад.
Так стільникові телефони на додаток до традиційного набору кнопок для набору
номера мають невеликий дисплей. Скільки-небудь складні речі, такі як робота з
електронною поштою, можуть вимагати комплектації справжньою клавіатурою,
електронним планшетом або пристроєм розпізнавання мови.

До програмного забезпечення клієнта входить не лише призначений для


користувача інтерфейс. У багатьох випадках на стороні клієнта виконується
також частина рівнів обробки і даних прикладної програми клієнт-сервер. На
основі вбудованого клієнтського програмного забезпечення функціонує
цілий клас спеціалізованих пристроїв, таких як автовідповідачі, лічильники
купюр, зчитувачі штрих-коду, телеприставки та ін. У подібних випадках
призначений для користувача інтерфейс є відносно невеликою частиною
клієнтського програмного забезпечення в порівнянні із засобами локальної
обробки і комунікацій.
Окрім призначеного для користувача інтерфейсу і іншого пов'язаного з
програмним забезпеченням, клієнтське програмне забезпечення містить
компоненти, які забезпечують прозорість розподілу. В ідеалі клієнт не має
бути обізнаний про свою взаємодію з віддаленими процесами. Для серверів
же, навпаки, інформація про розподілену роботу зазвичай не приховується в
цілях підвищення продуктивності і коректної роботи. Очевидно, що
реплікуємі сервери повинні час від часу зв'язуватися один з одним, аби
забезпечити певний порядок виконання операцій в кожній з реплік.
Прозорість доступу зазвичай забезпечується шляхом генерації (у
вигляді заглушки клієнта) з визначення інтерфейсу того, що повинен робити
сервер. Заглушка надає такий же інтерфейс, як і сервер, приховуючи при
цьому різницю архітектури і реальну взаємодію.
Існують різні способи реалізації прозорості розміщення, перенесення і
переміщення. Для реалізації прозорості важливо використовувати певну
систему іменування. У багатьох випадках важлива кооперація з програмним
забезпеченням клієнтської сторони.
Приклад.
Якщо клієнт вже прив'язаний до сервера, він може безпосередньо сповіщатися про
зміну місцезнаходження сервера. В цьому випадку проміжний рівень клієнта може
приховувати дійсне місце розташування сервера від користувача і при необхідності
непомітно повторити прив'язку до цього сервера. Найбільше, що може бути помічено у
програмі клієнта, – це тимчасове падіння продуктивності.

Аналогічним чином більшість розподілених систем реалізують


прозорість реплікації на стороні клієнта. Уявимо собі, наприклад,
розподілену систему з віддаленими об'єктами. Реплікацію віддаленого
об'єкту можна здійснити шляхом розсилки всім реплікам запиту, як показано
на рис. 3.10. Заступник клієнта повинен зібрати всі відповіді і передати
прикладній програмі клієнта одне повернене значення.
І, нарешті, розглянемо прозорість до збоїв. Маскування збоїв у взаємодії
з серверами зазвичай виконується за допомогою клієнтського програмного
забезпечення проміжного рівня. Так, клієнтське програмне забезпечення
проміжного рівня можна конфігурувати так, щоб воно багато разів
намагалося зв'язатися з сервером або вибирало після декількох спроб інший
сервер. Можлива також ситуація, коли програмне забезпечення клієнта, у
випадку якщо web-браузер не в змозі зв'язатися з сервером, повертало б дані,
збережені в кеші під час попереднього сеансу зв'язку.

Заступник
розмножує запити Репліка 1

Заступник Репліка 2

Репліка 3
Всі репліки
отримують однакове
звернення

Рис. 3.10. Можливий підхід до прозорої реплікації віддалених об'єктів з


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

Сервер у процесному розумінні – це процес, який реалізовує деяку


службу, потрібну групі клієнтів. Всі сервери працюють схожим чином: вони
очікують на появу вхідного повідомлення, яке посилається клієнтом, потім
перевіряють це повідомлення на правильність, після чого очікують появи
наступного повідомлення.
Сервери можуть бути організовані різними способами. В разі
ітеративного сервера він сам обробляє запит і при необхідності повертає
клієнтові у відповідь повідомлення. Паралельний сервер не обробляє
повідомлення сам, а передає його в окремий потік виконання або інший
процес, після чого відразу ж переходить в стан очікування наступного
вхідного повідомлення.
Приклад.
Прикладом паралельного сервера є багатопотоковий сервер. У іншій реалізації
паралельного сервера на кожен запит, що прийшов, може виділятися новий процес.
Подібний підхід застосовується в багатьох UNIX-системах. Потік або процес, який
обробляє запит, відповідає за відправку відповіді клієнтові, що прислав запит.

Клієнт завжди посилає запити в кінцеву точку (endpoint), що також


іменується портом (port), тієї машини, на якій працює сервер. Кожен сервер
переглядає вказану йому кінцеву точку. Одне з рішень – глобальне
призначення кінцевих точок широко поширеним службам.

Приклад.
Сервери, які обслуговують запити до FTP в Інтернеті, завжди працюють з портом 21.
HTTP-серверам World Wide Web завжди призначається TCP-порт 80. Ці кінцеві точки
визначені організацією призначення номерів Інтернету (Internet Assigned Numbers
Authority – IANA). Маючи призначені кінцеві точки, клієнтові досить знати мережеву
адресу тієї машини, на якій запущена служба. Для цієї мети використовуються служби
іменування.

Існує багато служб, які не потребують попереднього призначення


кінцевої точки.
Приклад.
Так служба часу може використовувати кінцеву точку, що в динаміці виглядає для
неї як локальна операційна система. В цьому випадку клієнт повинен спочатку визначити
кінцеву точку.
Для визначення кінцевої точки клієнтом в процесі виконання розроблено
рішення, яке реалізовано у розподіленому середовищі Distributed Computing
Environment (DCE), – це створення спеціального демона, що запускається на
кожній машині, на якій працюють сервери. Демон відстежує поточну кінцеву
точку кожного з серверів, що реалізовуються на даній машині. Демон сам
переглядає загальнодоступні кінцеві точки. При першому контакті з демоном
клієнт запрошує кінцеву точку, після чого зв'язується з потрібним йому
сервером.
Зазвичай кінцева точка асоціюється з конкретною службою. Проте
насправді реалізація кожної служби окремим сервером була б недоцільним
витрачанням ресурсів.
Приклад
В типових UNIX-системах нерідко є багато одночасно працюючих серверів, при
цьому велика їх частина пасивно чекає запитів від клієнта. Замість ведення такої кількості
пасивних процесів часто ефективніше мати один суперсервер (superserver), який
прослуховує всі кінцеві точки, що відносяться до конкретних служб, як показано на рис.
3.11. Подібний підхід реалізує, наприклад, демон inetd в UNIX. Цей демон переглядає
стандартні порти служб Інтернету. В разі приходу запиту він розпаралелює процес і
передає запит на подальшу обробку. Після закінчення обробки дочірній процес
завершується.

Продовження
роботи

Сервер Реальний сервер

Клієнт Клієнт

Демон Суперсервер

Визначення кінцевої Запит служби


точки Реєстрація кінцевої Створення сервера
точки для служби
Таблиця кінцевих
точок

Рис. 3.11. Прив'язка клієнта до сервера з використанням демона в середовищі


ОС і суперсервера в UNIX
Приклад.
Розглянемо користувача, який вирішив завантажити на FTP-сервер великий файл.
Почавши робити це, він виявив, що вибрав не той файл і хотів би відмінити подальшу
пересилку даних. Існує декілька способів зробити це. Один з підходів, надійно
працюючий в сучасному Інтернеті (а інколи і єдино можливий), – користувач негайно
закриває клієнтське програмне забезпечення, що автоматично викликає розрив з'єднання з
сервером, потім перезапускає його і продовжує роботу. Сервер, природно, розриває старе
з'єднання, вважаючи, що клієнт перервав роботу.

Правильніший спосіб викликати переривання зв'язку – розробляти клієнт


і сервер так, щоб вони могли пересилати один одному сигнал кінця зв'язку
(out-ofband), який повинен оброблятися сервером раніше всіх інших даних,
які передаються клієентом. Одне з рішень – змусити сервер переглядати
окрему кінцеву точку, на яку клієнт відправлятиме сигнал кінця зв'язку і
одночасно (з нижчим пріоритетом), – кінцеву точку, через яку передаються
нормальні дані. Інший варіант – пересилати сигнал кінця зв'язку через те ж
з'єднання, через яке клієнт пересилав свій запит. У TCP, наприклад, можна
посилати термінові дані.
Коли термінові дані досягають сервера, він перериває свою роботу (у
UNIX системах – по сигналу), після чого може проглянути ці дані і обробити
їх.
Важилива характеристика сервера – можливість збереження інформації
про стан клієнтів на сервері. Сервер без фіксації стану (stateless sewer) не
зберігає інформацію про стан своїх клієнтів і може міняти свій власний стан,
не інформуючи про це своїх клієнтів.
Приклад.
Web-сервер - це сервер без фіксації стану. Він просто відповідає на вхідні HTTP-
запити, які можуть вимагати завантаження файлу як на сервер, так і (набагато частіше) з
сервера. Після виконання запиту web-сервер забуває про клієнта. Крім того, набір файлів,
якими управляє web-сервер (можливо, в комбінації з файловим сервером), може бути
змінений без повідомлення клієнтів про цю дію.
В протилежність цьому, сервер з фіксацією стану (stateful server)
зберігає і обробляє інформацію про своїх клієнтів.
Приклад.
Типовим прикладом такого сервера є файловий сервер, що дозволяє клієнтові
створювати локальні копії файлів, скажімо, для підвищення продуктивності операцій
оновлення. Подібний сервер підтримує таблицю, яка містить записи пар (клієнт, файл).
Така таблиця дозволяє серверу відстежувати, який клієнт з яким файлом працює і, таким
чином, завжди визначати «найсвіжішу» версію файлу. Подібний підхід підвищує
продуктивність операцій читання-запису, здійснюваних на клієнтові.

Зростання продуктивності в порівнянні з серверами без фіксації стану


часто є основною перевагою і основною причиною розробки серверів з
фіксацією стану. Проте даний приклад також ілюструє основний недолік
таких серверів. В разі збою сервера він вимушений відновлювати свою
таблицю із записами пар (клієнт, файл), інакше не буде жодної гарантії в
тому, що робота відбувається з останньою оновленою версією файлу. Як
правило, сервери з фіксацією стану потребують відновлення свого стану в
тому вигляді, в якому воно було до збою. Необхідність забезпечити
відновлення після збою сильно ускладнює програмне забезпечення. В разі
архітектури без фіксації стану взагалі немає необхідності приймати якісь
спеціальні заходи по відновленню серверів після збою. Вони просто
перезапускаються і працюють, чекаючи запитів клієнта.
При розробці сервера вибір між архітектурою з фіксацією і без фіксації
стану не відбивається на службі, яку цей сервер повинен надавати.
Так оскільки до виконання читання або запису файли в будь-якому разі
повинні відкриватися, сервер без фіксації стану повинен тим або іншим
способом відтворити відкриття файлу. Стандартне рішення полягає в тому,
аби сервер, обробляючи запит на запис у файл або читання з файлу,
відкривав потрібний файл, виконував операцію читання або запису і негайно
його закривав.
У інших випадках сервер може зберігати записи про поведінку клієнтів,
аби ефективніше обробляти їх запити. Це можна зробити лише в тому
випадку, якщо сервер зберігатиме інформацію про клієнта. Традиційне
рішення полягає в тому, аби дозволити клієнтові посилати додаткову
інформацію про його попередні сеанси роботи з сервером. Ця інформація
часто прозоро зберігається браузером клієнта у вигляді файлів cookie –
маленьких фрагментів даних, що містять інформацію про клієнта, важливу
для сервера. Файли cookie ніколи не виконуються браузером, вони просто
зберігаються.
При першому зверненні клієнта до сервера останній пересилає файл
cookie разом із запитаними web-сторінками браузеру, а браузер зберігає цей
файл cookie. Кожного разу надалі при зверненні клієнта до сервера файли
cookie пересилаються браузером на сервер разом з текстом запиту. У теорії
цей підхід працює прекрасно, реально ж файли cookie для безпечного
зберігання відсилаються браузером назад на сервер часто абсолютно скрито
від користувача.
Сервери об'єктів
Сервер об'єктів (object server) – це сервер, орієнтований на підтримку
розподілених об'єктів.
Важлива різниця між стандартним сервером об'єктів і іншими (більш
традиційними) серверами полягає в тому, що сам по собі сервер об'єктів не
надає конкретної служби. Конкретні служби реалізуються об'єктами,
розташованими на сервері. Сервер надає лише засоби звернення до
локальних об'єктів на основі запитів від віддалених клієнтів. Таким чином,
можна відносно легко змінити набір служб, просто додаючи або видаляючи
об'єкти.
Сервер об'єктів, відповідно, виступає як місце для зберігання об'єктів.
Об'єкт складається з двох частин: даних, що відображають його стан, і
коду, що створює реалізацію його методів (див. рис. 3.12).
Дані об’єкту
(відображають
його стан)

Код об’єкту
(створює реалізацію
його методів)

Рис. 3.12. Структура серверу об’єктів


Чи будуть ці частини зберігатися окремо, а також чи зможуть методи
спільно використовуватися декількома об'єктами, залежить від сервера
об'єктів. Крім того, існує різниця і в способі звернення сервера об'єктів до
його об'єктів.
Приклад.
В багатопотоковому сервері об'єктів окремий потік виконання може бути
призначений кожному об'єкту або кожному запиту на звернення до об'єкту.

Для будь-якого об'єкту, до якого відбувається звернення, сервер об'єктів


повинен знати, який код виконувати, з якими даними працювати, чи
запускати окремий потік виконання для підтримки звернення і так далі.
Простий підхід – вважати, що всі об'єкти виглядають однаково і звернення до
них може утворюватися однаково. Саме так працює середовище DCE. На
жаль, подібному підходу зазвичай не вистачає гнучкості, і він іноді має ряд
обмежень при роботі з розподіленими об'єктами.
Правильніший підхід з боку сервера – підтримувати різні правила
обробки об'єктів. Розглянемо, наприклад, нерезидентні об'єкти. Нагадаємо,
що нерезидентним називається об'єкт, що існує лише під час існування
сервера, а можливо, і ще коротший термін. Типовою реалізацією
нерезидентного об'єкту можна вважати копію файлу, що зберігається в
пам'яті, призначену лише для читання. Калькулятор (що зазвичай
запускається на високошвидкісному сервері) також може бути реалізований у
вигляді нерезидентного об'єкту. Розумно створити нерезидентний об'єкт при
першому ж запиті до нього, а знищити після того, як не залишиться
пов'язаних з цим об'єктом клієнтів.
Перевага подібного підходу полягає в тому, що нерезидентні об'єкти
використовують ресурси сервера лише до тих пір, доки в цих об'єктах є
необхідність.
Недолік полягає в тому, що звернення може запросити для виконання
певний час, оскільки об'єкт ще потрібно створити. Тому інколи
застосовується інша політика – всі нерезидентні об'єкти створюються при
ініціалізації сервера. Це виконується за рахунок виділення ресурсів на
об'єкти навіть в тому випадку, якщо жоден клієнт не стане їх
використовувати.
Схожим чином сервер міг би виділяти кожному зі своїх об'єктів окремий
сегмент пам'яті. Іншими словами, можна заборонити спільне використання
об'єктами коду і даних. Подібний підхід міг би застосовуватися в тих
випадках, коли для реалізації кожного об'єкту не потрібно відділяти код від
даних або коли об'єкти потрібно відокремити один від одного з міркувань
безпеки. У цьому останньому випадку сервер повинен буде для
гарантованого захисту кордонів сегментів надати спеціальні засоби виміру
або вимагати підтримки від базової операційної системи. При
альтернативному підході можна дозволити об'єктам спільно використовувати
хоча би код. Так, база даних, що містить об'єкти, які відносяться до одного
класу, може бути ефективно реалізована шляхом однократного завантаження
на сервер реалізації цього класу. В разі приходу запиту на звернення до
об'єкту серверу досить буде витягувати з бази даних стан об'єкту і виконати
викликаний метод.
Аналогічно існує ряд різних підходів щодо роботи з потоками
виконання. Найпростіший з них – реалізація сервера з єдиним управляючим
потоком виконання. З іншого боку, сервер може підтримувати декілька
потоків виконання – поодинці на кожен об'єкт. В разі приходу запиту із
зверненням до об'єкту сервер просто передає запит потоку виконання, який
відповідає за цей об'єкт. Якщо потік виконання у цей момент зайнятий, запит
ставиться в чергу. Перевага такого підходу – в автоматичному захисті
об'єктів від одночасного доступу: для єдиного пов'язаного з об'єктом потоку
виконання всі звернення вишиковуються по порядку. Зрозуміло, можна
також виділяти окремий потік виконання кожному запиту, але при цьому
необхідно заздалегідь захистити об'єкти від одночасного доступу. Незалежно
від того, призначається потік виконання кожному об'єкту або кожному
методу, потрібно вирішити, створювати кожен потік за запитом або
підтримувати на сервері пул потоків. Оптимального рішення «на всі випадки
життя» тут бути не може.

3.6. Перенесення коду


До цих пір в основному розглядались розподілені системи, в яких
взаємодія обмежувалася передачею даних. Проте існують ситуації, коли
передача програм, інколи навіть під час їх виконання, дозволяє спростити
розробку розподілених систем. Окремою складною проблемою є перенесення
коду в гетерогенних системах. Типовою широко розповсюдженою
реалізацією є система D'Agents для мобільних агентів.

3.6.1. Підходи до перенесення коду


Традиційно перенесення коду в розподілених системах відбувається у
формі перенесення процесів (process migration), в разі яких процес цілком
переноситься з однієї машини на іншу. Перенесення працюючого процесу на
іншу машину – дороге і складне завдання, і для її виконання має бути вагома
причина. Такою причиною завжди була продуктивність. Основна ідея
полягає в тому, що продуктивність може зрости при перенесенні процесів з
сильно завантаженої на слабо завантажену машину. Завантаження зазвичай
виражається в поняттях довжини черги до процесора або завантаження
процесора, використовуються також і інші індикатори продуктивності.
Алгоритм розподілу завантаження, на базі якого приймаються рішення,
що включає розподіл і перерозподіл завдань відповідно до наявного набору
процесорів, грає важливу роль в системах інтенсивних обчислень. Проте в
багатьох сучасних розподілених системах оптимізація обчислювальної
потужності – менш важливе завдання порівняно, наприклад, із зниженням
комунікаційного трафіку. Більш того, враховуючи гетерогенність базових
платформ і комп'ютерних мереж, підвищення продуктивності шляхом
перенесення коду іноді ґрунтується в значній мірі на якісних міркуваннях, а
не на математичних моделях.
Приклад.
Розглянемо систему клієнт-сервер, в якій сервер управляє великою базою даних.
Якщо клієнтське програмне забезпечення збирається виконувати ряд операцій з базою
даних, використовуючи великі об'єми даних, може бути краще перенести частину
клієнтського програмного забезпечення на сервер, а по мережі передавати лише
результати. Інакше мережа може бути переобтяжена даними, які передаються з сервера на
клієнт. В цьому випадку перенесення коду засноване на міркуванні про те, що зазвичай
має сенс обробляти дані поблизу від того місця, де вони знаходяться.

Схожа причина може бути використана і при перенесенні частини


сервера на комп’ютер клієнта. В багатьох інтерактивних прикладних
програмах баз даних клієнт повинен заповнювати форму, яка потім буде
перетворена в серію операцій бази даних. Обробка форми на стороні клієнта
з пересилкою на сервер лише заповненої форми не зрідка дозволяє уникнути
пересилки по мережі значної кількості невеликих повідомлень. В результаті
клієнт покаже кращу продуктивність, а сервер витратить менше часу на
обробку форми і взаємодію.
Підтримка перенесення коду може також допомогти підвищити
продуктивність на основі паралелізму, але без звичайних складнощів,
пов'язаних з паралельним програмуванням.
Приклад.
Типовим прикладом може бути пошук інформації в Web. Відносно нескладно
реалізувати пошуковий запит у вигляді невеликої мобільної програми, що переноситься з
сайту на сайт. Створивши декілька копій цієї програми і розіславши їх по різних сайтах,
можна добитися лінійного зростання швидкості пошуку в порівнянні з єдиним
екземпляром програми.

Окрім підвищення продуктивності існують і інші причини підтримки


перенесення коду. Найбільш важлива з них – це гнучкість. Традиційний
підхід до побудови розподілених програмних засобів полягає в розбитті
прикладної програми на частини з подальшим визначенням, де яка частина
виконуватиметься.
Проте, якщо код переносити з машини на машину, виникає можливість
конфігурувати розподілені системи динамічно.
Приклад.
Розглянемо сервер, який реалізовує стандартизований інтерфейс до файлової
системи. Аби надати віддаленому клієнтові доступ до файлової системи, сервер
використовує спеціальний протокол. У звичайному варіанті клієнтська реалізація
інтерфейсу з файловою системою, заснована на цьому протоколі, має бути скомпонована з
прикладною програмою клієнта. Цей підхід передбачає, що подібне програмне
забезпечення для клієнта має бути доступне вже тоді, коли створюється клієнтське
програмне забезпечення.

Взаємодія клієнта
і сервера

Клієнт Сервер

Отримання коду
Збереження клієнтом
коду

Рис. 3.13 Принцип динамічної конфігурації клієнта для зв'язку з сервером


Важлива перевага подібної моделі динамічного дозавантаження
клієнтського програмного забезпечення полягає в тому, що клієнтові для
спілкування з сервером немає необхідності мати повний комплект
заздалегідь встановлюваного програмного забезпечення. Замість цього при
необхідності програми можуть бути перенесені на клієнта і так само
видалені, коли необхідність в них зникне.
Іншою перевагою буде те, що оскільки інтерфейси стандартизовані, то
можна змінювати протокол взаємодії клієнт-сервер і його реалізацію так
часто, як побажаємо. Зміни не зроблять впливу на існуючі клієнтські
програмні засоби, пов'язані з сервером. Існують, зрозуміло, і недоліки. Сліпо
вірити в те, що код, який завантажується, реалізує лише оголошені
інтерфейси доступу до вашого незахищеного жорсткого диска і не відправляє
найцікавіші фрагменти невідомо кому, – не завжди виправдано.

3.6.2. Моделі перенесення коду


Хоча перенесення коду має на увазі лише переміщення коду з машини на
машину, цей термін має ширшу сферу застосування. Традиційно зв'язок в
розподілених системах заснований на обміні даних між процесами.
Перенесення коду в широкому сенсі пов'язане з перенесенням програм з
машини на машину з метою виконання цих програм в потрібному місці. В
деяких випадках, таких як перенесення процесів, також потрібно переносити
стан програми, отримувані сигнали і інші елементи середовища.
Для кращого розуміння різних моделей перенесення коду розглянемо
шаблон, згідно якому, процес складається з трьох сегментів.
Сегмент коду – це частина, що містить набір інструкцій, які
виконуються в ході виконання програми.
Сегмент ресурсів містить посилання на зовнішні ресурси, необхідні
процесу, такі як файли, принтери, пристрої, інші процеси і тому подібне
Сегмент виконання використовується для зберігання поточного стану
процесу, включаючи закриті дані, стек і лічильник програми.
Абсолютний мінімум для перенесення коду пропонує модель слабкої
мобільності (weak mobility). Згідно цієї моделі допускається перенесення
лише сегменту коду, можливо разом з деякими даними ініціалізації.
Характерною рисою слабкої мобільності є те, що перенесена програма
завжди запускається зі свого вихідного стану. Це відбувається, наприклад, з
Java-aпплетами. Перевага подібного підходу в його простоті. Слабка
мобільність потрібна лише для того, щоб машина, на яку переноситься код,
була в змозі його виконувати. Цього цілком достатньо, аби зробити код
переносним.
В протилежність слабкій мобільності, в системах, що підтримують
сильну мобільність (strong mobility), переноситься також і сегмент
виконання. Характерна риса сильної мобільності – факт того, що працюючий
процес може бути припинений, перенесений на іншу машину і його
виконання продовжено з того місця, на якому воно було припинене.
Зрозуміло, що сильна мобільність значно потужніше слабкої, але і значно
складніша в реалізації. Прикладом системи, що підтримує сильну
мобільність, є система D'Agents, яку буде розглянуто далі.
Незалежно від того, є мобільність слабкою або сильною, слід розділяти
системи з перенесенням, ініційованим відправником, і системи з
перенесенням, ініційованим одержувачем. При перенесенні, ініційованому
відправником, перенесення ініціюється машиною, на якій переносимий код
постійно розміщений або виконується. Зазвичай перенесення, ініційоване
відправником, відбувається при завантаженні програм на обчислювальний
сервер.
Приклад.
Передача пошукових програм через Інтернет на сервер баз даних в Web для
виконання запиту на цьому сервері.

При перенесенні, ініційованому одержувачем, ініціатива в перенесенні


коду належить машині-одержувачеві.
Приклад.
Java-апплети.

Перенесення, що ініціюється одержувачем, зазвичай реалізується


простіше. У багатьох випадках перенесення коду відбувається між клієнтом і
сервером, причому ініціатива виходить від клієнта. Безпечне перенесення
коду на сервер, як це відбувається при перенесенні, ініційованому
відправником, часто вимагає, аби клієнт був спочатку зареєстрований і
впізнавався сервером. Іншими словами, сервер повинен знати всіх своїх
клієнтів, оскільки клієнти мають доступ до ресурсів (наприклад, до таких
ресурсів як диск) сервера, захист яких має обов'язково бути організованим. В
протилежність цьому, завантаження коду в разі ініціації цього процесу
приймаючою стороною може здійснюватися анонімно. Більш того, сервер
зазвичай не зацікавлений в ресурсах клієнта. Навпаки, перенесення коду на
клієнта виконується виключно з метою збільшення продуктивності клієнта. З
цього боку в захисті має потребу лише невелика кількість ресурсів, таких як
пам'ять і мережеве з'єднання.
В разі слабкої мобільності слід також розрізняти варіанти, коли
перенесений код виконується в процесі-приймачі або коли він виконується в
новому, спеціально запущеному процесі.
Приклад.
Java-апплети просто завантажуються в web-браузер і виконуються в адресному
просторі браузеру.

Перевага цього підходу полягає в тому, що немає необхідності


запускати новий процес і розривати через це зв'язок з машиною-приймачем.
Основний недолік полягає в тому, що процес-приймач доводиться захищати
від зловмисного або випадкового виконання коду. Просте рішення –
реалізувати створення окремого процесу для переміщеного коду
операційною системою. Відзначимо, що це рішення не вирішує проблем з
доступом до ресурсів.
Окрім перенесення працюючого процесу, так званої міграції процесу,
сильна мобільність може також здійснюватися за рахунок віддаленого
клонування. На відміну від міграції процесу клонування створює точну
копію вихідного процесу, яка виконується на віддаленій машині. Клон
процесу виконується паралельно оригіналові. У UNIX-системах віддалене
клонування має місце при відгалуженнях дочірнього процесу у тому випадку,
коли цей дочірній процес продовжує виконання на віддаленій машині.
Перевага клонування – в схожості із стандартними процедурами,
здійснюваними в багаточисельних програмних засобах. Єдина різниця між
ними полягає в тому, що клонований процес виконується на іншій машині. З
цієї точки зору міграція шляхом клонування – найпростіший спосіб
підвищення прозорості розподілу. Різні варіанти перенесення коду ілюструє
рис. 3.14.
Виконання в
процесі-
прийомнику
Перенос
ініційований
відправником
Виконання в
процесі-отримувачі

Слабка мобільність
(переноситься
сегмент коду)
Виконання в
процесі-
прийомнику
Перенос
ініційований
відправником
Виконання в
процесі-отримувачі

Перенесення коду

Перенос процесу
Перенос
ініційований
відправником
Клонування
процесу
Сильна мобільність
(переноситься
сегмент коду і
виконання)

Перенос процесу
Перенос
ініційований
отримувачем
Клонування
процесу

Рис. 3.14. Варіанти перенесення коду


3.6.3. Перенесення і локальні ресурси
Раніше розглядалось перенесення лише сегментів коду і виконання.
Сегмент ресурсів вимагає окремого розгляду. Перенесення коду часто
сильно затруднює процес перенесення сегменту ресурсів, які не завжди
можна перенести з такою ж легкістю без змін, як інші сегменти.
Приклад.
Розглянемо процес, який містить посилання на конкретний порт TCP, за допомогою
якого він взаємодіє з іншими (віддаленими) процесами. Це посилання знаходиться в
сегменті ресурсів процесу. При перенесенні процесу на іншу машину процес повинен
звільнити зайнятий ним порт і запитати інший – на тій машині, на яку він був
переміщений. У деяких випадках перенесення посилання проблем не створює. Наприклад,
посилання на файл з використанням абсолютної URL-адреси залишиться вірним
незалежно від того, на якій машині виконується процес, який містить цю URL-адрес.

Аби зрозуміти, який вплив надає перенесення коду на сегмент ресурсів,


було виділено три типи зв'язків процесу з ресурсами. Найбільш сильний
зв'язок спостерігається, коли процес посилається на ресурс по його
ідентифікатору. В цьому випадку процес вимагає в точності той ресурс, на
який посилається.
Приклад.
Подібна прив'язка по ідентифікатору (binding by identifier) є використання процесом
URL-адреси для посилання на конкретний web-сайт або інтернет-адреси для посилання на
FTP-сервер. По цих же причинах посилання на локальну кінцеву точку взаємодії також
вважатиметься прив'язкою по ідентифікатору.

Слабкіший зв'язок процесу з ресурсами матиме місце в тому випадку,


якщо процесу необхідне лише значення ресурсу. В цьому випадку виконання
процесу анітрохи не зміниться, якщо таке ж значення йому надасть інший
ресурс.
Приклад.
Типовою прив'язкою за значенням (binding by value) є звернення програм до
стандартних бібліотек, як при програмуванні на мові С або Java. Ці бібліотеки завжди
доступні на локальній машині, але їх дійсне місце розташування в локальній файловій
системі може бути різним. Для правильного виконання процесу важливі не конкретні
імена файлів, а їх вміст.

І, нарешті, найбільш слабка форма зв'язку має місце у тому випадку,


коли процес вказує на необхідність використання ресурсу певного типу.
Приклад.
Подібна прив'язка за типом (binding by type) може бути проілюстрована
посиланнями на локальні пристрої, такі як принтери, монітори і тому подібне.

При перенесенні коду часто необхідна зміна посилань на ресурси, при


цьому змінювати типа прив'язки ресурсу до процесу заборонено. Чи можна
змінювати ресурси, і якщо так, то як це залежить від того, чи можуть вони
бути перенесені на машину-приймач разом з кодом? Якщо конкретніше, то
необхідно визначити зв'язок ресурсів з машиною і розглянути варіанти.
Неприєднанні ресурси (unattached resources) можуть бути з легкістю
перенесені з машини на машину. Файли (даних) в цьому випадку зазвичай
пов'язані лише з програмою, що переноситься. В протилежність їм,
перенесення або копіювання зв'язаних ресурсів (fastened resources) можливо
лише з відносно значними витратами. Типовими прикладами зв'язаних
ресурсів можуть бути локальні бази даних або web-сайти цілком. Не
дивлячись на те, що ці ресурси теоретично не залежать від поточної машини,
часто буває неможливо перенести їх в інше середовище.
І, нарешті, фіксовані ресурси (fixed resources) спочатку прив'язані до
конкретної машини або середовища і не можуть бути перенесені на іншу.
Фіксованими ресурсами часто бувають локальні пристрої. Інший приклад
фіксованих ресурсів – локальні кінцеві точки взаємодії.
Скомбінувавши три типи прив'язки ресурсів до процесів і три типи
прив'язки ресурсів до машини, отримаємо дев'ять комбінацій, які слід
розглянути, обговорюючи питання перенесення коду.
Розглянемо спочатку можливості, що виникають при прив'язці процесу
до ресурсу по ідентифікатору. Якщо ресурс не приєднаний, краще всього
перенести його на іншу машину разом з кодом. Проте якщо цей ресурс
використовується переносимим процесом спільно з іншими, слід
організувати на нього глобальне посилання – посилання, яке в змозі буде
здолати кордон між машинами. Прикладом такого посилання може бути
URL. Якщо ресурс зв'язаний або фіксований, організація глобального
посилання також є найкращим вирішенням проблеми.
Реалізація системи глобальних посилань може бути складніше простого
використання URL і інколи виявляється дуже дорогою.
Приклад
Розглянемо програму обробки високоякісних зображень на окремій робочій станції.
Створення в реальному часі високоякісних зображень — це завдання, яке вимагає
інтенсивних обчислень, тому програма може бути перенесена на високопродуктивний
обчислювальний сервер. Організація глобальних посилань на робочу станцію означатиме
організацію зв'язку між сервером і робочою станцією. Крім того, серйозна обробка, що
відбувається одночасно на сервері і робочій станції, зажадає дотримання певних вимог до
швидкості передачі зображень. В результаті може виявитися, що перенесення програми на
обчислювальний сервер є невиправдано простою тому, що ціна підтримки глобальних
посилань занадто висока.
Іншим прикладом труднощів з підтримкою глобальних посилань може бути
перенесення процесу, який використовує локальну кінцеву точку взаємодії. В цьому
випадку іде мова про фіксовані ресурси, прив'язані до процесу по ідентифікатору, тому є
два основні рішення. Одне з них полягає в тому, аби дозволити процесу після перенесення
встановити з'єднання з вихідною машиною, створивши там окремий потік виконання,
який просто буде перенаправляти всі повідомлення, що приходять, на нове «місце
проживання» процесу.

Основним недоліком підходу пов’язаному з прив'язкою процесу до


ресурсу по ідентифікатору є те, що при збоях або пошкодженні вихідної
машини зв'язок з перенесеним процесом буде перерваний. Інше рішення
полягає в тому, аби, узявши всі процеси, пов'язані з перенесеним, поміняти їх
глобальні посилання і пересилати повідомлення на нову кінцеву точку
взаємодії цільової машини.
Інша ситуація виникає в разі прив'язки за значенням. Розглянемо
спочатку фіксовані ресурси. Комбінація фіксованих ресурсів і прив'язки за
значенням можлива, наприклад, в разі використання процесом ділянки
пам'яті спільно з іншими процесами. Організація глобальних посилань в
цьому випадку може потребувати реалізації розподіленої розділяємої пам'яті.
Проте найчастіше подібне рішення неприйнятне.
Зв'язані ресурси, посилання на яких виконується за значенням, — це
найчастіше бібліотеки часу виконання. Зазвичай допускається копіювання
цих ресурсів на іншу машину, причому це копіювання може бути здійснене
до перенесення коду. Організація глобальних посилань може виявитися
хорошою альтернативою копіюванню в тому випадку, якщо потрібно
скопіювати великий об'єм даних, наприклад словники текстового редактора.
Найбільш простий випадок – неприєднанні ресурси. Найкраще рішення
при цьому – скопіювати (або перемістити) ресурси в нове місце, виключаючи
варіанти, коли вони спільно використовуються декількома процесами. У
останньому випадку єдиним виходом буде створення глобальних посилань.
Останній варіант – прив'язка за типом. Незалежно від способу прив'язки
ресурсу до машини рішення полягає в новій прив'язці процесу до локальних
ресурсів того ж типа. Лише в тому випадку, якщо ресурси даного типа на
локальній машині відсутні, можна скопіювати або перемістити оригінальні
ресурси на нове місце або організувати глобальні посилання на них.

3.6.4. Перенесення коду в гетерогенних системах


Раніше передбачалось, що перенесений код може бути з легкістю
виконаний на цільовій машині. Це припущення відносилося виключно до
гомогенних систем. Проте розподілені системи створюються з набору
гетерогенних платформ, кожна з яких має свою власну машинну архітектуру
і операційну систему. Перенесення в подібних системах вимагає, аби
підтримувалися всі ці платформи, тобто сегмент коду повинен виконуватися
на всіх цих платформах без перекомпіляції тексту програми. Крім того, треба
упевнитись, що сегмент виконання на кожній з цих платформ буде
представлений правильно.
Проблеми можуть бути частково усунені в тому випадку, якщо
обмежитися слабкою мобільністю. В цьому випадку зазвичай не існує
інформації часу виконання, яку треба було б передавати від машини до
машини. Це означає, що досить скомпілювати вихідний текст програми,
створивши різні варіанти сегменту коду – поодинці на кожну потенційну
платформу.
В разі сильної мобільності основною проблемою, яку треба буде
вирішити, є перенесення сегменту виконання. Проблема полягає в тому, що
цей сегмент в значній мірі залежить від платформи, на якій виконується
завдання. Насправді перенести сегмент виконання, не вносячи до нього
жодних змін, можна лише в тому випадку, якщо машина-приймач має ту ж
архітектуру і працює під управлінням тієї ж операційної системи.
Сегмент виконання містить закриті дані процесу, його поточний стек і
лічильник програми. Стек зазвичай містить тимчасові дані, такі як значення
локальних змінних, але може також містити і інформацію, залежну від
платформи, наприклад значення регістрів. Важливо відзначити, що якби
вдалося позбавитися від даних, залежних від платформи, то перенести
сегмент на іншу машину і продовжити виконання там було б значно
простіше.
Перенесення коду обмежене декількома конкретними моментами
виконання програми. Точніше, перенесення можливе лише у момент виклику
чергової підпрограми. Під підпрограмою мається на увазі функція в С, метод
в Java і тому подібне. Виконуюча система створює власну копію програмного
стека, причому машинно-незалежну. Ця копія називається стеком
перенесення (migration stack). Стек перенесення оновлюється під час
виклику підпрограми або поверненні управління з підпрограми.
Під час виклику підпрограми виконуюча система виконує маршалінг
даних, які були поміщені в стек під час попереднього виклику (рис. 3.15). Ці
дані є значеннями локальних змінних, а також значеннями параметрів
поточного виклику процедури. Дані після маршалінга поміщаються в стек
перенесення разом з ідентифікатором викликаної підпрограми. Крім того, в
стек перенесення поміщається адреса (у формі мітки переходу), з якої
повинне продовжуватися виконання після повернення з підпрограми.
Якщо перенесення коду відбувається в точці виклику підпрограми,
виконуюча система виконує спочатку маршалінг всіх глобальних даних
програми, які утворюють сегмент виконання. Дані, специфічні для даної
машини, і поточний стек ігноруються. Дані після маршалінга і стек
перенесення передаються на машину, яка їх очікує. Крім того, на машину-
приймач завантажується відповідний сегмент коду, що містить відповідні для
її архітектури і операційної системи код. На машині-приймачі виконується
демаршалінг отриманих даних сегменту виконання, та із стека перенесення
формується новий стек виконання. Після цього виконання може бути
продовжене простим входом в підпрограму, яка була викликана на вихідному
сайті.
Зрозуміло, що подібний підхід можливий лише в тому випадку, якщо
компілятор генерує код для оновлення стека перенесення при кожному вході
в підпрограму або виході з неї. Компілятор повинен також генерувати в коді
мітки, які дозволяють реалізувати вихід з підпрограми у вигляді переходів
(машинно-незалежних). Крім того, необхідна відповідна виконуюча система.
Проте існує безліч систем, що успішно використовують подібну технологію.
Проблеми перенесення коду, викликані гетерогенністю, у багатьох випадках
схожі з проблемами переносимості, тому також схожі і методи їх рішення.
Приклад
В кінці 70-х років було запропоновано просте рішення, що дозволило вирішити
безліч проблем з перенесенням мови Pascal на різні машини. Таким рішенням стала
генерація проміжного машинно-незалежної коду для абстрактної віртуальної машини. Ця
машина вимагала реалізації на ряді різних платформ, завдяки якій програми на мові Pascal
могли працювати на них всіх. Ця проста ідея деякий час знаходила широке використання,
однак вона ніколи не вважалася загальним рішенням всіх проблем переносимості для
інших мов, особливо С.

Процедура Локальні операції Локальні зміні


Б стеку Б процедури Б

Мітка повернення до
процедури А від
процедури Б

Локальні зміні Значення параметрів


Процедура процедури Б процедури Б
А
Процедура
Адреса повернення з Процедура
Ідентифікація
А
процедури Б А Б
процедури

Виклик процедури Значення параметрів Локальні зміні


вміщується в стек процедури Б процедури А
програми
Мітка повернення до
Локальні
процедури, що
операції стеку А викликала процедуру А

Локальні зміні Значення параметрів


процедури А процедури А

Адреса повернення Ідентифікація


з процедури А процедури А

Програмний стек Стек переносу

Рис. 3.15. Перенесення коду в гетерогенних системах


На сьогоднішній день проблему перенесення коду в гетерогенних
системах почали вирішувати засобами мов сценаріїв, а також мов, що
володіють високою мірою переносимості, таких як Java.
Всі ці рішення, загалом, засновані на віртуальній машині, яка
інтерпретує або безпосередньо вихідні тексти програм (в разі мов сценаріїв),
або проміжний код, що видається компілятором (для Java).
Єдиний серйозний недолік переносимості, що реалізовується за
допомогою віртуальних машин, полягає в тому, що доводиться обмежуватися
конкретною мовою програмування. З цієї причини важливо, аби мови,
призначені для перенесення, мали інтерфейс з існуючими мовами.
Приклад
Аби проілюструвати перенесення коду, розглянемо тепер платформу проміжного
рівня, який підтримує різні форми перенесення коду. D'Agent, або повністю Agent TCL, –
це система, побудована на основі концепції агента. Агентом в системі D'Agent називається
програма, яка в гетерогенній системі здатна переміщатися з однієї машини на іншу.

3.6.5. Огляд перенесення коду в D'Agent


Агент в системі D'Agent – це програма, яка може переміщуватися з
однієї машини на іншу. В принципі програми можуть бути написані на різних
мовах, головне, аби машина, на яку переноситься код, могла виконати його.
На практиці це означає, що програми в D'Agent пишуться на інтерпретованих
мовах, а конкретніше, на командній мові утиліт (Tool Command Language,
TCL), Java або Scheme. Використання виняткове інтерпретованих мов значно
полегшує підтримку гетерогенних систем.
Програма, або агент, виконується в процесі, запущеному
інтерпретатором мови, на якій ця програма написана. Мобільність
підтримується трьома способами: за допомогою ініційованої відправником
слабкої мобільності, за допомогою сильної мобільності з перенесенням
процесів і, нарешті, за допомогою сильної мобільності з клонуванням
процесів.
Слабка мобільність реалізується за допомогою команди agent_submit. У
якості параметра використовується ідентифікатор машини, на яку
переноситься код. На цій же машині виконується сценарій.
Сценарій – це не що інше, як послідовність інструкцій. Сценарій
переноситься на машину-одержувач разом зі всіма описами процедур і
копіями змінних, які необхідні для його виконання на цій машині. На
машині-одержувачі процес запускає відповідний інтерпретатор, який і
виконує сценарій. У поняттях варіантів перенесення коду D'Agent забезпечує
ініційовану відправником слабку мобільність, коли перенесений код
виконується в окремому процесі.
Також підтримується сильна мобільність, що ініціюється відправником,
як у формі міграції, так і у формі клонування процесів. Для перенесення
працюючого агента він викликає команду agent_jump з вказівкою цільової
машини, на яку він має бути перенесений. При виклику команди agent_jump
виконання агента на вихідній машині припиняється і його сегмент ресурсів,
сегмент коду і сегмент виконання піддаються маршалінгу, укладаючись в
повідомлення, яке потім пересилається на цільову машину. Після доставки
повідомлення запускається новий процес, в якому виконується відповідний
інтерпретатор. Цей процес виконує демаршалинг повідомлення, що прийшло,
і продовжує виконання з інструкції, наступної за останнім викликом agent_
jump. Процес, в якому агент виконувався на вихідній машині, припиняє свою
роботу.
І, нарешті, підтримується клонування процесів за допомогою команди
agent_fork. Ця команда працює майже так само, як і agent_jump, за винятком
того, що процес, який запустив агента на вихідній машині, просто продовжує
роботу з інструкції, наступної за викликом agent_fork. Подібно до операції
fork в UNIX-системах, команда agent_fork повертає значення, по якому
процес, що її викликає, може визначити, що перед ним: клонована версія (у
UNIX іменована «дочірньою») або оригінальний процес («батьківським»).
Аби розглянути деякі деталі внутрішньої реалізації, розглянемо написані на
TCL агенти. Зсередини система D'Agent складається з п'яти рівнів (рис. 3.16).

5 Агенти

Інтерпретатор Інтерпретатор Інтерпретатор


4 TCL Scheme Java

3 Узагальнений агент RTS

2 Сервер

1 TCP/IP E-mail

Рис. 3.16. Склад системи D’Agent


Найнижчий рівень схожий з сокетами Берклі, в тому сенсі, що він
реалізує єдиний інтерфейс механізмів взаємодії базової мережі. У D'Agent
передбачається, що базова мережа надає механізми для роботи з
повідомленнями TCP і електронної пошти.
Наступним рівнем є сервер, що працює на кожній машині, на якій
виконується D'Agent. Сервер відповідає за управління агентами,
авторизацію і управління зв'язком між агентами. Для останнього виду
діяльності сервер привласнює кожному агентові локальний унікальний
ідентифікатор. Якщо використовувати мережеву адресу сервера, то кожен з
агентів може бути позначений парою (адреса, локальний ідентифікатор).
Подібне ім'я низького рівня використовується для установки зв'язку між
двома агентами.
Третій рівень містить незалежне від мови ядро, яке підтримує основні
моделі агентів. Так, наприклад, цей рівень містить реалізацію запуску і
закінчення роботи агента, реалізації різних операцій перенесення і засобу для
зв'язку між агентами. Зрозуміло, що операції ядра недалеко пішли від
операцій сервера, але на відміну від сервера ядро не відповідає за управління
набором агентів, розміщених на одній машині.
Четвертий рівень містить по одному на кожну підтримуючу в D'Agent
мову інтерпретатори. Кожен інтерпретатор містить компонент інтерпретації
мови, модуль безпеки, інтерфейс з рівнем ядра і окремий модуль для
перехоплення стану працюючого агента. Цей останній модуль необхідний
для підтримки сильної мобільності.
Найвищий рівень містить агенти, написані на одному з підтримуваних
системою мов. Кожен агент D'Agent виконується в окремому процесі. Так,
наприклад, коли агент переноситься на машину А, сервер розгалужує процес
виконання відповідного інтерпретатора, створюючи вітку для виконання цього
агента. Новий процес підхоплює стан мігрованного агента і продовжує його
виконання з тієї точки, на якій він був призупинений. Сервер відстежує локальні
канали створеного процесу, за допомогою яких процес отримує призначені для
нього повідомлення.
Найскладніша частина реалізації D'Agent – це здобуття стану працюючого
агента і передача його на іншу машину.
Інтерпретатору необхідна таблиця, в якій зберігаються глобальні змінні.
Так, обробник подій може повідомляти інтерпретатор, яку процедуру слід
викликати в разі приходу повідомлення від деякого агента. Пари (подія,
обробник) зберігаються в таблиці інтерпретатора. У іншій таблиці містяться
глобальні системні змінні, в яких зберігаються коди помилок, рядки з
повідомленнями про помилки, коди результатів, рядки повідомлень, що
виводяться разом з результатами і тому подібне. Є також окрема таблиця, в якій
зберігаються всі визначені користувачем глобальні змінні програми. І, нарешті, в
окремій таблиці зберігаються визначення процедур, зв’язаних з агентами. Ці
визначення процедур потребують перенесення разом з агентами для вибору
інтерпретатора на цільовій машині.
Інший аспект, безпосередньо пов'язаний з перенесенням агентів, –
наявність двох стеків, в яких зберігається поточний стан виконання агента.
У основі кожного агента лежить набір команд TCL, можливо, вбудованих в
конструкції, такі як цикли, інструкції множинного вибору і так далі Крім
того, команди можливо згруповані в процедури. Як це відбувається у всіх
інтерпретуємих мовах, агентом виконується команда за командою.
Спочатку розглянемо, що відбувається при виконанні базової команди TCL,
тобто команди, яка викликається не з призначеної для користувача процедури.
Інтерпретатор аналізує команду і будує запис, який поміщається в те, що
називається стеком команд (command stack). Цей запис містить всі необхідні
для виконання команди поля: значення параметрів, покажчик на процедуру
реалізації команди і тому подібне. Запис поміщається в стек, після чого може
бути використаний компонентом, який відповідає за виконання команди.
Іншими словами, стек команд є місцем зберігання поточного стану виконання
агента.
TCL також підтримує процедури, які визначаються користувачем. Окрім
стека команд середовище виконання D'Agent відстежує стек записів
активізації, які також називаються фреймами виклику. Фрейм виклику в
D'Agent містить таблицю змінних, локальних для процедури, а також імена і
значення параметрів, з якими ця процедура була викликана. Фрейм виклику
створюється лише в результаті виклику процедури і відноситься до команди
виклику процедури, поміщеної в стек команд. Фрейм виклику містить
посилання на пов'язану з ним команду.
Приклад
Розглянемо тепер, що відбувається, наприклад, коли агент викликає команду
agent_jump, за допомогою якої він переноситься на іншу машину. У цей момент повний
стан агента, описаний вище, піддається маршалингу і перетворюється в послідовність
байтів. Іншими словами, всі чотири таблиці і два стеки укладаються в масив байтів і
пересилаються на іншу машину. Сервер D'Agent на цільовій машині створює новий
процес, запускаючи інтерпретатор TCL. Процес обробляє отримані дані, виконує їх
демаршалинг і в результаті отримує стан агента, в якому він знаходився перед викликом
команди agent_jump. Виконання агента продовжується шляхом простого зняття з вершини
стека команд чергової команди.

3.7. Програмні агенти


Розглянемо процеси під дещо іншим кутом. Спочатку зосередимося на
одному з ключових питань – керуючих потоках виконання усередині
процесів. З позицій взаємодії ближче розглянемо узагальнену організацію
клієнтів і серверів. І нарешті, обговоримо перенесення програм і процесів. Ці
більш менш незалежні процеси об'єднаються в те, що називають
програмними агентами – автономними одиницями, здатними виконувати
завдання в кооперації з іншими, можливо, віддаленими агентами.
Агенти відіграють в розподілених системах усе більш важливу роль. Проте
дуже близько до дійсності твердження про те, що є лише інтуітивне визначення
того, що таке процес. Визначення програмних агентів в таких умовах теж
потребує уточнення.
3.7.1. Програмні агенти в розподілених системах
Програмний агент (software agent) визначається як автономний
процес, здатний реагувати на середовище виконання і викликати зміни в
середовищі виконання, можливо, в кооперації з користувачами або з іншими
агентами.
Властивість, яка робить агента чимось більшим, ніж процес, – це
здатність функціонувати автономно і, зокрема, проявляти при необхідності
ініціативу.
Визначення програмного агента є вельми невизначеним, і в результаті
багато типів процесів з легкістю можуть сприйматися в якості агентів.
Замість того аби робити спроби точніше визначити програмні агенти, краще
говорити про різних типів програмних агентів. Тобто в літературі зроблено
декілька спроб розробити класифікацію програмних агентів, але домовитися
про єдину класифікацію дослідникам нелегко.
Окрім автономності найважливіша якість агентів – можливість
кооперуватися з іншими агентами. Поєднання автономності і кооперації
приводить до класу кооперативних агентів.
Кооперативний агент (collaborative agent) – це агент, що становить
частину мультиагентної системи, тобто системи, в якій агенти,
кооперуючись, виконують деякі загальні завдання.
Приклад.
Типове програмне забезпечення, що використовує кооперативні агенти, – це
електронна конференція. Кожен з доповідачів представлений агентом, що має доступ до
питань, які користувач хоче представити на загальний розгляд. З урахуванням всіх
персональних обмежень на якийсь час, місце розташування, переміщення і тому подібне
спільна робота окремих агентів дозволяє організувати конференцію. У перспективі, таким
чином, можуть виконуватись розробки розподілених систем, особливо призначених для
обміну інформацією.
У ряді випадків виділяються з інших типів агентів мобільні агенти.
Мобільний агент (mobile agent) – це агент, в якого є здатність
переміщатися з машини на машину.
У термінах, які використовувалися при обговоренні перенесення коду,
мобільні агенти часто вимагають підтримки сильної мобільності, хоча це і не є
абсолютно необхідним. Вимога сильної мобільності витікає з того факту, що
агенти автономні і активно взаємодіють зі своїм середовищем. Перенос агента
на іншу машину без врахування його стану буде сильно утруднений. Проте як
було показано на прикладі системи D'Agent, поєднання агентів і слабої
мобільності також цілком можливо. Відзначимо, що мобільність – це загальна
властивість агентів, наявність якої не вимагає виділення особливого їх класу.
Так, наприклад, має сенс говорити про існування мобільних кооперативних
агентів.
Здатність до кооперації з іншими агентами або переміщення між
машинами – це системні властивості агентів. Вони не говорять нічого про
призначення агента. Для визначення функціональності агента потрібна інша
класифікація.
Клас, який традиційно виділяється, – це клас інтерфейсних агентів.
Інтерфейсний агент (interface agent) – це агент, що допомагає кінцевому
користувачу працювати з одним або декількома програмними засобами.
Серед властивостей, що традиційно є у інтерфейсного агента, можна
вказати здатність до навчання. Найчастіше вони взаємодіють з
користувачами, забезпечуючи їм підтримку.
Приклад
У контексті розподілених систем прикладом цікавого інтерфейсного агента може
бути агент, що відстежує взаємодії між агентами і користувачами в деякому
співтоваристві. Так, наприклад, створюються спеціальні інтерфейсні агенти для взаємодії
продавців з покупцями. Правильно зрозумівши, що хоче побачити або що може
запропонувати його власник, інтерфейсний агент може допомогти запропонувати
потрібну групу товарів.
Дуже близький до інтерфейсного агента інформаційний агент
(information agent). Інформаційний агент (information agent) – агент, що
займається управлінням інформацією з безлічі різних джерел.
Управління інформацією включає впорядкування, фільтрацію,
порівняння і тому подібне Важливості інформаційним агентам в
розподілених системах додає той факт, що вони можуть працювати з
інформацією з фізично різних джерел. Стаціонарні інформаційні агенти
зазвичай працюють з вхідними потоками інформації.
Приклад
Поштовий агент може застосовуватися для фільтрації в поштовій скриньці її
власника непроханої кореспонденції або для автоматичного перенаправлення вхідну
пошту у відповідні до її теми поштові скриньки.

В протилежність їм, мобільні інформаційні агенти зазвичай вільно


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

Властивість Спільність Опис

для агентів

Здатність працювати
Автономність Так
незалежно від інших

Здатність своєчасно
Реактивність Так реагувати на зміни в своєму
оточенні

Проектна Так Здатність ініціювати дії, що


впливають на їх оточення

Здатність обмінюватися
Комунікативність інформацією з
Так
користувачами і іншими
агентами

Тривалість Немає Відносно довгий час життя

Мобільність Немає Здатність переміщатися з


місця на місце

Адаптивність Немає Здібність до навчання

3.7.2. Технологія агентів


Уявлення про те, що таке агенти, не має сенсу в тому випадку, якщо
відсутня підтримка у вигляді реально існуючих систем агентів. Дуже
корисною була б можливість виділити постійно використовувані компоненти
агентів в розподілених системах і включити їх в програмне забезпечення
проміжного рівня. Як вихідну точку організація FIPA (Foundation for
Intelligent Physical Agents) розробила узагальнену модель програмних агентів.
Згідно цієї моделі агенти реєструються і працюють під управлінням
платформи агентів, як показано на рис. 3.17. Платформа агентів надає
основні служби, необхідні будь-якій мультиагентній системі. Сюди входять
механізми створення і знищення агентів, механізми розпізнавання агентів і
механізми взаємодії між агентами.
Компонент управління агентами відстежує агентів на відповідній
платформі. Він надає механізми створення і знищення агентів, а також механізм
перегляду поточної кінцевої точки щодо наявності конкретного агента. У цьому
сенсі компонент управління агентами надає службу найменування, за допомогою
якої глобально унікальний ідентифікатор відображується на локальну кінцеву
точку взаємодії.
Крім того, існує і окрема локальна служба каталогів, за допомогою якої
агенти можуть дізнатись, які ще агенти є на цій платформі. Служба каталогів в
моделі FIPA заснована на використанні атрибутів. Це означає, що агент надає
описи своїх служб в поняттях імен атрибутів разом з їх значеннями для даного
агента. До служби каталогів можуть мати доступ віддалені агенти, тобто агенти,
що знаходяться на інших платформах агентів.

Програма агент
Платформа агента

Компоненти Служба Канал зв’язку


управління каталогів між агентами
агентами
Кінцева точка
агенту

Міжплатформенний зв’язок

Рис. 3.17. Узагальнена модель платформи агента


Важливий компонент платформи агента – канал зв'язку між агентами
(Agent Communication Channel – АСС). У більшості моделей мультиагентних
систем агенти зв'язуються один з одним, пересилаючи повідомлення. Модель
FIPA – не виключення, вона покладає на АСС відповідальність за всю
взаємодію між різними платформами агентів. Зокрема, АСС відповідає за
надійний і направлений зв'язок точка-точка з іншими платформами. Канал
АСС може бути реалізований просто у вигляді сервера, що відстежує деякий
порт, призначений для вхідних повідомлень, які перенаправляються іншим
серверам або агентам, що є частиною платформи агентів. Для забезпечення
міжплатформеної взаємодії зв'язок між АСС відповідає інтернет-протоколу
IIОР (Internet INTER-ORB Protocol). У архітектурі D'Agent як АСС виступає
сервер.
3.7.3. Мови взаємодії агентів
Отже, в платформі агентів є своя специфіка. Відмінність від інших
підходів до розподілених систем стає зрозумілою при розгляді характеру
інформації, якою реально обмінюються агенти. Зв'язок між агентами
відбувається за допомогою комунікаційного протоколу прикладного рівня,
відомого під назвою мови взаємодії агентів (Agent Communication Language –
ACL). B ACL присутнім є жорстке розділення між метою повідомлення і його
змістом. Повідомлення може мати лише обмежений набір цілей.

Приклад
Метою повідомлення може бути запит на надання отримувачем певної служби.
Також метою повідомлення може бути відповідь на раніше надіслане повідомлення із
запитом. Іншим прикладом мети повідомлення може бути повідомлення сторони, яка
приймає, про подію, яка сталася, або про пропозицію стосовно чогось в ході узгодження.

Ідея ACL полягає в тому, що агент-відправник і агент-одержувач як


мінімум однаково розуміють мету повідомлення. Більш того, мета
повідомлення зазвичай визначає і реакцію одержувача.

Приклад.
Так при запиті пропозиції шляхом повідомлення, що має в заголовку мету CFP,
одержувач насправді повинен буде послати пропозицію, за допомогою повідомлення з
метою PROPOSE. У цьому сенсі ACL дійсно визначає високорівневий комунікаційний
протокол для набору агентів.

Як і більшість комунікаційних протоколів, повідомлення ACL


складаються із заголовка і реального вмісту (рис. 3.18). Заголовок містить
поле мети повідомлення, а також поля відправника і одержувача. Крім того,
як і в багатьох інших комунікаційних протоколах, вміст листа відокремлений
і є незалежним від останньої його частини. Іншими словами, передбачається,
що вміст листа визначать агенти, що вступили в зв'язок. ACL ніяк не задає
формат або мову змісту повідомлення.

Мета повідомлення

Поле відправника
Заголовок
Поле одержувача

Мова декодування

Реальні дані

Рис. 3.18 Структура повідомлення ACL


Тепер необхідно, щоб приймаючому агентові була надана вся необхідна
інформація для правильної інтерпретації вмісту. Для цього заголовок
повідомлення ACL повинен також визначати мову або схему декодування
вмісту. Цей підхід добре працює до тих пір, доки відправник і одержувач
однаково інтерпретують дані, або, точніше, символи повідомлення. Якщо
єдине розуміння відсутнє, незрідка потрібні додаткові поля, що
ідентифікують стандартне відображення символів в їх сенс. Таке
відображення зазвичай називається онтологією (ontology).

Висновки

1. Процеси відіграють фундаментальну роль в розподілених системах,


оскільки вони формують базис для зв'язку між різними машинами.
2. Важливим питанням є внутрішня організація процесів і зокрема, чи
здатні вони підтримувати декілька управляючих потоків виконання.
Потоки виконання в розподілених системах використовуються,
зокрема, для продовження роботи з процесором під час блокуючих
операцій введення-виводу. Таким чином, з'являється можливість
побудови ефективніших серверів, в яких декілька потоків виконання
працюють одночасно, причому деякі з них можуть бути блоковані в
очікуванні виконання дискових операцій введення-виводу або
операцій мережевої взаємодії.
3. Можлива організація розподілених програмних комплексів в
поняттях клієнтів і серверів. Клієнтський процес зазвичай реалізує
призначений для користувача інтерфейс, який може варіюватися від
простого виведення інформації до розширених інтерфейсів, здатних
підтримувати документи складної структури. Клієнтське програмне
забезпечення, крім того, здатне підтримувати прозорість розподілу,
приховуючи деталі, що стосуються зв'язку з серверами, поточного
місцерозташування серверів і реплікації серверів. Крім того,
програмне забезпечення клієнта здатне частково приховати
виникаючі збої і процеси відновлення після збоїв.
4. При побудові серверів приміняються різні архітектурні моделі.
Сервери можуть бути інтеративними або паралельними,
реалізовувати одну або декілька служб, зберігати інформацію про
стан або не зберігати. Архітектурні особливості стосуються адресації
служб і механізмів переривання серверів після надходження запиту
на обслуговування і можливо в ході його виконання.
5. Сервери об'єктів виділяються в особливий клас. Сервер об'єктів – це
процес, який містить розміщені в своєму адресному просторі об'єкти
і який готовий приймати направлені до них звернення. У окрему
категорію сервери об'єктів виділяються багато в чому завдяки
різноманітності способів звернення до об'єктів. Сервер може
запустити окремий потік виконання для кожного запиту до об'єкту. З
іншого боку, він може виділяти кожному об'єкту власний потік
виконання або залишити єдиний потік виконання для всіх своїх
об'єктів. За допомогою адаптера об'єктів в різних серверах може
бути реалізована різна політика звернення до об’єкта. На сервері
може бути декілька адаптерів об'єктів.
6. Важливою для розподілених систем функціональною властивістю є
перенесення коду з машини на машину. Для того, щоб підтримувати
перенесення коду, є дві вагомі причини – підвищення
продуктивності і мобільність. Інколи існує потреба в зменшенні
взаємодії за рахунок перенесення обчислень з сервера на клієнт.
Гнучкість зростає, коли клієнт має можливість динамічно
завантажувати програмне забезпечення, необхідне для роботи з
конкретним сервером. Завантажене програмне забезпечення може
бути вже налаштованим на взаємодію з цим сервером, позбавляючи
клієнта від необхідності повторно встановлювати його до початку
роботи.
7. При перенесенні коду існує проблема використання локальних
ресурсів, пов’язана з тим, що ці ресурси також необхідно переносити
на інші машини, організовувати нові прив'язки коду до локальних
ресурсів цільової машини або використовувати глобальні посилання.
Інша проблема полягає в тому, що при перенесенні коду треба брати
до уваги гетерогенність системи. Поточна практика показує, що,
можливо, кращим засобом впоратися з гетерогенністю є віртуальні
машини, які ефективно приховують гетерогенність за допомогою
коду, що інтерпретується.
8. Програмні агенти – спеціальний вид процесів, що працюють як
автономні модулі, які здатні кооперуватися з іншими агентами. З
точки зору розподілених систем, відмінність агентів від звичайних
програмних засобів в тому, що агенти взаємодіють один з одним за
допомогою комунікаційного протоколу прикладного рівня, який
називається мовою взаємодії агентів (ACL). У ACL є чітке
розділення між метою повідомлення і його змістом.
Питання для самоконтролю

1. Що розуміється під поняттям процес?


2. Що таке потоки виконання?
3. З яких елементів складається потік виконання?
4. Побудуйте схему потоку виконання та поясніть її.
5. Назвіть стани в яких можуть знаходитись процеси та потоки
виконання.
6. Назвіть способи організації побудови сервери. В чому полягають
відмінності між ними?
7. Охарактеризуйте організацію багатопотоковогу серверу.
8. Перерахуйте задачі клієнтського програмного забезпечення.
9. Як реалізується прозорість реплікації на стороні клієнта?
10. Що розуміється під поняттям сервер?
11. Які існують способи організації серверів?
12. Що таке сервер об’єктів?
13. Які існують підходи до обробки об’єктів?
14. Дайте обгрунтування необхідності перенесення коду.
15. Сформулюйте основні підходи до перенесення коду.
16. В чому полягає процедура перенесення локальних ресурсів?
17. Як реалізується перенесення коду в гетерогенних системах?
18. Як реалізується перенесення коду в D’Agent?
19. Що розуміється під поняттям агент?
20. Які існують види агентів?
21. В чому полягає технологія агентів?

You might also like