Оптимизация работы виртуальной инфраструктуры на базе VMWare vSphere

  • Tutorial
image

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

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

Для начала хотелось бы рассказать о двух технологиях, основным образом влияющих на производительность vSphere. Это технология NUMA и технология работы шедулера гипервизора ESXi.

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

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

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

Рассмотрим потенциальные проблемы, которые могу возникнуть с NUMA. Предполагаем, что vSphere его видит и корректно с ним работает. Для примера будем рассматривать 2-процессорную систему, как самый простой вариант NUMA. Предположим, что на физическом сервере 64 GB оперативной памяти, по 32 на каждом сокете.

1. Мы создаем виртуальную машину (ВМ) с одним виртуальным ядром (vCPU). Естественно, такую виртуальную машину сможет исполнить только один физический процессор. Рассмотрим ситуацию, когда ВМ надо дать 48 GB оперативной памяти. 32 GB памяти ВМ заберет у «своего» физического процессора, а еще 16 ей вынужденно придется забрать у «чужого». И при доступе к этим «чужим» гигабайтам мы получаем гарантированно высокие задержки, что ощутимо снизит быстродействие виртуальной машины и увеличит нагрузку на шину передачи данных между физическими процессорами. Исправить ситуацию можно, если дать виртуальной машине 2 виртуальных сокета по 1 ядру каждый. Тогда vSphere распределит 2 vCPU ВМ по разным физическим процессорам, взяв у каждого по 24 GB оперативной памяти. Дав виртуальной машине 1 виртуальный сокет мы лишим её возможности грамотно использовать 2 физических процессора.
2. Вариант, когда мы создаем в плюс к первому пункту вторую ВМ на 10 GB оперативной памяти и один vCPU. Если бы эта ВМ была одна, то никаких проблем нет, она вполне умещается в одну NUMA ноду с 32 GB оперативной памяти. Но у нас уже есть первая машина, которая у обоих нод NUMA отъела по 24 GB памяти, и у каждой ноды осталось свободно всего по 8 GB. В данной ситуации либо первая, либо вторая ВМ начнут использовать часть «чужой» памяти, хотя вроде бы каждая из них сконфигурирована правильно с точки зрения NUMA. Это очень характерная ошибка и необходимо очень досконально просчитывать вашу виртуальную инфраструктуру при проектировании, а так же комплексно подходить к конфигурированию виртуальных машин при эксплуатации.

Хотелось бы отметить, что vSphere имеет свою четкую логику при работе с NUMA и Hyperthreading.

Если у ВМ всего 1 виртуальный сокет, то при увеличении vCPU, исполнение машины будет производиться на одном физическом процессоре исключительно на его физических ядрах без использования технологии Hyperthreading. При превышении количества vCPU над количеством физических ядер процессора, ВМ продолжит исполняться в пределах этого физического процессора, но уже с использование Hyperthreading. Если количество vCPU превысило количество ядер процессора с учетом Hyperthreading, то начнут использоваться ядра соседних NUMA нод (других физических процессоров), что приведет к потере производительности (если указать неверное количество виртуальных сокетов). В случае, когда физический процессор сильно нагружен, и свободных физических ядер не осталось, то в любом случае будет использоваться технология Hyperthreading (если иное не указано в конфигурации виртуальной машины). Если посмотреть на цифры, то в среднем ВМ теряет порядка 30-40% производительности, если она работает на чистом Hyperthreading по сравнению с чистыми физическими ядрами. Но сам физический процессор имеет общую производительность примерно на 30% больше с технологией Hyperthreading, чем без нее (используя только физические ядра). Данный показатель очень зависит от типа нагрузки и оптимизации приложений ВМ к многопоточной работе.

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

По понятным причинам, ситуация с нагрузкой физического сервера постоянно меняется. Зачастую, возникает неравномерность нагрузки на физических процессорах сервера. vSphere следит за этим. Шедулер анализирует положение дел, вычисляет накладные расходы на перемещение ВМ или её части на другую NUMA ноду (перемещение памяти, ядер). Сравнивает эти расходы с потенциальной выгодой от перемещения и принимает решение — оставлять все как есть или же перемещать. Иными словами, при любой ситуации vSphere старается оптимизировать работу виртуальных машин. Наша задача состоит в том, чтобы упростить vSphere эту задачу и не ставить её в безвыходное положение.

О каких потерях может идти речь при неправильной конфигурации машин с NUMA нодами? Руководствуясь собственным опытом, могу сказать, что потери могут доходить до 30% общей производительности физического сервера. Много это или мало – решать вам.

Теперь, когда мы немного разобрались с NUMA и Hyperthreading, мне хотелось бы чуть подробнее рассказать о работе шедулера с ядрами виртуальных машин, vCPU.

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

Для легкости восприятия, предлагаю воспринимать все vCPU виртуальных машин как цепочку. Каждое звено цепи – это ядро vCPU (world, в терминах vSphere). Таких world у машины столько, сколько у нее vCPU. Есть еще 2 невидимых, служебных world, сопутствующих каждой виртуальной машине. Один отвечает за обслуживание машины в целом, второй за её ввод-вывод. Реальное потребление вычислительной мощности этими служебными мирами совершенно незначительное, а потребление ими оперативной памяти можно оценить по показателю overhead у каждой виртуальной машины. Стоит отметить, что при создании ВМ размером в весь физический хост, с равным количеством виртуальных и физических ядер, могут возникнуть некоторые потери производительности. Этого момента я коснусь чуть ниже.

Конвейер READY, это «труба», в которую по очереди сброшены все такие цепочки. Таймслот – это время, в течение которого виртуальные машины исполняются физическим процессором (исполняются их vCPU). На это время виртуальная машина практически без потерь, аналогично физическому серверу, использует физические процессоры аппаратного сервера (pCPU). Максимальная величина таймслота искусственно ограничена величиной порядка 1 миллисекунды. После окончания таймслота, vCPU ВМ принудительно помещаются шедулером в очередь конвейера READY. Шедулер имеет возможность менять очередность виртуальных машин в конвейере READY, приоритет каждой машины вычисляется исходя из её текущей фактической нагрузки, её прав на ресурсы (Shares), как давно машина была на физическом процессоре и еще нескольких менее значимых параметров. Логично предположить, что если ВМ на хосте одна, то она всегда будет проходить конвейер очереди READY без задержек т.к. у нее нет конкурентов на ресурсы со стороны других ВМ.

Каким образом шедулер располагает миры виртуальных машин на физических ядрах? Представим себе таблицу, которая имеет по ширине столько столбцов, сколько ядер у нашего физического сервера (с учетом Hyperthreading). По высоте каждая строка будет соответствовать очередному такту процессора(ов) сервера. Давайте представим себе 2-процессорный сервер, по 6 физических ядер на процессор, + Hyperthreading. Всего получим 24 ядра на сервер. Предположим, что у сервера высокая нагрузка, и vSphere вынуждена использовать Hyperthreading, так будет проще считать. Допустим, у нас есть несколько виртуальных машин:

• 4 штуки по 1 ядру
• 4 штуки по 2 ядра
• 2 штуки по 8 ядер
• 1 штука по 16 ядер

Итак, наступает первый таймслот, шедулер выбирает претендентов. Пусть первой будет машина на 16 ядер. Первые 16 физических ядер (pCPU) заняты, осталось 8. Туда поместились, допустим, 4 машины по 2 ядра (причем машина на 16 ядер должна иметь 2 виртуальных сокета, чтобы корректно работать с NUMA). Всё, таймслот заполнен полностью, это идеальный вариант. Мы не теряем производительность, pCPU не простаивают. Остальные виртуальные машины в это время не работают и находятся в очереди ожидания READY. Предположим, что «счастливые» виртуальные машины получили одинаковый по величине таймслот (хотя в реальности у всех ВМ таймслот разный и зависит от множества факторов). Итак, наступает второй таймслот, и шедулеру надо его заполнить.

Остались не обслуженными машины:

• 4 штуки по 1 ядру
• 2 штуки по 8 ядер

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

image

Аналогичным образом шедулер будет и далее наполнять таймслоты мирами виртуальных машин, стараясь сделать это максимально эффективно, чтобы уменьшить «дыры» в заполнении и повысить КПД виртуальной среды.

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

image

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

Сейчас хотелось бы вернуться к созданию виртуальной машины величиной в весь хост. Хорошо, пусть такая ВМ заняла собой целиком первый таймслот и отработала его. Теперь вспоминаем про системные миры, сопутствующие этой машине. Их тоже надо исполнять, как надо исполнять сам гипервизор и его собственные системные процессы. То есть надо и им выдавать таймслоты и занимать в них некоторое количество pCPU. А что в это время делать нашей большой ВМ? Правильно, ожидать освобождения ВСЕХ pCPU, чтобы иметь возможность там уместиться. То есть мы гарантированно теряем производительность на служебных задачах гипервизора (таймслотах), а это плохо (вспоминаем пример выше с большой и малой машинами). Для примера, программный iSCSI инициатор под высокой нагрузкой потребляет до 6 ГГц процессорной мощности. Это было бы не так заметно в случае с малыми ВМ т.к. они работали бы параллельно служебным процессам (в этих же таймслотах). А для большой ВМ так не получится т.к. она занимает весь таймслот целиком, все его pCPU, и не может уместиться в таймслот, если хоть один его pCPU уже кем-то занят, пусть и системным процессом.
О каких потерях может идти речь при неправильном конфигурировании виртуальной инфраструктуры и размещении машин по нодам? От нуля до бесконечности (в теории). Все зависит от конкретной ситуации.

Отдельно хотелось бы озвучить главное правило при сайзинге виртуальных машин: давайте виртуальной машине МИНИМАЛЬНО возможные ресурсы, при которых она сможет выполнять свои задачи. Не нужно давать ВМ 2 ядра, если хватает одного. Не нужно давать 4, если хватает 2-х (лишние ядра занимают место в таймслоте). Аналогично с памятью, не стоит выдавать машине лишнего. Возможно, другой машине может не хватить, не говоря уже о возникающих проблемах с живой миграцией (по сути копированием объема памяти ВМ) и NUMA.

Теперь, разобравшись с механизмом размещения vCPU виртуальных машин на pCPU таймслота, давайте вспомним про NUMA и его правила размещения. Для шедулера гипервизора все эти правила имеют значение при заполнении таймслота т.к. pCPU таймслота могут относиться к разным NUMA нодам. Теперь, помимо сложностей учета NUMA при конфигурировании виртуальных машин на хосте, мы получили и ограничения, накладываемые методикой работы шедулера гипервизора с таймслотами. Если мы хотим получить хорошую производительность ВМ, нужно обращать внимание на все подводные камни и руководствоваться следующими правилами:

• Стараться не создавать машины-гиганты (по сравнению с размером хоста)
• Для больших машин надо учитывать ограничения, накладываемые технологией NUMA
• Не стоит злоупотреблять с количеством vCPU по отношению к pCPU хоста
• Несколько мелких или средних машин всегда будут иметь преимущество в гибкости и общей производительности перед огромными машинами

Напоследок хотелось бы сказать о работе шедулера гипервизора с вводом-выводом. При обращении виртуальной машины к своему виртуальному аппаратному обеспечению, гипервизор приостанавливает работу ВМ, снимает её с pCPU и ставит в хранилище WAIT. В таком состоянии машина не работает, она просто ждет. В это время гипервизор трансформирует («подделывает») команды виртуального устройства гостевой машины в реальные команды, соответствующие командам гипервизора, после чего гипервизор возвращает виртуальную машину в конвейер READY. Аналогичная «заморозка» виртуальной машины происходит и при ответе виртуального устройства машине (гипервизору необходимо снова трансформировать ответ, но уже в обратную сторону ). Чем больше команд ввода-вывода производит виртуальная машина, тем чаще она находится в «заморозке» WAIT, и тем меньше её производительность. Чем более «старые» виртуальные устройства ввода-вывода использует виртуальная машина, тем сложнее гипервизору трансформировать команды, и тем дольше ВМ находится в состоянии WAIT.

VMWare прямо и официально не рекомендует виртуализовывать приложения с гиперактивным вводом-выводом. Уменьшить негативное влияние от состояния WAIT можно с помощью использования паравиртуальных устройств для виртуальной машины. Это 10-гигабитная сетевая карта VMXNET3 и паравиртуальный SCSI контроллер жесткого диска PVSCSI. Так же уменьшению влияния WAIT и общему повышению производительности способствует применение в физических серверах аппаратных устройств, предназначенных для ускорения работы виртуальных машин. Это различные сетевые и HBA адаптеры с поддержкой аппаратного iSCSI offload, прямого доступа к памяти, сетевые карты с поддержкой виртуализации и т.д.

На этом я хотел бы остановиться. Надеюсь, информация в данной статье была вам интересна, и вы сможете более эффективно подойти к построению или эксплуатации своей виртуальной инфраструктуры.
Поделиться публикацией
Комментарии 19
    +1
    А как Relaxed Co-Scheduling вписывается в эту картину?
    Насколько я понимаю теперь в ESXi нету ограничений на то что все vCPU/worlds одной VM должны выполняться в том же таймслоте?
      0
      Relaxed Co-Scheduling в природе существует, но в данной статье осознанно не описан, дабы не путать читателей. Я опасался, что услышав про его существование, коллеги начнут уповать на него, и забудут про азы оптимизации конфигурации виртуальных машин.
      Механизм Relaxed Co-Scheduling является помощником, позволяющим ВОЗМОЖНО получить дополнительные проценты производительности. Но его вклад в общую картину может быть многократно нивелирован изначально неправильной конфигурацией.
        +2
        И зря не стали описывать. Запугали людей страшилками про таймслоты, а верный механизм, использующийся системой, не описали.
        Вышеописанная ситуация, когда машина ждёт, чтобы освободилось количество pCPU, соответствующее её количеству vCPU, подходит разве что под описание технологии Strict Co-Scheduling, которая имела место в ESX 2.x и то только при условии, что на всех vCPU синхронно исполняются какие-то процессы или многопоточное приложение. Даже в Strict Co-Scheduling, если из восьми процессоров задействовано только два, а остальные в Idle, то таймслоты получат только активные два.
        Начиная с ESX 3.x и выше, с технологией Relaxed Co-Scheduling гипервизор вообще жонглирует ядрами вплоть до того, что два vCPU могут попеременно получать один и тот же pCPU. То есть, если между vCPU случится рассинхронизация, то заморозится в ожидании только самый активный процессор, а не вся ВМ. Напомню, что на дворе уже ESX 5.5.
        Эта и другая информация есть в документе «The CPU scheduler in VMware vSphere 5.1» www.vmware.com/files/pdf/techpaper/VMware-vSphere-CPU-Sched-Perf.pdf

        Хотя совет выдавать виртуальной машине минимально достаточный объём ресурсов всё ещё актуален. В первую очередь из-за NUMA. А также из-за задержек миграции, как между ВМ хостами так и vCPU между ядрами.

        Ещё совет по конфигурированию виртуальных процессоров. Если ВМ конфигурируется с несколькими виртуальными процессорными ядрами в каждом виртуальном сокете, то число ядер в таком сокете должно быть равным или меньшим числу ядер в физическом сокете. Меньшим, причём, желательно делением на множитель. То есть, если в сокете 6 ядер, то в виртуальном сокете допустимо использовать 1, 2, 3, 6, но не 5 и не 8. А лучше вариант 1 сокет = 1 ядро, тогда гипервизор сам легко подстроится под NUMA.
          0
          Там не все так гладко, как вы описываете. Тогда можно было бы делать все виртуалки по 50 ядер и в ус не дуть. На практике все же лучше понимать причинно-следственные связи и не заставлять гипервизор выкручиваться, создавая ему изначально сложные условия. Как я уже говорил выше, Co-Scheduling скорее стоит воспринимать как дополнительную помощь в решении поставленной задачи, но никак не как основной механизм. У всего есть разумные пределы.
            +1
            Бесспорно стоит понимать и оптимизировать.
            Не так всё гладко, наверняка, но и не так ужасно, как может показаться (и, судя по комментариям, показалось некоторым) из вашей статьи.
            Co-Scheduling это именно основной механизм. Ну или особенность работы основного механизма (CPU Scheduler).
              0
              Давайте я найду время и проведу тесты. Мне самому интересно получить данные в конкретных цифрах. Планирую создать несколько виртуальных машин, в каждой из которых будет запущет некий тест производительности процессора, однопоточный. То есть грузить будет 1 ядро у ВМ. Допустим, возьмем 10-ядерный процессор, 2*Xeon E5 2690v2, есть у меня такие в наличии. И сначала сделаем 20 машин с 1 ядром, прогоним на них параллельно тест, потом сделаем 20 машин по 1 виртуальному сокету и 10 ядер, протестируем. И затем сделаем 20 машин, по 2 виртуальных сокета, и по 20 ядер каждая.
              Полагаю, что результат теста даст четкое понимание эффективности работы технологии Co-Scheduling. Если особой разницы в результатах не увидим, значит технология реально работает. А если увидим, значит её эффективность не ахти.

              Заодно результаты можно будет в статью добавить. Тогда и про Co-Scheduling напишу. Спасибо за идею :)
                0
                Хорошая мысль. Особенно если давать неравную нагрузку на процессоры. Ну то есть загружать 1-2 процессора в 4-8-процессорных ВМ.
      –2
      Хм; тот факт, что шедулер мапит физические ядра на виртуальные исключительно _целиком_, многое объясняет, почему на VMWare всё так тормозит обычно :))
        +1
        Ну, выше в каментах есть ссылка на технологию Relaxed Co-Scheduling, которая позволяет «расшаривать» физические ядра в таймслоте. Не все так ужасно :)
        А варя тормозит в основном из-за слабых систем хранения. По крайней мере практика показывает, что причины тормозов из-за СХД в 90% случаев.
        0
        У нас на курсах по vSphere преподаватель советовал отключать Hyperthreading.
          0
          Странный совет. У меня преподаватель (Мошков, учебный центр НР, Москва), не рекомендовал отключать. Как я уже писал выше, бонус от Hyperthreading может достигать 75%!!! Но это идеальный случай. В основном этот показатель держится в пределах 15...30%
            0
            Преподавателя не припомню, учебный центр Микроинформ Москва. 2012г. Курс авторизованный VS5-ICM, с бумажками от vmware.
            0
            В официальном мануале «Performance Best Practices for VMware vSphere #.#» (как минимум начиная с версии «5.0»), рекомендуют ВКЛЮЧАТЬ HT, если он поддерживается. В этом же мануале описывают причины, по которым это целесообразно сделать (в объяснении как раз речь про NUMA).

            PS: Спасибо автору за статью. В прочитанной мною различной документации по ESXi и его оптимизации, объяснения про «таймслоты» нигде не встречал. И спасибо за наводку на книжку «Михеева».
              0
              Internal testing shows that the recent generation of HT processors displays a higher performance gain from utilizing both logical processors. This means that the potential performance loss by letting some hyper-threads idle for a fairness reason becomes non trivial. This observation encourages a more aggressive use of partial cores in load balancing. A whole core is still preferred to a partial core as a migration destination; but if there is no whole core, a partial core is more likely to be chosen. This has been accomplished by two policy changes in vSphere 5.x.

              Внутренние тесты (VMware) показали, что HT-процессоры показывают большую производительность от использования обоих логических ядер. Это значит, что потенциальные потери производительности от ожидающих потоков можно считать несущественными. Это наблюдение привело к более агрессивной политике использования «частичных ядер» при балансировке нагрузки в VMware 5.x.
              0
              Да уж. Почерпнул так почерпнул. Если можете, напишите еще статей на эту тему. Наверняка это не все про ВМ.
              Поставил бы +1, кармы не хватает
                +1
                Скорее всего что-то еще напишу. Вроде бы основное уже написал. Остальное есть в книге Михеева по vSphere.
                +1
                Спасибо за статью!
                Как начинающий был удивлён таким азам.
                Пойду переделаю свой сервер для жолтой программы.
                22 отдам гостю и 2 останеться для его служебных ядер. Итого 1 таймслот и всё — правильно? (Больше гостей на хосте нет).
                  0
                  А вам очень нужно одну большую ВМ создать? Если так, то я бы сделать именно так, как вы написали. Ну, и количество виртуальных сокетов в конкретно вашем случае можно дать равным количеству физических сокетов (для NUMA). Если есть возможность разнести ваше приложение на несколько меньших ВМ — это был бы лучший выход.
                  0
                  Производители серверов любят включать в BIOS по умолчанию эмуляцию NUMA. То есть сервер представляется операционной системе как НЕ NUMA устройство, и vSphere не может использовать свою оптимизацию для управления данной технологией. В документации по vSphere рекомендуется отключать (Disable) данную опцию в BIOS, это позволяет vSphere самостоятельно разбираться с вопросом.


                  А можно поподробнее узнать, где именно это в документации написано. Вот тут например про заблуждение и пишет автор. habrahabr.ru/post/263777

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

                  Самое читаемое