Архітектура системи X-Com

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Лекція

Архітектура системи X - Com

1. Основні компоненти системи


Система X - Com реалізована за принципами клієнт-серверної архітектури, в якій можна виділити два основних компоненти.

Сервер X - Com - Центральна частина системи, що містить серверну частину програми користувача і відповідає за:

розділення початкової завдання на блоки

розподіл завдань

координацію робіт усіх вузлів

контроль цілісності результату

збір результату розрахунку в єдине ціле

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

розрахунок блоків прикладної задачі

запит завдань для розрахунку від сервера

передачу результатів розрахунку на сервер

Всі комунікації між вузлами і сервером у X - Com відбуваються через мережу Інтернет. При цьому використовується тільки стандартний протокол HTTP (HyperText Transfer Protocol), що дозволяє підключати до системи практично будь-які обчислювальні потужності, що мають доступ в Інтернет. Система не вимагає налаштування для роботи через проксі-сервера, firewall та інші системи захисту. Дані, що передаються системою, аналогічні стандартним трафіку Інтернет.

2. Ієрархія вузлів і серверів


Для організації більш ефективних комунікацій і підключення більшої кількості вузлів система може бути організована у вигляді довільного ієрархічного дерева. Листям такого дерева завжди будуть обчислювальні вузли, в корені дерева - залишиться центральний сервер X - Com.

Проміжні сервера (такі як Сервер-2 на малюнку) з точки зору центрального сервера виглядають як звичайні обчислювальні вузли, а з точки зору нижележащих обчислювальних вузлів як центральний сервер.

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

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

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

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

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

3. Архітектура серверів X - Com і обчислювальних вузлів


Блок зв'язку з прикладною програмою являє собою набір інтерфейсів для взаємодії з серверною частиною програми користувача. У цій реалізації система підтримує 3 інтерфейсу зв'язку з серверною частиною прикладної програми:

Java API: для програм на мові Java.

З і C + + API: для програм на мовах C і C + +. Цим же інтерфейсом можна користуватися для компонування з будь-якими іншими мовами підтримують об'єктні файли.

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

Логіка центрального сервера. Цей блок системи, визначає алгоритм розподілених обчислень: логікою розподілу завдань по клієнтських машин, а також збором і аналізом результатів обчислень.

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

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

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

Серверний комунікаційний блок відповідає за пересилання пакету із завданням на вузли і також прийом від вузлів результатів обчислень. Підключення до вузлів відбувається за протоколом HTTP. Сервер X - Com має два основні режими взаємодії, які реалізуються в серверному комунікаційному блоці: синхронний і асинхронний. Синхронний режим означає, що на весь час обчислень вузол має доступ до сервера і статистика про рішення завдання передається в режимі online. Асинхронний режим означає періодичний контакт і збір статистики з клієнтським модулем, виродженим випадком асинхронного режиму є видача завдання клієнту і очікування від нього з'єднання з інформацією про закінчення розрахунку.

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

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

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

Блок зв'язку з обчислювальною частиною прикладної програми відповідає за взаємодію з прикладної програмою користувача. У поточній реалізації системи передбачено 2 інтерфейсу зв'язку з обчислювальною частиною прикладної програми:

C і С + + API: для програм на мовах C і C + +. Цим же інтерфейсом можна користуватися для компонування з будь-якими іншими мовами підтримують об'єктні файли.

STDIN - STDOUT API: інтерфейс використовує стандартні потоки введення-виведення.

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

4. Два методи розбиття вихідної задачі на блоки

У системі X - Com передбачено два основні методи розбиття вихідної задачі на блоки: метод послідовної вибірки та метод довільної вибірки, вибір того чи іншого методу проводиться виходячи із специфіки прикладної програми. По суті, ці методи відрізняються способом отримання від прикладної програми чергового завдання і повернення отриманого результату.

4.1 Метод послідовної вибірки

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

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

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

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

4.2 Метод довільної вибірки

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

4.3 Архітектура центрального сервера для реалізації методів послідовної і довільної вибірки


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

Нагадаємо, що прикладна програма взаємодіє з сервером X - Com через один з 3-х інтерфейсів: Java, C / C + +, Files. У кожному з цих інтерфейсів передбачені незалежні блоки функцій як для одного, так і для іншого методу.

У блоці логіки сервера є два незалежних модуля реалізують відповідно два методів розбиття вихідної задачі. Крім цих 2-х модулів у блоці логіки сервера є загальна частина, яка відповідає за:

ідентифікацію вузла

ведення бази даних (інформація про вузли, обчислювальних можливостях вузлів, а також про статистику з'єднань)

перевірку коректності результату

5. Точки взаємодії прикладної програми з системою X - Com


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

Серверна частина прикладної програми управляє формуванням завдань для розрахунку на вузлах. Програма може бути реалізована на будь-якому засобі програмування, важливо тільки, щоб вона задовольняла API X - Com.

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

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

6. Хід обчислень у системі X - Com

Для того щоб краще зрозуміти роботу системи та її зв'язок з архітектурою розглянемо хід обчислень на деякій задачі.

Для простоти припустимо, що завдання допускає рішення методом прямої вибірки і використовується проста архітектура з одним центральним сервером і кількома вузлами (без проміжних північ).

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

6.1 Розбиття вихідної завдання на блоки і нумерації цих блоків

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

6.2. Початковий момент часу і з'єднання вузлів з ​​сервером

У початковий момент часу сервер знаходиться в стані очікування запитів від обчислювальних вузлів. Нехай у нас є деяка кількість обчислювальних вузлів, і всі вони запущені.

Кожен вузол весь час поки він функціонує, періодично посилає запити "дай завдання" на сервер. Якщо стався збій з'єднання, або сервер ще не готовий вузол знову чекає деякий час і повторює спробу.

6.3 Підключення та ідентифікація вузла

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

Можливі чотири типи з'єднань:

"Дай завдання" - первинний запит результату;

"Отримай результат - дай наступне завдання" - повернення розрахованого завдання і запит наступного. Цей запит робиться в одній сесії для оптимізації мережевої взаємодії;

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

Повідомлення про статус розрахунку на даному сайті. Це інформаційний тип запитів, який важливий при тривалих обчисленнях, щоб сервер "пам'ятав" про існування сайту, такі запити передаються напряму в блок збору статистики про хід обчислень і прямо не впливають на хід обчислень.

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

6.4 Первинний запит завдання

У початковий момент часу всі вузли звертаються до сервера з запитом "дай завдання". Припустимо, що деякий вузол встановив з'єднання і пройшов процедуру ідентифікації.

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

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

6.5 Розрахунок завдання на вузлі

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

Закінчивши розрахунок, вузол посилає результат розрахунок на сервера. Для цього використовується запит "Отримай результат - дай наступне завдання".

6.6 Отримання сервером результатів обчислень

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

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

6.7 Закінчення обчислень

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

6.8 Структури даних сервера для зберігання інформації про вузли

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

Тип поля

Назва поля

Опис

Ідентифікація сесії: основний спосіб ідентифікації вузла

String

sId

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

Ці дані не впливають на хід обчислень, вони використовуються тільки при підрахунку статистики.

String

gcCode

Код клієнта задається користувачем на вузлі, використовується при розрахунку статистики. Може бути не унікальним, тоді в статистиці все вузла з цим кодом будуть додаватися.

String String

Cluster Node


Код клієнта зазвичай складається з двох частин: імені кластеру та імені вузла. Цей поділ є досить умовним і необхідно тільки для більш зручного збору та перегляду статистики. Якщо дана поділ не використовується код кластеру залишається порожнім.

Double

MHz

Частота процесора на вузлі.

String

IP

Останній IP адреса, з якого відбувався запит від даного вузла (він може змінюватися у випадку комутованого з'єднання).

String

OS

Операційна система вузла.

Дані про хід обчислень

Double

Last_access_perf

Продуктивність останнього розрахунку на даному сайті. У початковий момент часу містить -1.

Long

Last_access_time

Час останнього розрахунку на даному сайті. У початковий момент часу містить -1.

Boolean

IsActive

Прапор активності клієнта, якщо сервер вважає, що даний вузол вибув з обчислень, прапор встановлюється в значення "Брехня". Після будь-якого з'єднання від вузла приймає значення "Істина".

Long

Portion

Номер порції, яку в даний момент обчислює вузол. Якщо вузол не отримав даних для розрахунку містить -1.

Long

Portion _ time

Стартовий період часу, в який була передана остання порція для розрахунку даним вузлом. Якщо вузол не отримав даних для розрахунку містить -1.

6.9 Перерозподіл завдань у методі довільної вибірки

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

У методі довільної вибірки є три варіанти організації ходу обчислень:

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

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

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

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

Час очікування відповіді розраховується як розрахунковий час очікування відповіді помножене на коефіцієнт K _ wait. Розрахунковий час очікування відповіді, у свою чергу, визначається виходячи зі статистики роботи з кожним конкретним клієнтом і розміру поточного завдання. Коефіцієнт K _ wait - важливий атрибут роботи системи: при його збільшенні ми очікуємо пакет протягом більшого часу і відповідно менше шанс, що ми пошлемо один і той же пакет двом різним обчислювальним вузлам (затримка може бути пов'язана як з неточністю передбачення часу розрахунку, так і із завантаженням обчислювально вузла), з іншого боку при збільшенні цього коефіцієнта ми збільшуємо розміри вікна, що веде в прикладній програмі до збільшення часу очікування чергової порції даних, а також збільшення розмірів вікна вимагає додаткових ресурсів пам'яті центрального сервера.

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

6.10 Фонові процеси на сервері

Паралельно з основними процесами на сервері працюють фонові процеси, які не впливають на хід обчислень. Працюють два основних процеси: перевірка стану вузлів і відображення ходу обчислень. Перевірка станів вузлів - це процес, періодично перевіряє всі вузли з таблиці поточних обчислень, на предмет їх активності, при закінченні деякого часу, які обчислюється аналогічно часу очікування відповіді, але з іншим коефіцієнтом - K _ wait _ dead. K _ wait _ dead повинен бути більше K _ wait. Якщо вузол не відповідає більше ніж, час очікування активності, то він позначається в таблиці як неактивний.

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

6.11 Перевірка коректності результату

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

Відсутність перевірки коректності. Результат обчислень буде передаватися безпосередньо в прикладну програму, яка його зберігає.

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

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

Метод перерахунку результату. Ключовим параметром методу перерахунку служить коефіцієнт повторної перевірки - дійсне число більше одиниці. У разі цілого числа цей коефіцієнт означає скільком вузлам треба роздати одне й те саме завдання. Отримані результати звіряються один з одним, і в разі розбіжності використовується метод голосування для визначення правильного результату. Якщо рівну кількість вузлів проголосувало за кожний варіант результату, проводяться додаткові перевірки для визначення переможця. Всі вузли, які видали невірний результат, заносяться в чорний список і надалі не зможуть отримувати завдання на обробку. Якщо коефіцієнт повторної перевірки більше 1 і менше ніж 2, - то він характеризує ймовірність, з якою черговий пакет буде перевірений. Ця ймовірність становить коефіцієнт повторної перевірки мінус одиниця. У разі дійсного числа більшого 2, коефіцієнт повторної перевірки аналогічно характеризує ймовірність перевірки пакета найближчим до нього зверху, або найближчим знизу цілим числом перевіряючих вузлів.

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Лекція
67.6кб. | скачати


Схожі роботи:
Архітектура програмної системи
Архітектура системи на базі процесора Pentium Socket 7
Архітектура обчислювальної системи Класифікація комп ютерів
Архітектура операційної системи MS DOS Структура ОС Ms-Dos розбивка на модулі визначення ст
Архітектура IA-32
Архітектура
Архітектура відродження
Архітектура мікроконтролерів
Архітектура Візантії
© Усі права захищені
написати до нас