Оценка производительности распределённого приложенияна

advertisement
МИНОБРНАУКИ РОССИИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ
УЧРЕЖДЕНИЕ
ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
«НОВОСИБИРСКИЙ НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ
ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ» (НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ
УНИВЕРСИТЕТ, НГУ)
Кафедра общей информатики
Ипполитов Вадим Дмитриевич
Оценка производительности распределённого приложения
на примере Parallels Automation
МАГИСТЕРСКАЯ ДИССЕРТАЦИЯ
по направлению высшего профессионального образования
230100.68 ИНФОРМАТИКА И ВЫЧИСЛИТЕЛЬНАЯ ТЕХНИКА
ФАКУЛЬТЕТ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ
Тема диссертации утверждена распоряжением по НГУ №64 от «15» февраля 2011г.
Руководитель
Козлов С.А.
к.ф-м.н, инженер ООО «Параллелз»
…………………………
(подпись, печать)
Новосибирск, 2012г.
2
МИНОБРНАУКИ РОССИИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ
УЧРЕЖДЕНИЕ
ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
«НОВОСИБИРСКИЙ НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ
ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ» (НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ
УНИВЕРСИТЕТ, НГУ)
Кафедра общей информатики
УТВЕРЖДАЮ
Зав. кафедрой
Пальчунов Дмитрий Евгеньевич
…………………………
(подпись, дата)
ЗАДАНИЕ
на магистерскую диссертацию
студент Ипполитов Вадим Дмитриевич
факультета ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ
Направление подготовки 230100.68 ИНФОРМАТИКА
ТЕХНИКА
И
ВЫЧИСЛИТЕЛЬНАЯ
Магистерская программа: Технология разработки программных систем
Тема: Оценка производительности распределённого приложения на примере Parallels
Automation
Цели работы: реализовать механизм сбора статистических данных о нагрузке на сервера
системы Parallels Automation, спроектировать и реализовать программный продукт для
анализа и предсказания производительности системы.
Руководитель
Козлов С.А.
к.ф-м.н, инженер ООО «Параллелз»
…………………………
(подпись, печать)
3
Содержание
ВВЕДЕНИЕ................................................................................................................................4
1. Используемые термины........................................................................................................5
2. Существующие системы предсказания нагрузки..............................................................6
3. Задачи проекта.......................................................................................................................6
4. Работа над механизмом предсказания и первой версией системы..................................7
4.1. Сбор начальной статистики.........................................................................................7
4.2. Анализ параметров производительности оборудования..........................................8
4.2.1. Тактовая частота процессора...............................................................................8
4.2.2. Количество ядер....................................................................................................8
4.2.3. Объём оперативной памяти.................................................................................9
4.2.4. Тактовая частота памяти......................................................................................9
4.2.5. Скорость обмена данными с ПЗУ.......................................................................9
4.2.6. Пропускная способность сетевого оборудования.............................................9
4.3. Выбор параметров для предсказания нагрузки.......................................................10
4.4. Реализация и тестирование программной системы................................................10
5. Архитектура программной системы.................................................................................10
5.1. Слой абстракции данных...........................................................................................11
5.2. Интерфейс агентов.....................................................................................................11
5.3. Контроллер предсказателей......................................................................................11
5.4. Веб-интерфейс............................................................................................................11
5.5. Агенты.........................................................................................................................11
5.6. Функции-предсказатели.............................................................................................12
6. Недостатки выбранного подхода.......................................................................................12
7. Возможности дальнейшего развития................................................................................12
7.1. Прямая поддержка систем виртуализации..............................................................12
7.2. Превращение агента в исполняемый файл..............................................................13
7.3. Редактирование функций предсказания через веб-интерфейс..............................13
8. Заключение..........................................................................................................................14
Литература...............................................................................................................................15
4
ВВЕДЕНИЕ
В настоящее время очень большое распространение получают так называемые
облачные вычисления. Сервера в облаке находятся под контролем системы управления,
такой как Parallels Automation, и могут быть как виртуальные, так и не виртуальные.
Провайдер желает знать, сколько клиентов сможет обслужить каждый сервер. Это
требуется для того, чтобы предсказать свои расходы на инфраструктуру, установить
оптимальные расценки для клиентов и обеспечить необходимый уровень качества
обслуживания (SLA — Service Level Agreement). Один из способов узнать это —
проведение
прямых
измерений
производительности
при
различном
количестве
пользователей (имитация пользователей может быть сделана при помощи автоматических
функциональных тестов).
В распоряжении разработчиков системы автоматизации нет такого же мощного
оборудования, как у провайдера. Вместо этого имеется тестовое окружение, развёрнутое
на сравнительно слабом оборудовании. Также своё тестовое окружение с аналогичными
свойствами может быть у провайдера. Провайдер, приобретающий ПО для автоматизации,
ожидает, что производитель этого ПО имеет данные об ожидаемой максимальной
«плотности» размещения пользователей, при которой автоматизированный сервис
работает хорошо. Поэтому возникает необходимость предсказывать производительность
приложения в реальном ЦОДе по тем данным, которые можно собрать в одном из
тестовых окружений.
На первом этапе работы над проектом были проанализированы существующие
программные продукты схожего назначения. Также были рассмотрены различные аспекты
параметров производительности компьютеров с целью выяснить, какие из них могут
наиболее сильно влиять на производительность облачных сервисов, и найден инструмент
для измерения этих параметров. Затем были собраны и вручную проанализированы
статистические данные о нагрузке на сервера тестового окружения во время прохождения
автоматических тестов. В итоге была реализована программная система, позволяющая
собирать данные о загрузке серверов, анализировать её, строить функции предсказания и
предсказывать нагрузку на ресурсы серверов при изменении количества пользователей
сервисов и параметров оборудования.
5
1. Используемые термины
В тексте используются следующие термины и сокращения:
Центр
Набор компьютеров (серверов), объединённых в одну или
обработки
несколько внутренних информационных сетей, некоторые из
данных (ЦОД)
которых также доступны из сети Интернет.
Юридическое лицо, владеющее центром обработки данных и
Провайдер
предоставляющее своим клиентам услуги по доступу к
различным сервисам через Интернет.
Программный продукт, предоставляющий информационные
Сервис
услуги, например, возможность размещения и поддержания
доступности интернет-сайтов, электронных почтовых ящиков.
Физический
хост
Компьютер, являющийся частью центра обработки данных,
который непосредственно используется для размещения ПО,
предоставляющего сервисы.
Контейнер, созданный при помощи специального ПО и
Виртуальный
хост
функционирующий как самостоятельный компьютер, но
фактически
являющийся
процессом
внутри
другой
операционной системы. На одном компьютере может быть
размещено несколько виртуальных хостов.
Клиент
ОС
Лицо, за плату использующее ПО, размещённое на хостах
центра обработки данных, для решения своих бизнес-задач.
Операционная система.
6
2. Существующие системы предсказания нагрузки
Существует несколько коммерческих продуктов, позволяющих предсказывать
производительность
систем
с
изменением
различных
параметров.
Наиболее
продвинутыми являются TeamQuest Predictor [4] и up.time Capacity Planning [5]. Эти
средства позволяют делать предсказания как по тренду изменения количества запросов к
системе со временем, так и по изменению конфигурации оборудования.
К сожалению, эти продукты слишком дороги, и их приобретение обосновать не
удалось.
3. Задачи проекта
Рассмотрим распределённое приложение Parallels Automation (далее сокращённо
PA), развёрнутое на серверах центра обработки данных. На каждом сервере в
соответствии со схемой развёртывания установлены компоненты третьестороннего
приложения,
обеспечивающего
предоставление
необходимых
хостинговых
услуг
клиентам, а также управляющий агент PA.
Задачей данной работы является разработка механизма анализа и предсказания
нагрузки на сервера центра обработки данных и реализация программной системы,
основанной на этом механизме. Система должна позволять предсказать нагрузку на
ресурсы серверов при изменении количества пользователей сервисов и ключевых
параметров оборудования.
При этом делаются следующие допущения, которые будут обоснованы ниже:
1. При заданной конфигурации оборудования и ПО, нагрузка на сервер зависит
только от количества пользователей обслуживаемого сервиса.
2. При расчётах учитываются только два параметра: загрузка процессора и
оперативной памяти.
Дополнительным нефункциональным требованием является расширяемость системы
на случай, если второе из упомянутых допущений перестанет быть верным. Такое может
произойти при анализе других видов сервисов. Например, при анализе сервисов IPтелефонии, одним из ключевых факторов может стать пропускная способность сетевого
оборудования.
7
4. Работа над механизмом предсказания и первой версией
системы
Схема работы с системой предсказания такова:
1. В тестовом окружении запускаются автоматические нагрузочные тесты, с
постепенным увеличением количества одновременно активных «пользователей».
При этом агентами реализованной программной системы собираются данные о
загрузке ресурсов серверов.
2. По завершении автоматических тестов с помощью веб-интерфейса системы
производится ручной анализ собранных данных. Данные отображаются в виде
таблиц и графиков.
3. В процессе анализа выявляются эмпирические зависимости между изменением
количества пользователей и параметрами загрузки серверов. Эти зависимости
выражаются в виде функций предсказания. Построенная функция предсказания
ассоциируются
с
конкретным
сервисом
и
конкретной
конфигурацией
оборудования.
4. Процесс повторяется, до тех пор, пока качество предсказателей не станет
субъективно приемлемым.
5. После ввода желаемого количества пользователей сервиса, система отображает
предсказанную загрузку ресурсов соответствующих серверов.
Работа была разделена на несколько этапов, которые будут описаны ниже.
4.1. Сбор начальной статистики
Для того, чтобы понять общий характер зависимости между количеством
пользователей
и
нагрузкой
на
сервера,
необходимо
было
собрать
некоторые
статистические данные во время интенсивной работы с тестовой инсталляцией.
Parallels Automation позволяет управлять более чем 20 различными сервисами, среди
которых Microsoft Exchange различных версий, IIS, Apache HTTP Server, Qmail, Postfix и
многие другие. Также доступны сотни [2] сервисов в виде пакетов формата APS [3]. Ясно,
что каждый сервис по-своему определяет характер загрузки ресурсов серверов, и
исследовать их все не представляется возможным. Задачу упрощает то, что инструкции по
развёртыванию для большинства сервисов рекомендуют использовать отдельные
(виртуальные или физические) хосты для установки каждого сервиса. Поэтому можно
исследовать сервисы независимо друг от друга.
8
4.2. Анализ параметров производительности оборудования
Существует множество измеримых параметров производительности оборудования,
основными из которых являются тактовая частота и количество ядер процессора, скорость
и объём оперативной памяти, скорость чтения и записи ПЗУ и пропускная способность
сетевого оборудования. Рассмотрим каждый из них в отдельности.
Поскольку система Parallels Automation в качестве управляемых поддерживает
только 32 и 64-битные сервера архитектуры x86 с ОС Windows и Linux, другие
архитектуры и операционные системы в данной работе не рассматриваются.
4.2.1. Тактовая частота процессора
Тактовая частота — это один из факторов, определяющих количество абстрактных
операций в секунду, которые может выполнить процессор. Важно, что сравнение
производительности различных процессоров по тактовой частоте имеет смысл только в
том случае, если они принадлежат одной серии [6], то есть имеют прочие равные
параметры, а именно, размер кэшей всех уровней, длину конвейера, и т.д. В этом случае
можно считать, что производительность линейно зависит от тактовой частоты.
В настоящее время тактовая частота широко распространённых серверных
процессоров находится на уровне 3-4 ГГц. Ранее непрерывный рост тактовой частоты был
возможен благодаря уменьшению физических размеров транзисторов (из-за увеличения
их количества) в соответствии с законом Мура. Однако примерно в 2003 году рост
тактовой частоты прекратился, будучи ограниченным другими физическими факторами
[7]. Таким образом, значительного увеличения производительности серверов ЦОДа нельзя
добиться только за счёт изменения тактовой частоты.
4.2.2. Количество ядер
Закон Мура по-прежнему действует, и количество транзисторов в процессоре
удваивается каждые два года. Это приводит к увеличению количества вычислительных
ядер и объёма кэшей в процессоре.
Все
современные
процессоры,
устанавливаемые
в
сервера,
являются
многоядерными, обычно четырёхядерными и более. Поэтому можно считать, что если
приложение загружает все доступные ядра, то оно расчитано на многоядерность. Однако
напрямую переносить результаты, полученные на n-ядерном процессоре на k-ядерный
нельзя, если n ≠ k.
9
4.2.3. Объём оперативной памяти
Объём оперативной памяти влияет на то, сколько данных компьютер может
обрабатывать, не обращаясь к более медленным внешним носителям, таким, как жёсткие
диски [1]. Объём оперативной памяти на сервере может значительно варьироваться, от 4
ГБ до сотен ГБ, что делает этот параметр интересным для исследования в рамках данной
работы.
4.2.4. Тактовая частота памяти
Так же, как и тактовая частота процессора, частота памяти почти перестала
увеличиваться в последние годы. Кроме того, при увеличении тактовой частоты памяти,
увеличиваются и так называемые тайминги, причём производительность вычислительных
приложений в целом изменяется слабо [8].
4.2.5. Скорость обмена данными с ПЗУ
На данный момент существует два принципиально различных вида широко
доступных ПЗУ: накопители на жёстких магнитных дисках и твёрдотельные накопители.
Твёрдотельные накопители обладают значительным преимуществом перед НЖМД в
скорости чтения и записи в случае, когда обращения по случайным адресам преобладают
над последовательным доступом, а наиболее дорогие модели и при последовательном
доступе оказываются в два-три раза быстрее, чем НЖМД [9]. К сожалению, удельная
стоимость этих накопителей пока слишком велика для повсеместного использования.
Кроме того, в доступном автору тестовом окружении не имеется ни одного
твёрдотельного накопителя. Поэтому, несмотря на то, что сравнение производительности
сервисов при использовании различных видов ПЗУ представляет большой интерес, его не
удалось произвести в рамках данной работы.
Помимо различных видов ПЗУ, существуют также различные способы их
подключения, в частности, RAID-схемы. В тестовом окружении используются различные
конфигурации RAID на разных серверах.
4.2.6. Пропускная способность сетевого оборудования
Для большинства сервисов как внутреннее сетевое взаимодействие, то есть
взаимодействие между хостами одного сервиса внутри ЦОДа, так и внешнее, то есть
обмен данными с другими компьютерами в интернете, не являются узким местом:
стандартного для ЦОДов гигабитного канала в обоих случаях оказывается достаточно.
Сетевое взаимодействие может стать узким местом для хостов, основная задача
которых — пересылка данных, без их обработки и хранения в ПЗУ, например, прокси-
10
серверов для веб-трафика или IP-телефонии. В данной работе такие случаи не
рассматриваются.
4.3. Выбор параметров для предсказания нагрузки
По результатам предыдущего раздела было принято решение в первой версии
приложения ограничиться двумя параметрами:
1. загрузка процессора.
2. загрузка оперативной памяти.
Однако
архитектура
системы
должна
быть
расширяемой,
позволяя
при
необходимости добавить другие важные в некоторых случаях параметры, такие как
загрузка сетевых каналов.
4.4. Реализация и тестирование программной системы
На данном этапе были реализованы необходимые программные модули, и
протестирована работа системы. В качестве тестируемой подсистемы использовался
сервис Microsoft Sharepoint 2010.
5. Архитектура программной системы
Верхнеуровневая схема архитектуры представлена на рис.1.
агенты
Интерфейс
агентов
Web-интерфейс
HTTP
XML
Контроллер
предсказателей
Слой абстракции
данных
функции-предсказатели
СУБД
Рис 1: Архитектура системы
11
5.1. Слой абстракции данных
Система спроектирована таким образом, чтобы позволять сохранять и загружать
данные с произвольным набором атрибутов, автоматически создавая нужные таблицы в
СУБД. Это позволяет легко добавлять новые виды собираемых данных.
Слой абстракции данных поддерживает эту концепцию с помощью технологии
объектно-реляционного отображения Hibernate [10].
5.2. Интерфейс агентов
Интерфейс, через который агенты сбора статистики вносят новые данные в систему,
базируется на XML. Для получения объектов Java из XML используется библиотека
XStream [11]. Далее объекты передаются в слой абстракции данных для сохранения в
СУБД.
5.3. Контроллер предсказателей
Контроллер предсказателей обеспечивает доступ к списку доступных функций
предсказания нагрузки. Этот список автоматически генерируется в момент старта
программы с помощью процессора аннотаций Java [12]. Он позволяет фильтровать этот
список различными способами, например, по предсказываемому параметру (загрузка
оперативной памяти или процессора).
5.4. Веб-интерфейс
Веб-интерфейс предоставляет доступ к просмотру собранных данных о загрузке
хостов ЦОДа и количестве пользователей сервисов, а также позволяет инициировать
процедуру предсказания нагрузки.
5.5. Агенты
Агент представляет собой отдельное приложение, устанавливаемое на каждый хост
в ЦОДе. Приложение собирает данные о загрузке процессора и памяти с помощью
утилиты ptool [13], разработанной сотрудником компании Parallels. Утилита обладает
высокой точностью измерений и позволяет, при необходимости, замерять отдельно
нагрузку, создаваемую группой (деревом) процессов, причём . Например, можно замерять
и отправлять на сохранение в систему предсказания нагрузку на процессор, создаваемую
антивирусом (или любым другим системным процессом, например, утилитой резервного
копирования), и далее учитывать эти данные как дополнительный параметр в функции
предсказания. На данный момент сохраняется только суммарная нагрузка на процессор и
память, создаваемая всеми процессами в системе.
12
5.6. Функции-предсказатели
Функции-предсказатели оформляются в виде обычных Java-классов с аннотацией
@PredictorFunction. Хотя этот подход требует от исследователя запуска компилятора
Java при необходимости изменить функцию предсказания, на данный момент это не
является проблемой, поскольку пользователем системы предсказания является сам автор
работы. В будущем может быть добавлена поддержка скриптового языка, что позволит
редактировать имеющиеся и вводить новые функции предсказания через веб-интерфейс
системы.
При
реализации
функций
предсказания
можно
пользоваться
готовыми
статистическими фунциями, например, для вычисления скользящего среднего с заданным
окном, или дискретизированных интервалов. Функции-помощники в эту небольшую
библиотеку добавляются по мере выявления различных видов зависимостей.
6. Недостатки выбранного подхода
Предсказание нагрузки на сервер даёт представление о том, при каком количестве
пользователей сервер будет полностью загружен. Однако в реальности, эта граница не
всегда может быть достигнута, потому что время отклика сервиса при полностью
нагруженном сервере может оказаться недопустимо большим. Эту проблему можно
обойти, построив функцию предсказания таким образом, чтобы она завышала значения
при высоком уровне нагрузки. Однако это неудобно, потому что график предсказанной
функции в этом случае не будет визуально совпадать с реальным эмпирическим
графиком.
7. Возможности дальнейшего развития
Ниже приведены несколько путей улучшения разработанной системы предсказания.
7.1. Прямая поддержка систем виртуализации
В текущей версии системы виртуализация не поддерживается явно. Можно
установить агент на сервер и, одновременно, на каждый виртуальный хост. Однако
система не будет учитывать, что нагрузка на сервер в целом зависит от суммы нагрузок на
все виртуальные хосты, расположенные на этом сервере, а также что повышение нагрзки
на один виртуальный хост ведёт к ухудшению производительности других виртуальных
хостов на этом же сервере. Также виртуальность хостов никак не будет отражена в
отображаемой в приложении конфигурации ЦОДа.
13
7.2. Превращение агента в исполняемый файл
В данный момент для работы агента требуется наличие на хосте установленной
виртуальной машины Java. Это неудобно, поскольку на большинстве хостов она не
требуется для работы сервисов, и её приходится устанавливать специально. Более того,
установка JVM может оказаться неприемлемой, например, если система предсказания
будет разворачиваться в «чужом» тестовом окружении (в тестовом окружении
провайдера, использующего Parallels Automation). В этом случае объём устанавливаемого
ПО должен быть сведён к минимуму.
Проблему можно решить, в целом, двумя способами:
1. переписать агента на язык программирования, который изначально является
компилируемым, например, C++;
2. использовать компилятор GCJ [14] или ему подобный инструмент, способный
генерировать
исполняемые
файлы
для
Java-программ,
которые
можно
непосредственно исполнять в ОС Windows и Linux.
7.3. Редактирование функций предсказания через веб-интерфейс
Для реализации возможности задания функций-предсказателей через веб-интерфейс
можно использовать один из скриптовых языков для виртуальной машины Java, такой как
Groovy. Однако эта возможность не была исследована автором, может оказаться, что она
труднореализуема, например, из-за проблем с производительностью.
14
8. Заключение
В ходе работы были проанализирована предметная область и сформулированы
требования к системе предсказания нагрузки. Была реализована первая версия
программной системы, показавшая практическую применимость выбранного подхода, а
также выявлены связанные с ним проблемы.
Соискатель ……………………… Ипполитов В.Д.
(подпись, дата)
15
Литература
1. Иртегов Д.В. Введение в операционные системы — СПб.: БХВ-Петербург, 2012
2. Thousands of services – Parallels Automation [Электронный ресурс] Режим доступа:
http://www.parallels.com/products/automation/thousands/, свободный. — Загл. с
экрана. — Яз. англ.
3. Application Packaging Standard [Электронный ресурс] Режим доступа:
http://apsstandard.org/, свободный. — Загл. с экрана. — Яз. англ.
4. Capacity Planning Software: Powerful, Easy, Affordable. [Электронный ресурс] Режим
доступа: http://www.uptimesoftware.com/capacityplanning.php, свободный. — Загл. с
экрана. — Яз. англ.
5. TeamQuest Predictor — Accurately predict IT service performance with capacity
planning software. [Электронный ресурс] Режим доступа:
http://www.teamquest.com/products-services/teamquest-performancesoftware/teamquest-predictor/index.htm, свободный. — Загл. с экрана. — Яз. Англ.
6. Megahertz myth — Technology — The Guardian [Электронный ресурс] Режим
доступа: http://www.guardian.co.uk/technology/2002/feb/28/onlinesupplement3,
свободный. — Загл. с экрана. — Яз. Англ.
7. The Free Lunch Is Over – A Fundamental Turn Toward Concurrency in Software
[Электронный ресурс] Режим доступа: http://www.gotw.ca/publications/concurrencyddj.htm, свободный. — Загл. с экрана. — Яз. Англ.
8. Тест памяти DDR3: стоит ли переплачивать? [Электронный ресурс] Режим
доступа:
http://winline.ru/hardware/platform/test_pamyati_ddr3_stoit_li_pereplachivat.php ,
свободный. — Загл. с экрана.
9. All SSD Charts 2011 [Электронный ресурс] Режим доступа:
http://www.tomshardware.com/charts/ssd-charts-2011/benchmarks,129.html,
свободный. — Загл. с экрана. — Яз. Англ.
10. Relational Persistence for Java and .NET [Электронный ресурс] Режим доступа:
http://hibernate.org/, свободный. — Загл. с экрана. — Яз. Англ.
11. XStream - a simple library to serialize objects to XML and back again [Электронный
ресурс] Режим доступа: http://xstream.codehaus.org/, свободный. — Загл. с экрана.
— Яз. Англ.
16
12. Writing and processing custom annotations [Электронный ресурс] Режим доступа:
http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-339362483.htm, свободный. — Загл. с экрана. — Яз. Англ.
13. Киров А.В. Разработка инструментария для анализа производительности групп
взаимодействующих процессов в ОС Windows // Квалификационная работа на
соискание степени магистра, 2011.
14. Portable, optimizing, ahead-of-time compiler for the Java Programming Language
[Электронный ресурс] Режим доступа: http://gcc.gnu.org/java/, свободный. — Загл. с
экрана. — Яз. Англ.
Download