Статьи

Совет по отладке: как смоделировать медленный хардиск

Как инженер-программист, бывают случаи, когда вам нужна более медленная система.

На самом деле это происходит не часто: обычно, когда кто-то сообщает об ошибке в вашем программном обеспечении, которую вы никогда раньше не видели и которую вы не можете воспроизвести.

В большинстве случаев причиной этих призрачных ошибок являются условия гонки .

Условия гонки — это проблемы, с которыми вы можете столкнуться при многопоточном программировании . Представьте, что ваше программное обеспечение делает несколько вещей одновременно. Несмотря на то, что в большинстве случаев эти вещи происходят в понятном и интуитивном порядке, иногда этого не происходит; приводя к неожиданному состоянию вашей программы.

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

Так почему медленная система помогает?

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

По моему опыту работы с Java-приложениями, основным аспектом, связанным с производительностью, при воспроизведении состояния гонки является скорость доступа к диску. Больше, чем скорость процессора или объем оперативной памяти, я заметил, что скорость диска — это самая большая разница между аналогичными системами.

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

Решение будет основано на nbd и trickle и будет использовать сетевой уровень для регулирования пропускной способности nbd для вашего виртуального жесткого диска.

Я хотел бы добавить, что в этом нет ничего нового, и что я не предлагаю какой-либо особенно революционный подход. Есть много постов, которые описывают, как этого добиться. Но по многим причинам ни одна из тех, что я прочитал, не работала из коробки на моих установках Fedora 22 или Centos 6.

Это главная причина, побудившая меня вернуться в Интернет , добавив, что может быть, просто еще одну страницу с аргументом.

Давайте начнем с идеи использования ndb или сетевого блочного устройства для имитации нашего жесткого диска.

Насколько я понимаю, нет никаких официальных способов, предоставляемых ядром Linux для регулирования скорости ввода-вывода типовых блочных устройств.

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

QoS может быть реализовано на сетевом уровне . Таким образом, идея состоит в том, чтобы эмулировать блочное устройство через сеть.

Несмотря на то, что это может показаться очень сложным (и, возможно, это так), проблема уже была решена ядром Linux с модулем nbd .

Поскольку на моей Fedora 22 этот модуль не включен автоматически по умолчанию, мы должны сначала установить его, а затем включить:

1
2
3
4
5
6
7
8
9
# install nbd module
sudo yum install ndb
 
# load nbd module
sudo modprobe nbd
 
# check nbd module is really loaded
lsmod | grep nbd
nbd                    20480  0

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

1
2
3
4
5
6
7
# run this command as root
"cat > /etc/nbd-server/config" <<EOF
[generic]
[test]
    exportname = /home/pantinor/test_nbd
    copyonwrite = false
EOF

Где exportname — это путь к файлу, который будет представлять ваш медленный виртуальный exportname .

Вы можете создать файл с помощью этой команды:

1
2
# create an empty file, and reserve it 1GB of space
dd if=/dev/zero of=/home/pantinor/test_nbd bs=1G count=1

Теперь, когда конфиг и файлы назначения на месте, вы можете запустить nbd-server с помощью демона:

1
2
3
4
5
# start ndb-server daemon
sudo systemctl start nbd-server.service
 
# monitor the daaemon start up with:
journalctl -f --unit nbd-server.service

На этом этапе у вас есть сетевой процесс сервера, прослушивающий порт 10809 которому может подключиться любой клиент вашей сети, чтобы смонтировать его как сетевое блочное устройство.

Мы можем смонтировать его с помощью этой команды:

1
2
3
4
# "test" corresponds to the configuration section in daemon  config file
sudo nbd-client -N test  127.0.0.1 10809  /dev/nbd0
# my Centos 6 version of nbd-client needs a slightly different synatx:
#    sudo nbd-client -N test  127.0.0.1   /dev/nbd0

Теперь мы создали виртуальное блочное устройство, которое называется /dev/nbd0 . Теперь мы можем отформатировать его так, как будто он был нормальным:

01
02
03
04
05
06
07
08
09
10
11
# format device
sudo mkfs /dev/nbd0
 
# create folder for mounting
sudo mkdir /mnt/nbd
 
# mount device, sync option is important to not allow the kernel to cheat!
sudo mount -o sync /dev/nbd0 /mnt/nbd
 
# add write permissions to everyone
sudo chmod a+rwx /mnt/nbd

Не то чтобы мы передали команду mount флаг -o sync . Эта команда выполняет важную функцию : отключить расширение ядра Linux, которое задерживает завершение операций записи на устройства. Без этого все операции записи будут выглядеть мгновенно, и ядро ​​фактически выполнит запросы записи в фоновом режиме. С этим флажком все операции будут ждать, пока операция действительно не завершится.

Вы можете проверить, что теперь вы можете читать и писать в точке монтирования /mnt/nbd .

Давайте теперь временно размонтировать и отключиться от nbd-server :

1
2
3
sudo umount /mnt/nbd
 
sudo nbd-client -d /dev/nbd0

И давайте введем trickle .

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

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

1
2
# download a sample file and limts download speed to 50 KB/s
trickle -d 50 -u 50  curl -O  http://download.thinkbroadband.com/5MB.zip

Теперь, как вы можете ожидать, нам просто нужно объединить поведение trickle и nbd-server , чтобы получить желаемое поведение.

Давайте начнем останавливать текущий nbd-server , чтобы освободить его порт по умолчанию:

1
sudo systemctl stop nbd-server.service

И давайте начнем с помощью trickle :

1
2
# start nbd-server limiting its network throughput
trickle -d 20 -u 20 -v nbd-server -d

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

Не обращайте внимания на сообщение об ошибке: trickle: Could not reach trickled, working independently: No such file or directory

Теперь вы можете повторно выполнить команды для подключения к nbd-server и заново смонтировать его:

1
2
3
sudo nbd-client -N test  127.0.0.1 10809  /dev/nbd0
 
sudo mount -o sync /dev/nbd0 /mnt/nbd

И вы сделали! Теперь у вас есть медленный /dev/nbd0 смонтированный в /dev/nbd0 .

Вы можете проверить медленное поведение следующим образом:

1
2
3
4
5
6
7
sudo dd if=/dev/nbd0 of=/dev/null bs=65536 skip=100 count=10
10+0 records in
10+0 records out
655360 bytes (655 kB) copied, 18.8038 s, 34.9 kB/s
 
# when run against an nbd-server that doesn't use trickle the output is:
# 655360 bytes (655 kB) copied, 0.000723881 s, 905 MB/s

Теперь, когда у вас медленный раздел, вы можете просто поместить туда файлы вашего sw, чтобы имитировать медленный ввод / вывод.

Все вышеперечисленные шаги можно преобразовать в вспомогательные сценарии, которые значительно упростят процесс, подобный описанным здесь: http://philtortoise.blogspot.it/2013/09/simulation-slow-drive.html .