Ускорение raid5 md-массивов на запись

RAID5/6-массивы дисков — типичное решение для файловых архивов, к которым много запросов на чтение и мало на запись. Их слабое место: медленные операции записи, в которых для расчёта контрольной суммы требуется чтение со всех томов данных массива. Это приводит не только к медленной записи на массив новых данных, но и к медленному исполнению всех операций предполагающих модификацию раздела, в частности операции удаления. А если ещё и используется дешёвый вариант рейда на основе mdadm, без всяких батареек, кешей и специализированного софта для рейдов, то удаление большого количества файлов становится ну оочень медленной задачей.

Отчасти это можно исправить. raid5 при записи много читает, читает даже больше чем пишет. При удалении модифицируемые данные это структуры затрагиваемых файлов и директорий, в общем-то небольшого количества данных, но изменяемых многократно. Учитывая, что XFS (и другие устойчивые файловые системы тоже) делают это безопасно для отключения питания, т.е. собственно коммитом и через журнал. Поэтому, хороший прирост скорости удаления даёт изменение кеша чтения mdadm:

    echo 16384 > /sys/block/md?/md/stripe_cache_size

Параметр stripe_cache_size по умолчанию имеет значение 256 (страниц по 4Kb), что в большинстве случаев достаточно мало. Максимальное значение — 32768, при этом скорость достаточно хорошая уже при значениях 8192-16384. При увеличении параметра надо учитывать, что это значение в страницах для каждого устройства в рейде и он в результате может занимать весомую часть ОЗУ. Тем не менее, даже если ОЗУ не много, увеличение чаще имеет смысл.

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

SSH без дисконнекта

При длительной работе в терминале по SSH, особенно с длительными перерывами, очень удобно, чтобы подключение сохранялось всё это время. Если не отсылать и получать данные в открытом подключении, то через некоторое время сессия разрывается по таймауту, что обычно неудобно. Исправим это.

В протоколе реализована возможность сохранения сессии, TCPKeepAlive, клиент или сервер посылает "пустой" пакет, тем самым оживляет сессию и держит её открытой. Фича реализована как на клиенте, так и на сервере. На клиенте она включается в пользовательском конфиге ssh ~/.ssh/config

ServerAliveInterval 90

Клиент будет каждые 90 секунд отправлять пакет серверу и тем самым поддерживать соединение.

Можно настроить периодическое оживление и в общем случае, для всех клиентов сервера. В конфигурации демона /etc/ssh/sshd_config добавляем или правим

ClientAliveInterval 90
ClientAliveCountMax 960

В этих настройках сервер будет отправлять пакет каждые 90 секунд и максимум делать это 960 раз. В результате соединение продержится до суток (90*960 = 86400 = 24h).

Странности nginx ssl

Параметры SSL в конфигурации nginx могут быть описаны как в глобальной http-секции, так и в настройках локальных серверов server. В контексте server по логике настройки должны применяться только на этот сервер.

Интересно, что поддержка TLS v1.2 включается только если её включить в server-секциях всех виртуальных хостов, а не только нужного.

Включение telnet в Windows 7

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

Ясно, что всегда можно найти (и часто более удобную) альтернативу, но иногда предпочтительнее нативный клиент. Как его включить? Это возможно с помощью DISM. Для этого запускаем консоль (cmd) с правами администратора и выполняем в ней:

dism /online /Enable-Feature /FeatureName:TelnetClient

В результате, спустя некоторое и весьма продолжительное время и зачем-то потребовав перезагрузку (!) клиент ставится.

Смена кодировки файлов в utf8

В поддержке legacy-кода и обновлении скритов нередко возникает задача их перекодирования в utf-8. Это хорошо выполняется стандарной утилитой iconv, вот её использование для одного файла:

iconv -f cp1251 -t utf8 orig-in-cp1251.php -o out-in-utf8.php

При этом не удастся указать одинаковое входное и выходное названия: iconv начнёт писать до получения входа и получится файл нулевой длины. В этом случае станартный вывод полезно "замочить в губке" с помощью sponge. Сделаем однострочный скрипт, который делает всё сразу, он понадобится далее (назовём его to-utf8.sh):

#!/bin/sh
/usr/bin/iconv -f cp1251 -t utf8 "$1" | sponge "$1"

В качестве единственного аргумента он берет имя файла и рекодит его полностью.

Обычно требуется сконвертить все файлы определённого расширения в целой директории. Подключаем ещё find:

find /here-is-my-files/ -type f -iname "*.js" -exec to-utf8.sh "{}" \;

На часть файлов iconv может ругнуться в STDERR и эти файлы целесообразно проверить/перекодировать вручную.

Ещё более сложный (и достаточно частый) случай, когда есть файлы в разных кодировках и их необходимо перевести в одну. iconv в этом случае может сконвертировать ещё раз и испортить файл. То есть, нужно распознать исходную кодировку и рекодить только "не те" файлы.

Тогда помогает самый лучший вариант: утилиты enca/enconv. Из них первая только распознаёт кодировку, а вторая ещё и перекодирует.Интерфейс enconv до безобразия простой: в случае одного параметра она перекодирует файл из исходной (ЛЮБОЙ распознанной!) кодировки в ту, что указана в locale. Кодировку можно указать явно, тогда вся задача решается одной строкой

find /here-is-my-files/ -type f -iname "*.js" -exec enca "{}" \;

Для улучшения точности язык также можно "подсказать", с помощью параметра (-L ru).

Последний, enca-способ, похоже самый оптимальный для большинства задач.

Вырезание заголовков в exim4

exim4 — отличный почтовый сервер для исходящей почты. По умолчанию он сохраняет заголовки полностью и добавляет ещё свои. В большинстве случаев эти заголвки делают письмо излишне информативным для получателя и этого желательно избежать.

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

Received: from srv12 ([10.0.0.12])
	by mymail.example.com with esmtp (Exim 4.84)
	(envelope-from )
	id 1cPEo3-0003N7-Jj
	for user@example.com; Thu, 05 Jan 2013 20:38:39 +0000

или следующее

x-originating-ip: [10.54.14.36]

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

Если письмо генерируется автоматически, некоторые интерпретаторы по умолчанию добавляют информацию о себе и о запускаемом скрипте. В частности, этим отличается PHP:

X-PHP-Originating-Script: 0:myscript.php

Поэтому, также вырезаем заголовок X-PHP-Originating-Script.

Если же почтовый сервер обслуживает офис, то из заголовков можно узнать используемый почтовый клиент. Например,

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0)
 Gecko/20100101 Thunderbird/45.5.1

или

X-Mailer: Microsoft Outlook 14.0

Обычно, эта информация вполне безопасна. Информацию о клиенте оставляют многие публичные почтовые сервисы. Однако, её тоже не всегда имеет смысл раскрывать. Особенно, если это веб-клиент или внутренняя CRM. Таким образом, можно ещё срезать заголовок User-Agent.

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

system_filter = /etc/exim4/filter

А в самом /etc/exim4/filter прописать вырезаемые заголовки. Например:

headers remove X-PHP-Originating-Script
headers remove Received

После этой доработки, количество заголовков заметно уменьшается и излишняя информация не раскрывается. Естественно, это происходит с сохранением DKIM-подписи (подписывает сервер), поскольку заголовки вырезаются до её формирования.

Confluence + nginx

Стандартная установка Atlassian Confluence вешает его по умолчанию на 8090 http-порт. Софтину в целях совместимости и безопасности целесообразно ставить в виртуалку и обращаться к ней по http, при этом сама виртуалка может находится в недоступной извне локальной сети. Поэтому, возникает задача проксировать траффик 8090 порта конфлюенса вовне. Ниже описывается, как это меньшими средствами сделать с помощью nginx.

В документации Atlassian рассматривается вариант проксирования траффика, в том числе энжинксом. Предлагаемый в документации способ предполагает правки в xml-конфиге самого Confluence, что есть не лучшее решение. Можно обойтись настройкой только nginx, без правок оригинального конфига конфлюенса, что обычно намного разумнее. Вот пример проксирования:

	location / {
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $remote_addr;
		port_in_redirect off;
		proxy_pass http://confluence-vhost:8090;
		proxy_redirect http://confluence-vhost:8090/ /;
		proxy_connect_timeout 600;
		#proxy_redirect off;
	}

Аналогичным способом можно завернуть траффик в SSL и отдавать его через https, что существенно повышает безопасность работы.

hubbed_hosts в exim4

Иногда настраиваемый сервер имеет FQDN имя, которое им обрабатываться не должно, но именоваться он должен именно так. В тривиальной настройке exim будет трактовать почту на этот домен локальной и складывать в /var/mail или подобную директорию для локальной почты. Чтобы домен и соответствующая почта не считалась локальной можно это явно прописать в /etc/exim4/hubbed_hosts, например

example.com:  mx.example.com

Ошибка Munin INDIVIDUAL BUFFER POOL INFO

При обновлении MySQL от версии 5.6 его показатели не читаются мунином. В логах появляется ошибка:

Unknown section: INDIVIDUAL BUFFER POOL INFO at /etc/munin/plugins/mysql_innodb_rows line 1098.

Ошибка возникает в результате того, что мунин не распознает новую секцию (INDIVIDUAL BUFFER POOL INFO) в ответе СУБД. Наикратчайший (однако, не лучший) путь вылечить — отключить эту секцию. Для этого в скрипте, который парсит параметры БД /usr/share/munin/plugins/mysql_, находим немного перед 1098 строчкой определение секции

my %section_map = (

и добавляем в самом начале этой секции

'INDIVIDUAL BUFFER POOL INFO' => \&skip,

Проверить корректность запуска можно munin-run на любом из собирающих скриптов. Например:

cd /etc/munin/plugins
munin-run mysql_innodb_rows

grep без комментариев и пустых строк

Часто нужно посмотреть "активные" строчки в конфиге, т.е. исключить из него комментарии и пустые. Это просто делается грепом

grep -v '^$\|^\s*\#' some-config.conf

Или более коротко, не учитывая комментариев, начинающихся не с начала строки:

grep -v '^$\|^#' some-config.conf

Удаление очень больших директорий в Linux

Современные файловые системы вроде ext3/ext4, xfs позволяют создавать в директориях очень большое количество файлов. В ряде случаев (обычно по ошибке или недосмотру) это реализуется на практике и тогда некоторые операции с такой директорией становятся очень медленными. Это касается прежде всего операций, требующих сортировку списка содержимого директории. Такая сортировка, например, происходит при вызове листинга ls, который по умолчанию сортируется, что естественным образом приводит к очень медленному исполнению команды. Также, большая директория очень медленно удаляется rm, поскольку последний формирует листинг.

Чтобы ускорить (а иногда и просто осуществить) удаление большой директории нужно отключить сортировку. Команда rm при удалении берет полностью список файлов, поэтому удалять очень большую директорию "в лоб" с помощью "rm -rf" очень неоптимальный вариант. Большую директорию удобнее удалять частями: листингом без сортировки некоторого количества файлов и их удалением. Сортировка в ls отключается параметром -U, что приводит к такой команде частичного удаления

ls -UA -1 . | head -n 1000 | xargs rm -f

Чтобы удалить содержимое директории полностью и при этом не грузить IO хоста постоянно лучше поставить команду в цикл с небольшими перерывами. Простейший (но не оптимальный и не самый корректный) способ осуществить это

while [ true ]; do ls -UA -1 . | head -n 100 | xargs rm -f 2>/dev/null; sleep 1; done

Альтернативный способ — изменить ionice процесса удаления.

Зеркалирование TCP порта с помощью iptables

В ряде задач системного администрирования требуется зеркалировать один tcp-порт на другой. Типичный пример: закрытый почтовый smtp порт 25 у некоторых провайдеров. В этом случае удобно смапить один порт на другой порт того же сервера, чтобы почту можно было отсылать по обоим портам. С помощью iptables это легко реализуется

$IPTABLES -A FORWARD -p tcp --dport 2025 -j ACCEPT
$IPTABLES -t nat -A PREROUTING -p tcp -d $WAN_IPADDR --dport 2025 -j REDIRECT --to-ports 25

После этого подключаться можно по обоим портам.

phpmyadmin за SSL-фронтендом nginx

Администрировать БД MySQL часто бывает удобно с помощью phpmyadmin. Естественно, пользоваться им необходимо безопасно, т.е. через https.

Простой вариант решения заключается в указании явного URL для пхпмайадмина в его конфиге:

$cfg['PmaAbsoluteUri'] = 'https://admin.example.com/pma';

Это полностью рабочий и безопасный для других сайтов вариант, но требует правки конфига phpmyadmin.

Альтернативный вариант — передавать порт, по которому идет соединение на nginx front-end от пользователя. Для этого в стандартных настройках прокси для энжикса меняем

proxy_set_header Host $host;

на

proxy_set_header Host $host:$server_port;

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

Установка sphinx-плагина для memcached в Debian

Многие плагины к сфинксу в дебиане можно найти и подключить с помощью

munin-node-configure --suggest
munin-node-configure --shell

Однако, есть много стоковых плагинов в /urs/share/munin/plugins/, которые не предлагаются и не включаются таким способом. В частности, плагин к memcached подключается вручную. Ставится он коротко следующим образом.

Плагин требует перловскую библиотеку Cache::Memcached, если её нет в системе — ставим:

apt-get install libcache-memcached-perl

Далее вручную идем в директорию с конфигами и подключаем плагин:

cd /etc/munin/plugins
ln -s /usr/share/munin/plugins/memcached_ memcached_rates
ln -s /usr/share/munin/plugins/memcached_ memcached_bytes
ln -s /usr/share/munin/plugins/memcached_ memcached_counters

Что означают все показатели и как работает плагин можно посмотреть в самом perl-скрипте /usr/share/munin/plugins/memcached_.

Далее запускаем получившиеся симлинки и проверяем, что плагин работает. По окончании рестартуем munin-node:

Ограниченный SFTP-доступ на сервер

Часто возникает задача дать доступ на сервер в определенную директорию по протоколу sftp, чтобы при этом не было доступа в весь корень файловой системы. Т.е. используя технику chroot. Делается это следующим образом.

Сначала создается пользователь в системе. Обычно по sftp заходят для правки контента и группа пользователя назначается общей для этого рода пользователей (например, www-data). Всё это делается опциями к adduser или useradd.

Далее в /etc/ssh/sshd_config созданному пользователю newuser добавляется кусок конфига, который определяет параметры входа и chroot:

Match User newuser
	ChrootDirectory %h
	ForceCommand internal-sftp
	AllowTcpForwarding no
	X11Forwarding no

После изменения конфига, естественно, нужно рестартануть sshd.

На этом все не заканчивается. Вот что гласит мануал sshd_config:

ChrootDirectory
Specifies the pathname of a directory to chroot(2) to after authentication. All components of the pathname must be root-owned directories that are not writable by any other user or group. After the chroot, sshd(8) changes the working directory to the user’s home directory.

Из соображений безопасности, чтобы работал chroot, директория пользователя должна быть от пользователя root (при этом группа может быть не рутовой). Выполняем это требование, voila и всё работает.

Также для безопасности обычно имеет смысл отключить шелл пользователя

	usermod newuser -s /bin/false

PS: Это все применимо именно для sftp. К сожалению, для scp это не работает и при попытке подключиться по ssh/scp произойдет ошибка.

locale failed in Debian

При установке в свежей ОС Debian новых пакетов обычно возникает ошибка вроде

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = "en_US:en",
LC_ALL = (unset),
LC_CTYPE = "ru_RU.UTF-8",
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

Для исправления нужно подключить локали, хватает русской и английской utf-8. Для этого:

dpkg-reconfigure locales

И там выбираем соответствующие en_US.UTF-8 и ru_RU.UTF-8.

Расширение LSI raid массива

Как и в случае замены проверяем диски:

./MegaCli64 -pdInfo -PhysDrv \[4:4\] -a0
./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0

Добавляем диски в массив:

./MegaCli64 -LDRecon -Start -r6 -Add -PhysDrv[4:4,4:15] -l2 -a0

После можно смотрим статус массива и процент завершения:

./MegaCli64 -LDInfo -LAll -aAll

Как убрать фигурные кавычки WordPress

Русский WordPress в стоковой конфигурации имеет плохую привычку заменять обычные кавычки на фигурные (французские). Особенно это досаждает, когда выкладывается какой-то код и в нем происходит автозамена.

К счастью, это легко исправляется. Для этого в файле /wp-includes/formatting.php находим строки, отвечающие за замену кавычек:

/* translators: opening curly double quote */
$opening_quote = _x( '“', 'opening curly double quote' );
/* translators: closing curly double quote */
$closing_quote = _x( '”', 'closing curly double quote' );

и в них меняем символы ‘“’, ‘”’ на ‘"’.

PS: Да, с обновлением WP, код может снова поменяться на оригинальный. По-хорошему, такое надо делать с помощью утилит diff и patch.

Замена диска в LSI raid-массиве

Время от времени жесткие диски выходят из строя и их необходимо менять. Далее описывается алгоритм такой замены на контроллере LSI MegaRaid SAS9260-4I с помощью оригинальной от производителя утилиты MegaCli.

Жесткие диски в экспандере пронумерованы по снизу вверх, справа налево (по столбцам, т.е. первый столбец снизу вверх идут диски 0-1-2-3 и т.д.). Будем менять 15 сыплющийся диск на исправный 10 в рабочем и здоровом RAID6-массиве. Состояние SMART 15-го диска можно посмотреть командой:

smartctl -d sat+megaraid,15 -a /dev/sdc

Для заменяемого диска находим счетчик перемещенных секторов Reallocated_Sector_Ct далеким от нулевого значения, что означает, что с диском не все в порядке. Информацию об ошибках носителя также можно обнаружить и в состоянии физического диска контроллера:

./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0

,
где Media Error Count отличен от нуля. 15 в этой команде — id диска на экспандере.

Все работы проводим на исправном массиве. Проверяем, что массив здоров (Optimal):

./MegaCli64 -LDInfo -LAll -aAll | less

Отключаем и вынимаем дефектный жесткий диск:

./MegaCli64 -PDOffline -PhysDrv \[4:15\] -a0
./MegaCli64 -PDPrpRmv -PhysDrv \[4:15\] -a0
./MegaCli64 -PDMarkMissing -PhysDrv \[4:15\] -a0

С помощью -LDInfo -LAll убеждаемся, что нарушен искомый массив и с помощью ./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0, что диск действительно вне массива.

Теперь необходимо добавить исправный 10-й диск взамен неисправного. Делается это с помощью команды

./MegaCli -PdReplaceMissing -PhysDrv [E:S] -ArrayN -rowN -aN

для которой нам потребуются номера Array и row. Эти числа берутся из вывода

./MegaCli64 -PdGetMissing -a0

Запускаем команду с нужными параметрами, она добавляет диск. Подтверждаем, что диск добавился корректно

./MegaCli64 -pdInfo -PhysDrv \[4:10\] -a0

и в выводимой информации присутствуют правильный номер Disc Group.

Заключительный шаг — запуск ребилда

./MegaCli64 -PdRbld -Start -PhysDrv \[4:10\] -a0

состояние которого можно посмотреть через некоторое время

./MegaCli64 -PdRbld -ShowProg -PhysDrv \[4:10\] -a0

Все вышеприведенное справедливо и для других контроллеров LSA аналогичных моделей. Кроме этого, утилита MegaCli умеет ещё много чего полезного, что легко находится в гугле.