\section{Приоритезация ввода/вывода в Xen}

\subsection{Приоритеты для использования Disk I/O}
\subsubsection{ionice}
С выходом CFQ v3 в Linux 2.6.13 появилась возможность выставлять приоритеты использования дисковой подсистемы для процессов, чего раньше так не хватало. Подобно утилите \textbf{nice}, предназначенной для назначения приоритетов использования процессора, появилась утилита \textbf{ionice}, назначает для процессов приоритеты ввода/вывода. 

Синтаксис команды прост:

\begin{verbatim}
ionice -c класс -n приоритет -p PID
\end{verbatim}

Класс:

\begin{itemize}
\item  3 (Idle) — Получает приоритет на использование жесткого диска только когда другие программы ничего не пишут. Приоритеты не используются.
\item  2 (Best Effort) — Класс по умолчанию. Доступные приоритеты [0-7].
\item  1 (Real Time) — Даёт преимущественный доступ к диску процессу, несмотря на другие процессы. Доступные приоритеты [0-7].
\end{itemize}

Подробнее: man ionice

\subsubsection{Приоритеты ввода/вывода гостевых доменов Xen}
После запуска гостевых систем по \textbf{ps} \texttt{aux} можно видеть в квадратных скобках появившиеся драйвера блочных устройств xvd, после которых указан 
ID гостевого домена. Приоритеты для этих процессов можно устанавливать
с помощью \textbf{ionice}, точно также как и для всех остальных.

\begin{verbatim}
$ ps aux | grep xvd
root       616  0.0  0.0      0     0 ?        S<   16:05   0:00 [xvd 1 07:00]
igor       773  0.0  0.0   3892   764 pts/0    R+   16:08   0:00 grep xvd
\end{verbatim}

Изменение приоритета ввода/вывода нужно выполнять для процесса 616.

Аналогичным образом можно выполнять и приоритезацию 
ввода/вывода для HVM-доменов, 
только для этого нужно применять 
\textbf{ionice} к процессам \textbf{qemu-dm}, 
работающим в домене 0.

\begin{verbatim}
$ ps aux | grep qemu-dm
root       645  8.3  0.1  27272  2400 ?        Sl   16:05   0:09 /usr/lib/xen-3.2-1/bin/qemu-dm -d 2 -domain-name winxp-hdd ...
igor       769  0.0  0.0   3888   764 pts/0    R+   16:07   0:00 grep qemu-dm
\end{verbatim}

\subsubsection{Эксперименты}
Проведём 2 эксперимента для операций чтения и записи.

Выставим одной гостевой системе класс \textit{Real Time}, а второй — \textit{Idle}.

Запустим одновременно \textit{dd} на обеих системах для записи небольшого файла. Конечно слово «одновременно» здесь весьма условно.
Для повышения точности лучше провести несколько измерений.

\begin{verbatim}
%# dd if=/dev/zero of=/root/file.txt bs=1024 count=10240000
\end{verbatim}

В результате средняя скорость в первой гостевой системе -- 40Mb/sec, во второй -- 20Mb/sec.

Другим экспериментом является операция тестирования скорости чтения диска с помощью \textit{hdparm}:

\begin{verbatim}
%# hdparm -t /dev/xvda
\end{verbatim}

В результате в первом гостевом домене скорость — 25Mb/sec, во втором — 2Mb/sec.

\subsubsection{Заключение}
Недостатком данного решения является отсутствие соответствующих опций в конфигурационном файле гостевых доменов Xen,
что означает, что при каждом старте домена необходимо устанавливать его приоритет заново.

Следует обратить внимание, что данная возможность доступна только для CFQ.

Проверьте, какой способ приоритезации используется:

\begin{verbatim}
cat /sys/block/ИМЯ_ДИСКА/queue/scheduler
\end{verbatim}

Название активного планировщика должно быть в квадратных скобках.
Например:

\begin{verbatim}
$ cat /sys/block/sda/queue/scheduler 
noop anticipatory deadline [cfq]
\end{verbatim}


\subsection{Приоритезация ввода/вывода с помощью dm-band}

\textbf{dm-band} — драйвер операционной системы Linux, позволяющий управлять скоростью работы с блочными устройствами. Предназначен для использования в виртуализированной среде и с группами процессов (cgroups). В настоящее время dm-band работает как драйвер device-mapper.

\subsubsection{Что такое dm-band}
\textbf{dm-band} — это контроллер, регулирующий полосу пропускания при выполнении операций ввода/вывода с блочным устройством,
реализованный как драйвер device-mapper.
Несколько работ, использующих одно физическое устройство,
должны делить между собой его полосу пропускания.
\textbf{dm-band} выделяет каждой работе полосу пропускания в соответствии
с её весом, который может задаваться административно.

В настоящее время работой (job) может быть группа процессов с одинаковым
идентификатором pid, pgrp или uid. 
В будущем планируется сделать поддержку cgroup. 
Работой также может быть виртуальная машина Xen или KVM.

\begin{verbatim}
# dmsetup message band1 0 weight 40
# dmsetup message band2 0 weight 10
\end{verbatim}

\subsubsection{Как работает dm-band}
У каждого band-устройства есть как минимум одна его группа, 
которая по умолчанию так и называется — default group.

Band-групп у устройства может быть и несколько.
У каждой band-группы есть (1) вес и (2) закреплённая за ней работа.
\textbf{dm-band} выделяет маркеры группе пропорционально её весу.

Если у группы есть в запасе маркеры, запрос ввода/вывода, сделанный
её работой, передаётся ниже.
Если же маркеров у группы не осталось, обращение блокируется.
Когда группа делает запрос ввода/вывода, она тратит один маркер.
Когда маркеры заканчиваются у всех групп,
работающих с данным устройством, \textbf{dm-band} пополняет их запас.

При таком подходе работа, закреплённая за band-группой с большим весом,
гарантированно получит возможность сделать большее количество
запросов ввода/вывода.

Полоса пропускания (bandwidth) в \textbf{dm-band} определяется
как отношение времени обработки маркеров данного устройства
к времени обработки маркеров всех устройств.
Время обработки маркера определяется длительностью цикла
ввода/вывода, включающим время поиска (seek latency), задержку
на обработку прерывания (interrupt latency) и прочее.

\subsubsection{Как его использовать}
Ниже показано как управлять полосой пропускания при доступе 
к дискам. В примере используется один диск с двумя разделами.

Более подробная информация представлена в
документации на ядро Linux, в файле \texttt{Document/device-mapper/band.txt}.

\paragraph{Создание и привязка band-устройств}
Нужно создать два band-устройства \texttt{band1} и \texttt{band2} и привязать их к разделам
\texttt{/dev/sda1} и \texttt{/dev/sda2} соответственно:
\begin{verbatim}
 # dmsetup remove band1
 # dmsetup remove band2
\end{verbatim}

Если команды выполнятся успешно,
будут созданы новые файлы устройств \texttt{/dev/mapper/band1} и \texttt{/dev/mapper/band2}.

\paragraph{Управление полосой пропускания}
Назначим \texttt{band1} и \texttt{band2} веса 40 и 10 соответственно:

\begin{verbatim}
# dmsetup message band1 0 weight 40
# dmsetup message band2 0 weight 10
\end{verbatim}

После этих команд \texttt{band1} сможет использовать 80\% — 40/(40+10)\(\ast{}\)100 —
полосы пропускания к физическому диску \texttt{/debv/sda}, 
а \texttt{band2} — оставшиеся 20\%.

\paragraph{Дополнительные возможности}
В этом примере будут созданы две дополнительные band-группы для \texttt{band1}.
В первую группу входят все процессы с user-id 1000,
а во вторую — процессы с user-id 2000.
Их веса соответственно 30 и 20. 

Сначала тип band-групп \texttt{band1} устанавливается равным \texttt{user}.
Затем группы с user-id 1000 и 2000 присоединяются к \texttt{band1}.
И последнее, назначаются веса для групп с user-id 1000 и 2000.

\begin{verbatim}
# dmsetup message band1 0 type user
 # dmsetup message band1 0 attach 1000
 # dmsetup message band1 0 attach 2000
 # dmsetup message band1 0 weight 1000:30
 # dmsetup message band1 0 weight 2000:20
\end{verbatim}

Теперь процессы в группе с user-id 1000
могут использовать 30\% — 30/(30+20+40+10)\(\ast{}\)100 —
доступной физической полосы пропускания диска.

\begin{verbatim}
Band Device    Band Group                     Weight
  band1         user id 1000                     30
  band1         user id 2000                     20
  band1         default group(the other users)   40
  band2         default group                    10
\end{verbatim}

\paragraph{Удаление band-устройств}
Удалить band-устройства, которые больше не используются,
можно так:

\begin{verbatim}
 # dmsetup remove band1
 # dmsetup remove band2
\end{verbatim}

\subsubsection{Планы на будущее}
Что можно было бы сделать в будущих версиях:
\begin{itemize}
\item  Добавить поддержку Cgroup;
\item  Управлять скоростью записи и чтения по отдельности;
\item  Добавить поддержку WRITE\_BARRIER;
\item  Оптимизировать;
\item  Добавить дополнительные инструменты для настройки (или хватит одного \textbf{dmsetup}?);
\item  Создать новые политики планировщика BIOs (или достаточно уже существующей, весовой?).
\end{itemize}

\subsubsection{Замеры}
Ниже представлены результаты замеров, которые выполнил разработчик \textbf{dm-band}, Ryo Tsuruta.
Они подтверждают то, что \textbf{dm-band} работает так, как и ожидалось.
В ходе экспериментов создаётся несколько band-групп на нескольких физических разделах
и выполняется интенсивный ввод/вывод на эти устройства.

\paragraph{Железо для испытаний}

\begin{verbatim}
DELL Dimention E521:

  Linux kappa.local.valinux.co.jp 2.6.23.14 #1 SMP
    Thu Jan 24 17:24:59 JST 2008 i686 athlon i386 GNU/Linux
  Detected 2004.217 MHz processor.
  CPU0: AMD Athlon(tm) 64 X2 Dual Core Processor 3800+ stepping 02
  Memory: 966240k/981888k available (2102k kernel code, 14932k reserved,
    890k data, 216k init, 64384k highmem)
  scsi 2:0:0:0: Direct-Access     ATA      ST3250620AS     3.AA PQ: 0 ANSI: 5
  sd 2:0:0:0: [sdb] 488397168 512-byte hardware sectors (250059 MB)
  sd 2:0:0:0: [sdb] Write Protect is off
  sd 2:0:0:0: [sdb] Mode Sense: 00 3a 00 00
  sd 2:0:0:0: [sdb] Write cache: enabled, read cache: enabled,
    doesn't support DPO or FUA
  sdb: sdb1 sdb2 < sdb5 sdb6 sdb7 sdb8 sdb9 sdb10 sdb11 sdb12 sdb13 sdb14
    sdb15 >
\end{verbatim}

\paragraph{Результаты тестирования управления полосой пропускания для разделов}
Конфигурация для эксперимента \#1:
\begin{itemize}
\item  Создать три раздела \texttt{sdb5}, \texttt{sdb6} и \texttt{sdb7}.
\item  Назначить веса 40, 20 и 10 соответственно для \texttt{sdb5}, \texttt{sdb6} и \texttt{sdb7}.
\item  Запустить 128 процессов, выполняющих одновременно случайные операции прямого чтения и прямой записи блоков размером 4KB
\item  Подсчитать количество выполненных операций в течение 60 секунд.
\end{itemize}

\begin{verbatim}
результат эксперимента #1
 ---------------------------------------------------------------------------
|     device      |       sdb5        |       sdb6        |      sdb7       |
|     weight      |    40 (57.0%)     |     20 (29.0%)    |    10 (14.0%)   |
|-----------------+-------------------+-------------------+-----------------|
|   I/Os (r/w)    |  6640( 3272/ 3368)|  3434( 1719/ 1715)|  1689( 857/ 832)|
|  sectors (r/w)  | 53120(26176/26944)| 27472(13752/13720)| 13512(6856/6656)|
|  ratio to total |       56.4%       |       29.2%       |      14.4%      |
 ---------------------------------------------------------------------------
\end{verbatim}

Конфигурация для эксперимента \#2:
\begin{itemize}
\item  в точности такая же как для эксперимента \#1, за исключением того, что не запускаются процессы, работающие с \texttt{sdb6}
\end{itemize}

\begin{verbatim}
результаты эксперимента #2
 ---------------------------------------------------------------------------
|     device      |       sdb5        |       sdb6        |      sdb7       |
|     weight      |    40 (57.0%)     |     20 (29.0%)    |    10 (14.0%)   |
|-----------------+-------------------+-------------------+-----------------|
|   I/Os (r/w)    |  9566(4815/  4751)|     0(    0/    0)|  2370(1198/1172)|
|  sectors (r/w)  | 76528(38520/38008)|     0(    0/    0)| 18960(9584/9376)|
|  ratio to total |       76.8%       |        0.0%       |     23.2%       |
 ---------------------------------------------------------------------------
\end{verbatim}

\paragraph{Результаты тестирования управления полосой пропускания для band-групп}
Конфигурация для эксперимента \#3:
\begin{itemize}
\item  Создать два раздела \texttt{sdb5} и \texttt{sdb6}
\item  Создать две дополнительные band-группы на \texttt{sdb5}, первая для \texttt{user1} и вторая для \texttt{user2}.
\item  Назначить веса 40, 20, 10 и 10 для band-групп \texttt{user1}, \texttt{user2}, default-групп разделов \texttt{sdb5} и \texttt{sdb6} соответственно
\item  Запустить 128 процессов, выполняющих одновременно случайные операции прямого чтения и прямой записи блоков размером 4KB
\item  Подсчитать количество выполненных операций в течение 60 секунд.
\end{itemize}

\begin{verbatim}
результаты эксперимента #3
 ---------------------------------------------------------------------------
|dev|                          sdb5                        |      sdb6      |
|---+------------------------------------------------------+----------------|
|usr|     user1        |      user2       |  other users   |   all users    |
|wgt|   40 (50.0%)     |    20 (25.0%)    |   10 (12.5%)   |   10 (12.5%)   |
|---+------------------+------------------+----------------+----------------|
|I/O| 5951( 2940/ 3011)| 3068( 1574/ 1494)| 1663( 828/ 835)| 1663( 810/ 853)|
|sec|47608(23520/24088)|24544(12592/11952)|13304(6624/6680)|13304(6480/6824)|
| % |     48.2%        |       24.9%      |      13.5%     |      13.5%     |
 ---------------------------------------------------------------------------
\end{verbatim}

Конфигурация для эксперимента \#4:
\begin{itemize}
\item  в точности такая же как для эксперимента \#3, за исключением того, что не запускаются процессы, работающие с band-группой \texttt{user2}
\end{itemize}

\begin{verbatim}
результаты эксперимента #4
 ---------------------------------------------------------------------------
|dev|                          sdb5                        |     sdb6       |
|---+------------------------------------------------------+----------------|
|usr|     user1        |      user2       |  other users   |   all users    |
|wgt|   40 (50.0%)     |    20 (25.0%)    |   10 (12.5%)   |   10 (12.5%)   |
|---+------------------+------------------+----------------+----------------|
|I/O| 8002( 3963/ 4039)|    0(    0/    0)| 2056(1021/1035)| 2008( 998/1010)|
|sec|64016(31704/32312)|    0(    0/    0)|16448(8168/8280)|16064(7984/8080)|
| % |     66.3%        |        0.0%      |      17.0%     |      16.6%     |
 ---------------------------------------------------------------------------
\end{verbatim}

\paragraph{Выводы}
\textbf{dm-band} работает хорошо при выполнении случайных операций чтение/запись.
В будущем планируется провести тестирование на 
реальных приложениях, таких как СУБД и файловые серверы.

\subsubsection{Почему нельзя было просто доработать CFQ?}
В Linux есть механизмы для приоритезации дискового ввода/вывода.
Почему нельзя было использовать их?

Ниже перевод письма одного из соавторов dm-band Хироказу Такаши (Hirokazu Takashi)
в список рассылки Xen-devel\url{http://lists.xensource.com/archives/html/xen-devel/2008-01/msg00852.html}, 
в котором он отвечает на этот вопрос.

\begin{verbatim}
From: Hirokazu Takahashi <taka@valinux.co.jp>

Доработать стандартный планировщик ввода/вывода, который есть в ядре,
это самый простой подход. Действительно, планировщик CFQ
можно было бы научить управлять полосой пропускания путём 
относительного небольшой модификации кода.
Оба подхода (использовать device-mapper и модифицировать CFQ)
имеют свои плюсы и минусы.

В настоящее время мы выбрали вариант с device-mapper по следующим причинам:
* он может работать с любым планировщиком. Некоторые хотят использовать планировщик NOOP
  для работы с high-end хранилищами;
* его должны использовать только те, кому нужно управление пропускной способностью I/O;
* он независим от других планировщиков и его легко поддерживать;
* не усложняется сопровождение CFQ.

У сегодняшней реализации планировщика CFQ есть некоторые ограничения,
которые мешают использовать его для управления полосой пропускания так,
как хотелось бы. У планировщика есть только 7 уровней приоритета,
что означает, что у него есть только 7 классов ввода/вывода.
Если назначить один и тот же приоритет A нескольким виртуальным машинам,
эти машины должны будут поровну делить полосу ввода/вывода,
выделенную классу A. Если при этом есть машина, работающая с приоритетом B, 
более низким чем A, и она такая одна, может так получится, что у неё будет
большая полоса пропускания чем у машин класса A.

Вообще, я думаю, что нужно чтобы в CFQ был планировщик с двумя уровнями.
Один уровень используется для выбора лучшей группы cgroup или работы (job),
а второй — для выбора класса с наивысшим приоритетом ввода/вывода.

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

У подхода с использованием device-mapper тоже есть свои минусы.
Сложно получить информацию о возможностях и конфигурации нижележащих устройств, 
такую, например, как информацию о разделах и LUN. И возможно, потребуется разрабатывать 
дополнительные инструменты для настойки.
\end{verbatim}

\subsection{Дополнительная информация}
\begin{itemize}
\item \htmladdnormallinkfoot{Приоритезация ввода/вывода в Xen с помощью планировщика CFQ}{http://xgu.ru/wiki/xen/io} (рус.)
\item \htmladdnormallinkfoot{Приоритезация ввода/вывода с помощью dm-band}{http://xgu.ru/wiki/dm-band} (рус.)
\end{itemize}
