Q: FreeBSD-FreeBSD remote shell speed
Уважаемые FreeBSD-веды!
у меня в подполе происходит Я гоняю zfs snapshots с ящика на ящик таким примерно способом:
zfs send .... | mbuffer -s 64k -m 64m | ssh -c aes128-gcm@openssh.com box2 zfs recv
И между двумя ящиками на i3 все происходит хорошо: ssh с этим шифром бегает на скорости 900+MB/sec, реально zfs recv может принять 450-500 и я всем доволен.
Но на Atom C3758 все не так радужно: одно ядро медленнее раза в 4 и ssh -c aes128-gcm@openssh.com дает мегабайт 300 в секунду, одно ядро выжирается целиком.
Думал, что дело в шифровании. Поставил openssh-portable c NONECIPHER, те же ~300 мегабайт/сек.
Посоветовали rsh. Долго вспоминал как настраивать, лет 15 не касался, настроил, ~300 MB/sec.
Запускаю так (ssh/rsh - одинаково по смыслу):
in @ 282 MiB/s, out @ 282 MiB/s, 5046 MiB total, buffer 100% full5+0 records in<br>
5+0 records out<br>
5368709120 bytes transferred in 17.227217 secs (311641109 bytes/sec)
Удаление mbuffer с посылающей стороны ничего не меняет.
При этом с mbuffer на mbuffer все хорошо:
in @ 1180 MiB/s, out @ 1180 MiB/s, 49.8 GiB total, buffer 100% full50+0 records in<br>
50+0 records out<br>
53687091200 bytes transferred in 49.435914 secs (1085993701 bytes/sec)
(c принимающей стороны там через inetd:
courier stream tcp nowait root /usr/local/bin/mbuffer mbuffer -q -o /dev/null -s 64k -m 64m
На интерфейсах с обоих сторон одинаково:
a # ifconfig ix0 ix0: flags=8843metric 0 mtu 9000 options=e404bb RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,LRO,VLAN_HWTSO,RXCSUM_IPV6,TXCSUM_IPV6
Вопрос: что бы такое потюнить (у ssh, openssh-portable, rsh, FreeBSD) чтобы ну хотя-бы мегабайт 500 в секунду получить?
Comments
> что бы такое потюнить (у
> что бы такое потюнить (у ssh, openssh-portable, rsh
Лучше исключить ssh из цепочки пересылки данных, даже с выключенным шифрованием.
Замена mbuffer на nc (netcat) на обеих концах может ощутимо поднять скорость. Были прецеденты.
Тут такая история
Тут такая история
1) ssh (и с шифрованием и без) работает быстрее rsh
2) mbuffer - mbuffer выжирает нормально почти всю полосу, ну там не 10 гигабит а 8, мне достаточно.
Проблема в том, что мне нужен именно remote shell, чтобы ошибки с удаленного конца ловить.
То есть конечно, если rsh починить не получится, придется mbuffer - mbuffer или netcat, но не хотелось бы
> Проблема в том, что мне
> Проблема в том, что мне нужен именно remote shell, чтобы ошибки с удаленного конца ловить.
Ммм, а в чём проблема с ошибками?
s=/var/run/send.success
rm $f && zfs send | { ssh remotehost zfs recv && touch $s; }
if [ -e $s ]; then
success
else
failure
fi
zfs recv примет данные откуда
zfs recv примет данные откуда? C stdin? Ну вот со скоростью подачи через ssh и есть проблема.
Ну то есть наверное вы имели
Ну то есть наверное вы имели в виду "на удаленном хвосте запустить mbuffer -I | zfs recv && touch
Ну да, так можно, онанизм но можно.
Нет, я имел в виду именно то,
Нет, я имел в виду именно то, что написал. Если удалённый zfs recv вернёт ошибку, то ssh её вернёт тоже и локальный touch не исполнится. И какая разница - проверять код возврата сложной команды или простого test -e localfile ? Суть одна и решение полностью корректное.
Ну подождите: zfs send | {
Ну подождите: zfs send | { ssh remotehost zfs recv && touch $s; }
Это именно кормление zfs recv данными через медленный (в данном случае) ssh.
Оно у меня так сейчас примерно и работает, но проблема в том, что ssh на новом ящике - медленный.
Это я понимаю.
Это я понимаю.
Я не понял, отчего вот это было сказано? "Проблема в том, что мне нужен именно remote shell, чтобы ошибки с удаленного конца ловить." Под remote shell тут понимается именно ssh? Он не имеет проблем с передачей признака ошибки, как впрочем и rsh.
Я имел в виду вот что:
Я имел в виду вот что:
Если я пускаю zfs send | ssh remote zfs recv
То где бы оно не сломалось, тут, там, посередине - достаточно проверить один код ошибки, если он не 0, то клеим ласты.
А если же мы к примеру запускаем как-то так (синтаксис условный, могу напутать с кавычками)
ssh remote "nс -l port | zfs recv" & # я кстати сходу даже не знаю можно ли так, но почему собственно и нет....
sleep 1;
zfs send | nc remote port
То вся логика обработки ошибок, количества мест их возникновения и проч - сильно усложняется в сравнении с one-liner.
А если я для сохранения 1-liner на своей стороне - на удаленную сторону привешу zfs recv в inetd.conf - то скрипты опять 1-liner, но вот обработка ошибок еще более усложняется.
Теперь понятно.
Теперь понятно.
Я, кстати, сейчас припомнил, что для определенных комбинаций скорости CPU источника и приёмника и скорости сети при передаче бекапов мне неплохо помогала компрессия потока при помощи zstd (порт archivers/zstd):
dump ... | nice zstd | ...
На Xeon E5620 2.40GHz оно мне сжимало со скоростью 48 мегабайт в секунду и экономило 37%, сжимая 417G до 263G и время передачи с 5 до 3 часов (там был медленный приёмник).
То что в ежедневном режиме
То что в ежедневном режиме гоняется через zfs send - оно по большей части сжатое (в смысле - сами файлы внутри сжатые/несжимаемые).
Ну и на 10G, то есть гигабайт в секунду, сжимать могут не только лишь все.
И ещё момент касательно zfs
И ещё момент касательно zfs send и компресии: когда я развлекался с этой темой пару лет назад, zfs send --compressed ещё не существовало даже в OpenZFS, хотя уже был фичереквест. Тогда для сжатых файловых систем zfs send безусловно распаковывал данные перед отправкой, так что в обратной компрессии перед выпуском в сеть был смысл для сжимаемых данных и незанятых ядер CPU.
Нынче уже есть zfs send -c и оно сжатые блоки данных посылает в сжатом виде, но вот блоки с метаданными оно AFAIK таки разжимает перед отправкой и если метаданных много... Можно потестировать.
У меня данные, за редчайшими
У меня данные, за редчайшими исключениями, плохо сжимаемые. Соответственно, zfs-компрессия не используется.
Соответственно, zfs-компрессия не используется
Я бы и для плохо сжимаемых данных включал lz4. Впрочем для данного процессора лучше проверить.
lz4 в смысле latency вовсе не
lz4 в смысле latency вовсе не бесплатный - если данные не жмутся, лучше не надо
lz4 в смысле latency вовсе не бесплатный
Если мне не изменяет память, если блок не жмётся то пишется не жатый и читается соответственно. Если удалось хоть немного сжать, то с диска будет читаться меньше секторов, что может компенсировать время затраченное на декомпрессию, поэтому с latency не всё так однозначно.
А не возникает ли там проблем
А не возникает ли там проблем на пустом месте от небольших сжатий? Ну там блоки стали не известного размера, а переменного?
А не возникает ли там проблем на пустом месте
А с чего им возникнуть? Блоки по дизайну могут быть любого размера. Помнится у тебя в конфигурации raidz2 (4+2) два диска при чтении часто простаивали. А если бы блоки были разные - читалось бы со всех. Плюсов достаточно и они понятны, а из минусов на ум приходит только использование на очень медленных процессорах.
Ну считая что ядро у этого
Ну считая что ядро у этого нового атома - в 4 раза медленнее, чем у i3/3.3Ghz, там, прикидывая хрен к носу, ~200MB/s на ядро должно получаться. Или больше гига на всех восьми.
Попробую вот на тестовом томе, который 3x6Tb stripe
Достать линейку и померяться
Достать линейку и померяться - несложно.
Взял я самые сжимаемые файлы, которые у меня есть - нежатые raw (там в каждом 16-битном слове два верхних бита - нули, т.е. на 12% жмется гарантировано, ну а дальше - как кто умеет, zip где-то 80% от полного объема).
Ну и результаты (других файлов на томе нет):
zfs get all | grep compr
ztest compressratio 1.01x -
ztest compression off default
ztest refcompressratio 1.00x -
ztest/test compressratio 1.01x -
ztest/test compression lz4 local
ztest/test refcompressratio 1.01x -
1% - бессмысленно.
Для других данных (из тех что у меня много) будет еще хуже.
Скорость записи, соответственно, ну тоже не растет. При записи 600Mb/sec - 6 процессорных threads каждая жрет половинку CPU по top.
1% - бессмысленно
Не настаиваю :-), но упомяну про скрытые плюсы. Очень хорошо жмутся метаданные (пусть их объём и невелик по отношению к данным). Насколько помню, ты используешь 1MB recordsize. Если файл больше 1MB и нет сжатия, то последний блок аллоцирует на диске 1MB. Если предположить, что размеры файлов имеют случайное распределение, то в среднем на хвосте файла можно ожидать выигрыша в 0,5MB на диске и это не отражается в коэффициенте сжатия. Как оказалось, embedded-data block pointers после включения lz4 имеют ощутимую долю запросов (если где-то ещё остался счётчик могу посмотреть % от общего числа запросов в реальной эксплуатации). Ну и по умолчанию арк теперь жмёт блоки данных (lz4) и хранит их в таком виде в памяти. Экономить на процессорном времени не сильно получится :-).
метаданные
Похоже я когда-то пропустил и метаданные теперь по умолчанию жмутся на диске независимо от установок датасета.
А я опять вляпался в
А я опять вляпался в primarycache=metadata (+, если правильно помню, prefetch и/или большой recordsize).
Было опять смешно - 400Mb/s с дисков и меньше 100 уходит в сеть.
если правильно помню
Если правильно помню :-), recordsize не соответствует размеру блока передачи по smb. На всякий случай, как-то недавно обнаружил, что primarycache=metadata (и даже none) при send/recieve не спасает от вымывания арка.
Ну меня primarycache=metadata
Ну меня primarycache=metadata сильно спасло от вымывания ARC (ARC перестал пухнуть с первым же бэкапом - они у меня на отдельный Zpool), но общий результат получился огорчительным, backup verify стал идти в разы дольше.
primarycache=metadata
Если несколько пулов на общий арк и внеший бэкап по самбе тогда конечно имеет смысл. А чтение (верификация) по самбе с primarycache=metadata думаю для приемлемой скорости нужно хорошо согласовать с чтением из пула.
Я не вижу ручек для
Я не вижу ручек для согласования без общего ухудшения всего, самба то тоже общая (как и ARC).
Нужно, наверное, играть recordsize на бэкапном пуле. Но я вспоминаю, что года 2 или 3 назад я во все это уже играл - и в результате наплевал на вымывание ARC, так оказалось проще всего.
наплевал на вымывание ARC
В принципе для файлового сервера здравая мысль. Всегда в процессе возникают не очень подходящие задачи для арка, то кто-то запустит поиск на 300000 файлах, то кому-то нужно перенести большой объём в другое место... Для самба сервера при настройке арка и пула (в моём понимании) важно при запросе стараться не тратить время на чтение метаданных с дисков и максимально быстро читать нужный блок данных файла из пула.
Я на бэкапный пул поставил
Я на бэкапный пул поставил запиливаться два старых OCZ Vertex. Выкинуть жалко, использовать невозможно, пусть падут смертью храбрых уж, заодно посмотрим, сколько это займет.
Пока вместе с data, посмотрю на эффективность, должна быть хорошая, если нет - то только метадату на них отправлю
только метадату на них отправлю
Метадату я стараюсь держать всю в арке и что бы она оттуда не уходила вообще. Ради интереса проверь какой объём она занимает в арке для всех твоих данных в пуле (без сжатия и с ним). Думаю не пожалеешь :-).
А что значит "стараюсь"? Там
А что значит "стараюсь"? Там же решают за нас.
А что значит "стараюсь"?
vfs.zfs.arc_meta_limit определяет максимальный размер метаданных в арке. К сожалению "за нас решили" какой порядок вытеснения записей в арке и он всё таки умудряется вытеснять метаданные даже если их меньше лимита. Но можно закомментировать "ненужное". Я оставил вытеснение метаданных только в случае превышения лимита и при сигнале системы, что мало памяти.
В смысле - понастраивать ядро
В смысле - понастраивать ядро через vim?
Не, не могу пойтить на это, svn up или все сломает или сам сломается
не вижу ручек для согласования без общего ухудшения всего
Сегодня нужно было подойти к линейке. Попробовал заодно освежить память по поводу primarycache=metadata. Пул из четырёх дисков (страйп из двух зеркал). Взял файл с recordsize=128k.
dd if=/data/test/test_32g_128k of=/dev/zero bs=128k
34359738368 bytes transferred in 180.599959 secs (190253301 bytes/sec)
Префетч не работает, получаем прогнозируемую скорость для единичной очереди.
Чтение этого файла по сети эксплорером 300+MB/s, gstat показывает, что суммарная очередь на чтение иногда доходит до 8.
Создал файл с recordsize=1M.
dd if=/data/test/test_32g_1M of=/dev/zero bs=128k
34359738368 bytes transferred in 1284.648935 secs (26746403 bytes/sec)
Хорошо видно, как резко падает скорость, если читаем данные мимо арка и блоками меньше чем размер recordsize.
dd if=/data/test/test_32g_1M of=/dev/zero bs=1M
34359738368 bytes transferred in 162.679963 secs (211210636 bytes/sec)
Так ближе к норме.
Чтение эксплорером 130+MB/s, gstat показывает суммарное чтение с дисков около 180MB/s.
Эксплорер опять "химичит", но это уже не спасает.
Во-первых, dd if=/dev/zero bs
Во-первых, dd if=/dev/zero bs=1G это плохая идея (читать крупными кусками из /dev/zero под FreeBSD). Во-вторых (и убедиться в первых) - надо запускать top -SHPI в процессе на обоих системах и глядеть, где узкое место. Ещё полезно в процессе запускать systat -vm 3 и глядеть в правый столбец на количество прерываний.
(по частям буду отвечать) Да,
(по частям буду отвечать) Да, bs=1G - идея не очень, ну то есть 1M - быстрее раза в два. Тем не менее "скорость - достаточная"
20 и 40 GB/sec в таком раскладе. mbuffer понятно тоже жрет от души и с ним (| mbuffer -o /dev/null) получается 2.5 и 5, но и в этом случае это все на порядок больше той скорости, что мы имеем с rsh/ssh (а dd bs=1G| mbuffer | network | mbuffer - ну 8Gbit дают, в отличие от 2.5 через *sh).
Пошел пускать топы и systat.
Скорость тут достаточная,
Скорость тут достаточная, потому что не приходится параллельно тратить CPU на обслуживание сетевых прерываний и CPU хватает. А когда сеть тоже хочет CPU - картина будет другая.
Ну вот как бы сказать: dd bs
Ну вот как бы сказать: dd bs=1G | mbuffer | network | mbuffer | devnull - 8гигабит
а dd bs=1G | rsh | network | mbuffer | devnull - 2.5
Сдается мне, дело тут не (только) в dd.
Конечно, не только в dd.
Конечно, не только в dd. Узкое место наверняка CPU, а dd bs=1G только усугубляет проблему, создавая немалый дополнительный вклад в загрузку CPU драйвером /dev/zero, что никак не помогает вычленить основную неоптимизированную подсистему, чтобы её оптимизировать :-)
У меня узкое место - на
У меня узкое место - на принимающей стороне.
Вот типичная картина (скриншоты проще получаются в png, пардон)
top на sender: https://www.dropbox.com/s/3issenlt4x833ah/top-rsh-send.png?dl=0
top на receiver: https://www.dropbox.com/s/1r6fva7876mekxf/top-rsh-recv.png?dl=0
На sender делаю так:
# dd if=/dev/zero bs=1M count=10000 | rsh 10.5.0.3 dd of=/dev/null
10000+0 records in
10000+0 records out
10485760000 bytes transferred in 33.885600 secs (309445904 bytes/sec)
20475234+8465 records in
20480000+0 records out
10485760000 bytes transferred in 33.756500 secs (310629359 bytes/sec)
При этом ssh стабильно
При этом ssh стабильно быстрее (процентов на 10) вместе со всем шифрованием:
# dd if=/dev/zero bs=1M count=5000 | ssh -c aes128-gcm@openssh.com 10.5.0.3 dd of=/dev/null
5000+0 records in
5000+0 records out
5242880000 bytes transferred in 15.304234 secs (342577094 bytes/sec)
10240000+0 records in
10240000+0 records out
5242880000 bytes transferred in 14.986247 secs (349846106 bytes/sec)
Это на принимающей стороне
Это на принимающей стороне HPN, на передающей - обычный, сейчас попробую HPN patches применить еще.
> У меня узкое место - на
> У меня узкое место - на принимающей стороне.
Да, так оно обычно и бывает. На принимающей стороне, судя по https://www.dropbox.com/s/1r6fva7876mekxf/top-rsh-recv.png?dl=0 многовато прерываний и просто безобразное время system time, которое объясняется не заданным bs у принимающего dd, от чего он использует дефолтный bs=512 и насилует ядро безумным количеством сисколлов write() - лучше всё же задать bs=1m.
Что касается прерываний на принимающей стороне - не вижу скриншотов systam и я не уловил, какие там сетевые интерфейсы? Если Intel, то максимизировано ли количество приёмных дескрипторов чипа и настроена ли группировка прерываний (interrupt coalescing) под бОльшую нагрузку? Я не пробовал тюнить десятигигабитные интелевские интерфейсы, а насчет гигабитных можно почитать тут: https://dadv.livejournal.com/139170.html
Я что хочу сказать
Я что хочу сказать
1) когда я фигачу ssh (360Mb/sec)/rsh (до 330) - я вижу ~40k прерываний в секунду. Типа, много.
если на принимающей стороне увеличить bs у dd, результат не меняется
2) Дальше беру mbuffer:
Sender:
dd if=/dev/zero bs=1M count=50000 | mbuffer -4 -O 10.5.0.3:3333 -s 64k -m 64m
in @ 1180 MiB/s, out @ 1180 MiB/s, 48.3 GiB total, buffer 100% full50000+0 records in
50000+0 records out
52428800000 bytes transferred in 42.463043 secs (1234692477 bytes/sec)
Receiver:
mbuffer -4 -I 3333 -s 64k -m 64m -o /dev/null
in @ 1180 MiB/s, out @ 1180 MiB/s, 48.3 GiB total, buffer 0% full
summary: 48.8 GiByte in 42.5sec - average of 1176 MiB/s
Прерываний 75-85k в секунду.
Теперь уж netcat, раз его все советуют:
dd if=/dev/zero bs=1M count=50000 | nc 10.5.0.3 3333
50000+0 records in
50000+0 records out
52428800000 bytes transferred in 82.591318 secs (634797954 bytes/sec)
mbuffer быстрее.
Из чего я делаю вывод, что дело не в настройках собственно сетевого интерфейса ix (сетевая карта на sender Intel X540, на принимающей Ethernet Connection X553/X557-AT 10GBASE-T, обе 10G). Возможно interrupt moderation помог бы немного, но для 9k-пакетов там количество пакетов на самом деле не очень большое.
Дело, как я думаю, в настройках tcp. Что-то такое mbuffer умеет, чего ssh/rsh не умеют. Может быть тупо большой tcp buffer и не скейлить его.
вдогонку: судя по 98%
вдогонку: судя по 98% interrupt при тестах с mbuffer, этот 1.1 гигабайт/сек - близко к пределу, но тем не менее - могет.
> если на принимающей стороне
> если на принимающей стороне увеличить bs у dd, результат не меняется
Зато будет виднее, кто жрёт CPU, а кто нет.
> Может быть тупо большой tcp buffer и не скейлить его.
mbuffer, судя по его сорцам, по умолчанию ставит размер приёмного буфера в 1 мегабайт (TCP RWIN), а rsh использует системный дефолт:
$ sysctl net.inet.tcp | fgrep recv
net.inet.tcp.recvspace: 65536
net.inet.tcp.recvbuf_max: 2097152
net.inet.tcp.recvbuf_inc: 16384
net.inet.tcp.recvbuf_auto: 1
Вероятно, автоскейлинг тупо не успевает разогнать. Можно попробовать либо поднять первоначальное значение net.inet.tcp.recvspace сразу до мегабайта, либо резко увеличить инкремент net.inet.tcp.recvbuf_inc
No luck:
No luck:
# sysctl net.inet.tcp | grep space
net.inet.tcp.sendspace: 1048576
net.inet.tcp.recvspace: 1048576
(на обоих концах, конечно)
# dd if=/dev/zero bs=1M count=10000 | ssh -c aes128-gcm@openssh.com 10.5.0.4 dd of=/dev/null bs=1M
10000+0 records in
10000+0 records out
10485760000 bytes transferred in 33.001974 secs (317731297 bytes/sec)
lexa@home-gw:/home/lexa# dd if=/dev/zero bs=1M count=10000 | rsh 10.5.0.4 dd of=/dev/null bs=1M
10000+0 records in
10000+0 records out
10485760000 bytes transferred in 34.201657 secs (306586318 bytes/sec)
Читать tcpdump (гигабайтный) на предмет что там с tcp options происходит и отчего - уже не хочется.
Я сдался, 350Mb/sec меня, на
Я сдался, 350Mb/sec меня, на самом деле, устраивают почти.
что бы такое потюнить
http://www.allanjude.com/bsd/AsiaBSDCon2017_-_SSH_Performance.pdf
Прежде чем начинать тюнить -
Прежде чем начинать тюнить - надо определить узкое место. И раз rsh тоже тормозит (а это голый TCP-сокет), то узкое место наверняка не (только) в ssh.
надо определить узкое место
Там как раз и об узких местах.
У нас на линуксах в какой-то
У нас на линуксах в какой-то момент выяснилось, что rsh теперь тот же ssh...
На FreeBSD не так
На FreeBSD не так