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

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

Что такое виртуализация?

Эмоционально яркое определение виртуализации дал Фред Хэпгуд: «Виртуализация — это замена физических элементов вычислительной среды (будь то аппаратура или программное обеспечение) искусственными "клонами", которые, являясь точными копиями оригиналов, избавляют нас от необходимости — порой доставляющей массу неудобств — иметь дело с самими оригиналами» [1].

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

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

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

Головная боль компьютерщиков и электриков

Наличие большого числа быстродействующих компьютеров в современных вычислительных центрах еще не есть гарантия успешного и оптимального выполнения возложенных на эти центры задач. Как правило, каждый отдельный сервер решает одну-две задачи, используя свои ресурсы в среднем на 15-20%. Значит, основную часть времени он простаивает, занимая место, потребляя электричество и нагревая окружающую среду, борьба за охлаждение которой, в свою очередь, требует дополнительных затрат электроэнергии. Каждый сервер нужно администрировать, обновлять и ремонтировать. На вопрос «что делать» ответ вроде бы очевиден — разместить приложения на меньшем числе серверов, увеличив коэффициент средней загрузки до 50-70%, и тем самым вдвое-втрое сократить затраты на оборудование, место для его размещения и электроэнергию. Хотелось бы повышать коэффициент загрузки и дальше, но профессионалы, занимающиеся настройкой производительности ИТ-систем, хорошо знают, что для большинства распространенных операционных систем и приложений этот коэффициент не стоит доводить до значений, превышающих 70%, иначе время отклика на каждый запрос при пиковой нагрузке будет настолько большим, что негативно скажется на настроениях пользователей — в конце концов, ИТ-служба создается для облегчения ведения дел, а не наоборот. Кроме того, имеется ряд других веских причин, не позволяющих запускать несколько приложений, решающих разные задачи, на одном сервере в единой операционной среде.

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

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

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

Виртуализация и кластеризация

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

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

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

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

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

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

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

HP Integrity и виртуализация

Для иллюстрации основных способов формирования виртуальной серверной среды рассмотрим реализацию, объединяющую несколько подходов к созданию виртуальных машин, — HP Virtual Server Environment (VSE) [3].

В качестве базовой платформы для консолидации и виртуализации компания HP предлагает использовать серверы семейства Integrity, на основе процессоров семейства Itanium. Двухъядерные процессоры Dual Core Intel Itanium2 9000 (Montecito), использующиеся в этих системах, специально оптимизированы для параллельной обработки и работы не только в многопользовательской многозадачной среде, но и в виртуальной серверной среде, поскольку имеют не четыре режима защиты, как их предшественники, а пять. Дополнительный режим предназначен для функционирования монитора виртуальных машин, полностью изолирующего ядра нескольких операционных систем, которые могут исполняться одновременно в среде виртуальных машин на одном физическом процессоре с помощью технологии Intel Virtualization Technology. К тому же этим процессорам требуется существенно меньше тактов на переключение контекста, чем процессорам семейства x86.

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

Аппаратные разделы (nPars) обеспечивают полную электрическую изоляцию для защиты раздела от аппаратных и программных сбоев в соседних разделах, выполнение нескольких независимых копий разных операционных систем в разных разделах (поддерживаются HP-UX, OpenVMS, Linux и Windows), а также они предоставляют возможность переброски ресурсов из раздела в раздел (требуется перезагрузка реконфигурируемых разделов, а остальные разделы продолжают работать). Элементарной минимальной единицей ресурсов для аппаратных разделов является «ячейка» (cell), содержащая несколько процессоров, память и платы ввода/вывода.

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

Виртуальные машины (Integrity VM) аналогичны виртуальным разделам, но осуществляют полную виртуализацию аппаратного обеспечения, что позволяет изолировать несколько независимых копий разных ОС (например, HP-UX, OpenVMS, Linux и Windows) в рамках одного аппаратного раздела или физической машины, дает возможность запустить несколько виртуальных «процессоров» на одном физическом и подстроить их «тактовую частоту» (фактически степень загрузки физических процессоров «виртуальными процессорами» данной виртуальной машины), а также обеспечивает динамическую миграцию процессорного времени (поддерживается на уровне как целых процессоров, так и специально задаваемой доли процессорного времени) из одного виртуального раздела в другой (перезагрузка не требуется), совместное использование процессоров и ресурсов ввода/вывода разными копиями ОС, возможность запуска конкретной копии ОС с неизмененными настройками и драйверами на аппаратно разных физических машинах (полезно для процессов тестирования и внедрения, а также обеспечения устойчивости к отказам и катастрофам). Элементарной минимальной единицей ресурсов является доля процессорного времени, некоторое количество памяти и виртуальные платы ввода/вывода, резервируемые за виртуальной машиной, что позволяет при необходимости запускать несколько ОС одновременно даже на однопроцессорной машине.

Разделы ресурсов внутри одной копии ОС (Secure Resource Partitions, SRP) предоставляют изолированные ресурсы различным задачам или их группам внутри одной копии HP-UX, обеспечивая управление процессорным временем для каждого раздела, изолированное управление памятью для каждого раздела, управление полосой пропускания ввода/вывода для каждого раздела, прикрепление пользователей и приложений к определенному разделу, изоляцию приложений в разных разделах друг от друга, включая невозможность связи между приложениями разных разделов. Кроме этого можно предоставить выделенные сетевые интерфейсы каждому разделу и изолировать, если нужно, ресурсы файловой системы.

Отметим, что операционная система OpenVMS позволяла обеспечить функциональность, аналогичную vPars и SRP, еще на процессорах Alpha. Перенос OpenVMS на Integrity позволил воспользоваться всеми виртуализационными преимуществами новой платформы.

Все способы виртуализации можно комбинировать в рамках одной машины, например создать несколько аппаратных разделов и запустить в одном из них, скажем, несколько копий HP-UX в виртуальных разделах vPars, в другом обеспечить выделенные ресурсы с помощью SRP, а в прочих разместить несколько копий других ОС — OpenVMS, Windows, Linux — непосредственно в аппаратных разделах или с помощью виртуальных машин.

Поскольку операционные системы, запускаемые в разделах, могут, в свою очередь, обеспечивать работу эмуляторов или кросс-компиляторов других типов процессоров, на Integrity технически возможно консолидировать все многообразие приложений, работающих на семействе процессоров Itanium, подавляющее большинство приложений, работающих на процессорах PA-RISC, многие приложения, работающие на процессорах Alpha и VAX, ряд приложений, работающих на семействе процессоров x86, и даже программное обеспечение для мэйнфреймов, причем так, чтобы все эти приложения не конфликтовали друг с другом.

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

Виртуализация и консолидация

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

Рис. 1. Вычислительный центр с полной виртуализацией ресурсов

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

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

При аварии остальные виртуальные машины можно перезапустить на любом работающем оборудовании семейства Integrity в сохранившемся центре. Реконфигурация самих копий ОС (что, может быть, не столь существенно для OpenVMS, но важно для HP-UX, Windows и Linux) и перенастройка приложений при таком переносе не потребуются, поскольку конфигурация виртуальной аппаратной части самих виртуальных машин будет той же.

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

Зачем же нужна виртуализация?

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

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

Литература

  1. Фред Хэпгуд, "Весомые выгоды виртуализации". Директор информационной службы, 2005, № 12.
  2. Христоф Миташ, Вернер Фишер, "Виртуализация с вариациями". Журнал сетевых решений LAN, 2006, № 7.
  3. Herington, Bryan Jacquot, The HP Virtual Server Environment: Making the Adaptive Enterprise Vision a Reality in Your Datacenter, Published September, 2005 by Prentice Hall PTR, ISBN 0-13-185522-0.

Кирилл Вахрамеев (Kirill.Vakhrameev@hp.com) — технический консультант и OpenVMS Ambassador, компания HP (Москва).

Поделитесь материалом с коллегами и друзьями

Купить номер с этой статьей в PDF