FreeBSD ZFS performance: просто возьмите молоток побольше

Если поискать в этом блоге, особенно в каментах, то найдете что ZFS на трех дисках (RAIDZ) давала у меня скорость чтения/записи порядка 75-80 Mb/sec. Так оно и было до недавнего времени, пока я с этой скоростью не уперся в скорость на сети (samba).

Пришлось навести следствие. Выяснилось очень простое, хотя и не вполне очевидное:

  • У меня был даунклоченый Core2Duo: 1.86Ghz работающий на ~1.6, задаунклочил летом, по случаю жары, просто на всякий случай.
  • При этом при чтении с ZFS system time как правило не рос выше 50%, что я неверно интерпретировал как однопоточность ZFS (судя по всему, неверно, ибо потом в тестах видел и 70% system) и верно интерпретировал как упертость в процессор.
  • Банальный оверклок того же горшка (и памяти) приводил к почти линейному росту скорости FS.

Тогда я пошел в лабаз и купил там еще один 2TB диск и 3.06-гигагерцовый C2D (E7600), собрал все в кучку (дисков стало 4) и результат:

  • 170-195 Mb/sec на запись
  • 230-280 Mb/sec на чтение
Скорость, судя по всему, зависит от того, в какую зону диска, побыстрее или помедленнее, файловая система положила файл. System при этом держится на уровне 20-30%, а изменение частоты горшка на производительность почти не влияет. Ну и Samba в диск больше не упирается.

Все тестирование делалось методом

dd if=/dev/zero of=file bs=1M count=20000
dd if=file of=/dev/null bs=1M
То есть речь о больших файлах, с мелкими всегда все сложнее и хуже.

Заодно поисследовал другую проблему. У меня три диска WD20EADS (которые Caviar Green, медленные и холодные), а четвертым к ним я купил WD20EARS. Этот четвертый - он с 4-килобайтными секторами, но наружу рапортует про 512 байт на сектор.

Есть мнение(tm), что такое поведение с секторами - очень плохо для ZFS. Допустим, оно хочет записать туда 4 килобайта, выровненые на 512: с вероятностью 7/8 диск сделает чтение двух секторов, поапдейтит нужные куски и запишет, что конечно медленнее, чем просто попасть в 4k-сектор.

Про эту фишку исписана уже половина интернета (и проблема не только с ZFS, но и со многими другими FS), но вот то что я вижу у себя выглядит гораздо лучше. Допустим, мы собираем массив так:

zpool create pool raidz disk1-512 disk2-512 disk3-512 disk4-4k
естественно, разделы под ZFS на всех четырех дисках выровняны на 4k (8 секторов), уж по этим граблям глупо было бы ходить.

После этого мы нагружаем диск какой-то длинной записью (dd if=/dev/urandom of=/pool/file) и смотрим на нагрузку через systat -vm. На первой сотне гигабайт записи 4-й диск действительно оказывается перегружен, у него и очередь подлиннее и busy time побольше....

Пересобираем массив иначе:

zpool create pool raidz disk1-512 disk4-4k disk2-512 disk3-512 
И при том же паттерне нагрузки наиболее загруженным оказывается уже disk3.

Если же налить на FS побольше данных и опять начать писать длинный файл - загрузка по дискам оказывается просто примерно одинаковой, никаких признаков тормозов на 4-к-секторном диске нету.

Естественно, я пробовал поиграться и с ashift, к сожалению ZFS-ные бут-блоки от FreeBSD не сумели загрузиться с тома с ashift=12, городить же отдельную /boot FS на флэшке мне откровенно мучительно.

Comments

Я вот чего-то не понимаю, -512 и -4k - это твои маркера, чтобы в дисках не запутаться, или это такие специальные хаки для zfs, чтобы она понимала, какой размер?

Это мои маркера, причем только для ясности изложения.

Ага, я на это надеялся. Тогда следующий вопрос - как понимать фразу про выравнивание разделов? У тебя zpool собирается не из дисков целиком, что ли?

Нет, там же еще раздел на котором загрузчик лежит.

Т.е.
gpart create -s GPT $disk
gpart add -s 134 -t freebsd-boot $disk
gpart add -t freebsd-zfs $disk

И так по всем четырем дискам. А 134 - это магическое число (вместо обычных 128) которое и дает нужное выравнивание:
gpart list ada0
...
2. Name: ada0p2
...
offset: 86016 (== 21x4096)

А, тогда понятно.

Вопрос в том, что будет, если отдать zfs такие диски целиком (вперемешку).

Если целиком, т.е. загрузчик еще где-то, то можно и ashift=12 поставить и тогда вообще все должно быть хорошо.

Это без пересборки системы-то можно сделать?

Надо только zpool пересобрать. Там (по ссылке выше, из поста) патч на одну строчку, в создание тома передается дополнительный атрибут и все.

Т.е. все уже предусмотрено внутри, но не подперто утилитами.

Но - я никакой значимой разницы не увидел и с 4к-блоками (ashift=12) при наливке первых сотен гигабайт на том больше всего занят 4-й диск из четырех, независимо от того, какие у него внутри секторы.

А если типа так:

gpart create -s gpt ada0
gpart add -a 4k -s 128k -t freebsd-boot ada0
gpart add -a 4k -s 40g -t freebsd-zfs -l system0 ada0
gpart add -a 4k -t freebsd-zfs -l data0 ada0

gpart show ada0
=> 34 3907029101 ada0 GPT (1.8T)
34 6 - free - (3.0K)
40 256 1 freebsd-boot (128K)
296 83886080 2 freebsd-zfs (40G)
83886376 3823142752 3 freebsd-zfs (1.8T)
3907029128 7 - free - (3.5K)

man gpart:

...[-b start] [-s size]...

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

В принципе, в интернете рекомендуют делать отступ в 2048 секторов. Так делает и Windows7, кстати.

Какой смысл иметь два ZFS-тома на одном диске? Чтобы грузиться?

В разных источниках разные магические числа, однако -s это размер:
gpart add -t type [-a alignment] [-b start] [-s size] [-i index]
Одни так
gpart add -b 40 -s 1024 -t freebsd-boot $dev
другие так
gpart add -b 34 -s 94 -t freebsd-boot ada0
жесть ...

Так для freebsd-boot никакой особой разницы нет, куда и как, главное чтобы влезал. gptzfsboot в 9.1 имеет размер 40499, 80 секторов по 512 хватит.

Это в какой системе счисления ? 94+80=174 а не 134 ...

-s - это size.
И 90 хватит и 1024

Ну как так можно
Все тестирование делалось методом
dd if=/dev/zero of=file bs=1M count=20000
dd if=file of=/dev/null bs=1M
ну вы же знаете что zfs одинаковые блоки записывает только раз тоесть компрессия встроенна !!!
нужно

dd if=/dev/random

а насчет настроек было интересно почитать, правда пока не ясно что с выравниваниями под 512 и под 4 или сколько там в современных дисках, нужно ли их делать или они делаются в gpt ...

deduplication - нету. И если смотреть iostat, то видно что на диски таки пишется, а не непишется.

А urandom дает на этой машине 60Mb/sec, больше не может.

А есть практический опыт использования zfs ? Интерисует связка ZFS с MySQL с deduplication или без, диски брать с 512 или 4к и нужно ли SSD под кеш ?

4k-диски - это же от 2Tb и более? Вы на сколько терабайт базу MySQL собрались делать?

Сейчас все новые диски идут 4к а в рейд думаю WD5003ABYX так как по цене альтенатив все равно нет. В любом случае с 512 нужно делать выравнивание ? Их почти не осталось в продаже :( Скорее всего придется брать WD2003FYYS немогу нагуглить какие там кластеры но он SATA2.

Теперь, когда из Оракла ушло большинство инженеров высшего класса,
которые и двигали Sun вперёд, судьба zfs несколько туманна и в целом, и особенно bsd-версии, Оракл очень любит всё закрывать.

28-ю версию, как я понимаю, доимпортят.

А дальше да, судьба туманна.

Я провёл у себя на сервере (Celeron3300, 2Gb RAM, 4xWD 20EARS, 4xSamsung HD204UI) тестирование ZFS, после того как обнаружил, что RAID10 из ZFS показывает скорость чтения всего около...80Мбайт/сек.
Для этого на уже работающем сервере протестировал все варианты ZFS и UFS через gpart и gnop, то есть:

1. Один диск
UFS
1.1. GPT -b 34
1.2. GPT -b 34 и GNOP -S 512
1.3. GPT -b 34 и GNOP -S 4096
1.4. GPT -b 2048
1.5. GPT -b 2048 и GNOP -S 512
1.6. GPT -b 2048 и GNOP -S 4096
ZFS
2.0. Whole ZFS w/o GPT и GNOP
2.1. GPT -b 34
2.2. GPT -b 34 и GNOP -S 512
2.3. GPT -b 34 и GNOP -S 4096
2.4. GPT -b 2048
2.5. GPT -b 2048 и GNOP -S 512
2.6. GPT -b 2048 и GNOP -S 4096

Тестировал через dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000, цикл из пяти раз, результаты усреднил. Получил следующие цифры, "запись/чтение", в Мбайт/сек соответственно:

UFS:
1.1. 103/109
1.2. 105/106
1.3. 107/107
1.4. 115/106
1.5. 118/105
1.6. 118/109

ZFS:
2.0. 23/57
2.1. 25/57
2.2. 20/54
2.3. 19/54
2.4. 17/53
2.5. 17/53
2.6. 21/53

Тюнил предлагаемые различные параметры vfs.zfs и vmem size, скорости у массива ZFS не изменялись практически, так что думаю, и для одиночного диска не изменились бы (просто уже не стал это проверять).
В чём проблема, не знаю, но это чудовищно.

P.S. Ещё два интересных вывода:
1. Использование GPT с выровненными разделами и GNOP с любым размером блока ведёт к увеличению скорости записи на 12%
2. ZFS наоборот, НЕ любит GPT с выровненными разделами и GNOP.

Забыл уточнить: ZFS RAID10 составлен из WD 20EARS, а тестировал я одиночный диск Samsung серии F4.

benchmark.1.1.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -s 20G -t freebsd-ufs -l benchmark $1 && \
newfs -O2 -U /dev/gpt/benchmark && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gpart delete -i 1 $1 && gpart destroy $1

benchmark.1.2.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -s 20G -t freebsd-ufs -l benchmark $1 && \
gnop create -v /dev/gpt/benchmark
newfs -O2 -U /dev/gpt/benchmark.nop && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark.nop /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark.nop
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop && gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.1.3.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -s 20G -t freebsd-ufs -l benchmark $1 && \
gnop create -v -S 4096 /dev/gpt/benchmark
newfs -O2 -U /dev/gpt/benchmark.nop && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark.nop /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark.nop
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop && gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.1.4.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
newfs -O2 -U /dev/gpt/benchmark && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark && gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.1.5.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
gnop create -v /dev/gpt/benchmark
newfs -O2 -U /dev/gpt/benchmark.nop && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark.nop /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark.nop
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.1.6.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
gnop create -v -S 4096 /dev/gpt/benchmark
newfs -O2 -U /dev/gpt/benchmark.nop && \
if [ ! -d '/mnt/benchmark' ]; then
mkdir -p /mnt/benchmark
fi

echo '
#Do testing
'
for i in 1 2 3 4 5; do
mount /dev/gpt/benchmark.nop /mnt/benchmark
if [ `mount | grep -c benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
umount /mnt/benchmark
done

echo '
#Print out system info
'
dumpfs -m /dev/gpt/benchmark.nop
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Cleanup
'
rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.0.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
#zpool create -m /mnt/benchmark samsung /dev/$1 || exit 1
#if [ ! -d '/mnt/benchmark' ]; then
# mkdir -p /mnt/benchmark
#fi

#ln -fhs /samsung/benchmark/ /mnt/benchmark/

echo '
#Do testing
'
for i in 1 2 3 4 5; do
zpool create -m /mnt/benchmark samsung /dev/$1 || exit 1
# zfs create -V 20G samsung/benchmark || exit 1
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
echo "Benchmark FS doesn't mounted or mounted incorrectly. Quit."
exit 1
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
# zfs delete samsung/benchmark || exit 1
zpool destroy samsung
done

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
#gnop list
#gpart show -l $1
#gpart list $1
#smartctl -a /dev/$1
camcontrol identify $1

echo '
#Cleanup
'
rmdir /mnt/benchmark
zpool destroy samsung
#gnop destroy /dev/gpt/benchmark.nop
#gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.1.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
#gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
#gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark || exit 1
#if [ ! -d '/mnt/benchmark' ]; then
# mkdir -p /mnt/benchmark
#fi

#ln -fhs /samsung/benchmark/ /mnt/benchmark/

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
#gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
#gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.2.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
#gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
gnop create -v /dev/gpt/benchmark
#gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop || exit 1
#if [ ! -d '/mnt/benchmark' ]; then
# mkdir -p /mnt/benchmark
#fi

#ln -fhs /samsung/benchmark/ /mnt/benchmark/

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
zpool get all samsung
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.3.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
#gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
#gnop create -v /dev/gpt/benchmark
gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop || exit 1
#if [ ! -d '/mnt/benchmark' ]; then
# mkdir -p /mnt/benchmark
#fi

#ln -fhs /samsung/benchmark/ /mnt/benchmark/

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
zpool get all samsung
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.4.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
#gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
#gnop create -v /dev/gpt/benchmark
#gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark || exit 1

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
zpool get all samsung
#gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
#gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.5.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
#gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
gnop create -v /dev/gpt/benchmark
#gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop || exit 1

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
zpool get all samsung
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

benchmark.2.6.sh

#!/bin/sh
# $1 - disk_name
# mount to /mnt/benchmark

echo '
#Create FS
'
if [ `gpart show $1 2>&1 | grep -c 'No such geom'` -ne 1 ]; then
echo "Some gpart already exists, quit"
exit 1
fi
gpart create -s GPT $1 && \
gpart add -b 2048 -s 20G -t freebsd-ufs -l benchmark $1 && \
#gpart add -s 20G -t freebsd-zfs -l benchmark $1 && \
#gnop create -v /dev/gpt/benchmark
gnop create -v -S 4096 /dev/gpt/benchmark
#newfs -O2 -U /dev/gpt/benchmark.nop && \

zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop || exit 1

echo '
#Print out system info
'
zfs get all samsung
zfs list -r samsung
zpool status -v samsung
zpool get all samsung
gnop list
gpart show -l $1
gpart list $1
smartctl -a /dev/$1
camcontrol identify $1

echo '
#Do testing
'
for i in 1 2 3 4 5; do
if [ `mount | grep -c "/mnt/benchmark` -ne 1 ]; then
zpool create -m /mnt/benchmark samsung /dev/gpt/benchmark.nop
fi
cmd='time -l sh -c "dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000 && fsync /mnt/benchmark/zero.4G"'
echo "$i: "$cmd
echo $cmd | sh
cmd="time -l dd if=/mnt/benchmark/zero.4G of=/dev/null"
echo "$i: "$cmd
echo $cmd | sh
zpool destroy samsung
done

echo '
#Cleanup
'
#rmdir /mnt/benchmark
gnop destroy /dev/gpt/benchmark.nop
gpart delete -i 1 /dev/$1 && gpart destroy /dev/$1

Информация о диске:

pass5: ATA-8 SATA 2.x device
pass5: 300.000MB/s transfers (SATA 2.x, UDMA6, PIO 8192bytes)

protocol ATA/ATAPI-8 SATA 2.x
device model SAMSUNG HD204UI
firmware revision 1AQ10001
serial number S2H7JD2Z903729
WWN 50024e90415d988
cylinders 16383
heads 16
sectors/track 63
sector size logical 512, physical 512, offset 0
LBA supported 268435455 sectors
LBA48 supported 3907029168 sectors
PIO supported PIO4
DMA supported WDMA2 UDMA6
media RPM 5400

Feature Support Enable Value Vendor
read ahead yes yes
write cache yes yes
flush cache yes yes
overlap no
Tagged Command Queuing (TCQ) no no
Native Command Queuing (NCQ) yes 32 tags
SMART yes yes
microcode download yes yes
security yes no
power management yes yes
advanced power management yes no 0/0x00
automatic acoustic management yes no 0/0x00 254/0xFE
media status notification no no
power-up in Standby yes no
write-read-verify no no 0/0x0
unload no no
free-fall no no
data set management (TRIM) no

Я не понимаю вот чего - выше вы пишете, что скорость чтения - 80Mb/sec, а в тестах получается ~55?
C gnop я не стал связываться, не понимаю как с него будет грузиться.

Не может у вас такого быть, что упираетесь вы в процессор?

>Я не понимаю вот чего - выше вы пишете, что скорость чтения - 80Mb/sec, а в тестах получается ~55?

Где я это писал? Вы не спутали с вот этим?

1. Использование GPT с выровненными разделами и GNOP с любым размером блока ведёт к увеличению скорости записи на 12%

Так это для UFS имелось в виду, посмотрите сами - 103 против 118 Мбайт/сек.

>C gnop я не стал связываться, не понимаю как с него будет грузиться.
Не задумывался об этом. :)

>Не может у вас такого быть, что упираетесь вы в процессор?
После вашего тестирования задумался об этом, но визуальных оснований так полагать нет: LA 0.5, "top -aSHP" и "systat -v 1" не показывают никаких больших нагрузок.
Удивительно, что по systat диск находится в состоянии busy всего на 20-30%. Не понимаю просто, что происходит.
Попробую завтра воткнуть Core2Quad и проверить.

system time то какой?

Я свои эксперименты начал, увидев на system 50% ровно. И хотя видал с тех пор и выше, продолжаю думать что упирание в процессор/память или что-то еще из этой области - вполне возможно.

С C2D на 3+ - упираюсь явно в диски, и по iostat это вижу и по systat.

Памяти - 8 гигов, arc_max-ом рулил в диапазоне 2-5 гигов, но такой уж большой разницы не увидел, у меня или working set совсем маленький (вроде buildworld) или уже много-много гигабайтов, промежуток редко бывает.

Порядка 5-10%

2 users Load 0,12 0,16 0,16 8 ноя 00:00

Mem:KB REAL VIRTUAL VN PAGER SWAP PAGER
Tot Share Tot Share Free in out in out
Act 77448 7448 901288 11876 96980 count
All 278568 10728 1074738k 38128 pages
Proc: Interrupts
r p d s w Csw Trp Sys Int Sof Flt cow 4406 total
92 4589 5 482 404 380 zfod uart0 irq4
ozfod 159 em0 uhci0
5,2%Sys 0,4%Intr 0,0%User 0,0%Nice 94,4%Idle %ozfod uhci2 ehci
| | | | | | | | | | | daefr uhci3 ehci
=== prcfr 2001 cpu0: time
dtbuf 4019 totfr hdac0 257
Namei Name-cache Dir-cache 100000 desvn react 245 ahci0 259
Calls hits % hits % 34469 numvn pdwak 2001 cpu1: time
24991 frevn pdpgs
intrn
Disks ada0 ada1 ada2 ada3 ada4 ada5 pass0 567264 wire
KB/t 124 0,00 0,00 128 0,00 83,88 0,00 131628 act
tps 31 0 0 32 0 181 0 1192664 inact
MB/s 3,75 0,00 0,00 3,98 0,00 14,84 0,00 16780 cache
%busy 5 0 0 4 0 9 0 80200 free

ada5 - как раз тестируемый диск в момент тестирования на запись (тест 2.0).

Или в виде вывода "time" после теста (запись - чтение пятикратно):

4194304000 bytes transferred in 198.051275 secs (21177869 bytes/sec)
198,50 real 0,00 user 6,20 sys
--
4194304000 bytes transferred in 74.119052 secs (56588743 bytes/sec)
74,12 real 3,16 user 36,41 sys
--
4194304000 bytes transferred in 192.018093 secs (21843275 bytes/sec)
192,44 real 0,00 user 5,84 sys
--
4194304000 bytes transferred in 69.386375 secs (60448524 bytes/sec)
69,39 real 2,90 user 35,17 sys
--
4194304000 bytes transferred in 172.790038 secs (24273992 bytes/sec)
175,21 real 0,00 user 5,67 sys
--
4194304000 bytes transferred in 69.845113 secs (60051503 bytes/sec)
69,84 real 3,26 user 34,76 sys
--
4194304000 bytes transferred in 164.499585 secs (25497353 bytes/sec)
166,38 real 0,00 user 5,65 sys
--
4194304000 bytes transferred in 68.432740 secs (61290897 bytes/sec)
68,44 real 3,15 user 34,71 sys
--
4194304000 bytes transferred in 166.231105 secs (25231764 bytes/sec)
166,50 real 0,00 user 5,66 sys
--
4194304000 bytes transferred in 68.704074 secs (61048840 bytes/sec)
68,70 real 2,79 user 35,00 sys

top -aSCHIP в момент записи

last pid: 6953; load averages: 0.15, 0.26, 0.20 up 5+04:28:56 00:07:44
300 processes: 3 running, 276 sleeping, 2 stopped, 19 waiting
CPU 0: 0.0% user, 0.0% nice, 2.3% system, 0.0% interrupt, 97.7% idle
CPU 1: 0.0% user, 0.0% nice, 1.5% system, 0.0% interrupt, 98.5% idle
Mem: 125M Active, 1136M Inact, 557M Wired, 16M Cache, 210M Buf, 108M Free
Swap:

PID USERNAME PRI NICE SIZE RES STATE C TIME CPU COMMAND
10 root 171 ki31 0K 32K RUN 1 116.7H 94.38% {idle: cpu1}
10 root 171 ki31 0K 32K CPU0 0 115.6H 94.09% {idle: cpu0}
5565 root 45 0 14020K 5036K tx->tx 1 0:04 1.56% dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000

Хм.
Перегрузил сервер, выключив весь тюнинг zfs и vmem, убрал все посторонние программы и задачи. Итог - скорость записи и чтения увеличилась, но всё равно не дотягивает до UFS: запись стала порядка 30 Мбайт/сек, чтение порядка 70 Мбайт/сек.
Интересно, что при записи диск стал загружен на 100%, раз в ~4-5 секунд busy (и скорость) сбрасывается практически до нуля и одновременно подскакивает system load до 17-20%.


last pid: 3569; load averages: 0.01, 0.24, 0.18 up 0+00:06:12 00:16:59
244 processes: 3 running, 222 sleeping, 19 waiting
CPU 0: 0.0% user, 0.0% nice, 6.0% system, 1.1% interrupt, 92.9% idle
CPU 1: 0.0% user, 0.0% nice, 11.3% system, 0.4% interrupt, 88.3% idle
Mem: 48M Active, 3620K Inact, 543M Wired, 272K Cache, 1348M Free
Swap:

PID USERNAME PRI NICE SIZE RES STATE C TIME CPU COMMAND
10 root 171 ki31 0K 32K CPU0 0 5:58 100.00% {idle: cpu0}
10 root 171 ki31 0K 32K RUN 1 5:59 97.75% {idle: cpu1}
3557 root 47 0 14020K 4996K tx->tx 0 0:01 4.05% dd if=/dev/zero of=/mnt/benchmark/zero.4G bs=4M count=1000
0 root -16 0 0K 2128K - 0 0:00 0.98% {zio_write_issue}

ZIL же!

Я тут перелез на Windows7 и наблюдаю ту же картину что была когда-то с XP -- iperf без опций -w показывает всего 120Mbit (на гигабите!), с -w 128k показывает хорошие 800Mbit, а вот с Samba Копируется 25MiB/s (Т.е. не 120 мегабит, но никак и не 800). И iperf показывает на винде по-умолчанию окна в 8KiB. Да, jumbo разрешены (7KiB, больше мой адаптер на винде не умеет)!
Ты вот в этом месте ничего не делал? Это только мне так не везёт? Или реестр опять править надо?

Делал, еще как делал.

Но я не помню, что именно делал для этого, а что - по другой причине, поэтому только summary:

1) На винде отключаем QoS. И сервис и в настройках драйвера сетевой карты, если он там есть.
2) Включаем Jumbo Frames с обеих сторон.
3) На FreeBSD:
/etc/sysctl.conf:
net.inet.tcp.recvbuf_auto=1
net.inet.tcp.recvbuf_inc=131072
net.inet.tcp.recvbuf_max=1048576
net.inet.tcp.sendbuf_auto=1
net.inet.tcp.sendbuf_inc=131072
net.inet.tcp.sendbuf_max=1048576
net.inet.tcp.maxtcptw=102400
net.inet.tcp.mssdflt=8800
net.inet.tcp.recvspace=262144
net.inet.tcp.sendspace=262144
kern.ipc.nmbclusters=204800
kern.ipc.nmbjumbop=192000
kern.ipc.maxsockbuf=2097152

/usr/local/etc/smb.conf:
read raw = yes
read size = 65536
socket options = TCP_NODELAY SO_RCVBUF=655360 SO_SNDBUF=655360

Результат:

(на запись чуть похуже, но на длинных файлах тоже в районе 100mb/sec)

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

Когда на WS работал реалтек (наплатный) - они периодически не могли договориться о гигабите, сваливаясь в полудуплекс (и сотку, кажется) со стороны винды, тогда как FreeBSD была не в курсе. Результат понятен.

Похоже, что read raw творит последние чудеса -- без него было 60-65, теперь 95-110. И, да, на Win7 таки даже спец-плагин FAR'а копирует ужасно. А на XP был лучше эксплорера... Забавно.

QOS был выключен всегда, всё через свитч HP ProCurve. На сервер интел-гигабит, на клиенте -- Atheros. Ещё интересно, что же так iperf тупит-то?!

Но, мать моя, безо всякого ZFS на сервере при этом kernel (По top -S) + smbd жрут полное ядро E4500... ЧЕМ!? Не прерывания, не сетёвка, не диск, не raid5 (он жрёт скромные 2%)! Именно процесс "kernel" 60-65% и smbd ещё 35-40% :) Пора апгредйить камень? Или E4500 разогнать... Но я не умею Core2 гнать :(

У меня kernel за неделю аптайма сожрал час времени. можно себе позволить.

C2D гонится легко процентов на 20, а то и больше, в интернетах масса пособий (но все сводится к подъему напряжений, вестимо). Конкретно про 4500-й не знаю, впрочем, не пробовал.

103 минуты за 15 дней... nfsd (отдаёт те же файлы торренто-качалке по NFS) -- 115 минут, прерывания -- 135 минут :)
Но я-то боюсь того, что он под нагрузкой именно упирается в процессор.

ZFS/RAIDZ на 1.6-1.8 гигагерцовом горшке - конкретно упирался.

А UFS у меня давно нету уже.

На реалтеке у меня последнее ускорение (до насыщения сети 120mb/sec по netstat) случилось именно заходом в пропертя драйвера сетевой карты и выключения там QoS.

При этом по сети никакого QoS не ходило, но возможно в драйвере на эту тему был оверхед на простановку тегов или на их разбор.

Поэтому в Intel сразу выключил, не задумываясь (там это называется Priority & VLan)

У меня та же фигня. smb утыкается в одно ядро и всё, атас.

Хе-хе. Собрал самую свежую фрю 8, с фиксами на if_em. Рзрешил net_isr:

net.isr.direct=0
net.isr.direct_force=0

Радикально увеличил все очереди.

Стало лучше -- полностью насыщенный линк при 60% одного ядра. iperf Показывает 980 мегабит вместо 850 раньше.

Включил поллинг на em0 -- загрузка процессора 5-7% на тех же скоростях! ХАХА. Вот и хвалёный intel PRO/1000

С другой стороны, у меня он чипсетный, а во фре в драйвере кода для ich8lan столько же сколько для всех остальных вариантов вместе взятых, так что может это и говно и надо купить PRO/1000 PT Desktop, единственный доступный у нас PCIe x1 адаптер от интела.

У меня упражнения с net.isr ни на что не повлияли, впрочем сеть (практически) насыщается без проблем.

Забавно. У меня net.isr.direct=0 и net.isr.direct_force=0 ровно наоборот делает, минимум 100 Мбит "срезает".
Кстати, iperf и em0:taskq у меня упорно на одно ядро сажались. Разнесение на разные ("cpuset") дало прирость на те же 100 мбит.

P.S. Не очень вижу смысла в покупке однопортовой PT для дома, 32-битного PCI на гигабит всё же хватает, пусть и впритык.

PCI однопортовка стоит столько же сколько PT'шка :)

Смысл изначально был в том, что было два слота, один PCI, второй PCIe и нужно было два порта, сотку к ISP, гигабит к рабочей станции (наплатный был занят гигабитом к остальному дому и порты в свитче кончились).

С тех пор однопортовая PT-шка просто есть. Когда она освободилась, я ее ткнул в WS, для сравнения с наплатным реалтеком. Большой разницы не обнаружил, впрочем.