суббота, 10 декабря 2011 г.

Изменение размера переменной innodb_log_file_size


При коммите InnoDB записывает данные не сразу в файлы данных, а сначала записывает изменения в innodb_log_file. Дело в том что записать данные непосредственно в таблицу - существенно более дорогая операция, чем записать изменения в бинарный лог. 
Ведение innodb_log_file позволяет проводить оптимизацию i/o: записывать данные большими последовательными кусками, а также более быстрее обслуживать клиентов (клиент быстро сделал коммит, а данные в табличное пространство записываются в фоне). 
При старте после неожиданного отключения MySQL просматривает innodb_log_file, откатывая транзакции, которые не успели завершиться перед крахом и отмечая коммиты, которые успели (и были полностью записаны в innodb_log_file). Чем больше файл, тем больше времени требуется серверу, чтобы просмотреть его.

mysql> show variables like 'innodb_log_file_size';
+---------------------------+--------------+
| Variable_name        | Value       |
+---------------------------+--------------+
| innodb_log_file_size | 5242880 |

По умолчанию в mysql 5.5 размер innodb_log_file_size установлен в 5M. 
Как же определить наиболее оптимальный размер?
Выполните эти команды во время наиболее интенсивной нагрузки вашего сервера:

mysql> pager grep sequence
PAGER SET TO 'grep sequence'
mysql> SHOW engine innodb STATUS\G SELECT sleep(60); SHOW engine innodb STATUS\G

Подробности смотрите в ссылках в конце статьи.

Собственно, процедура. Как оказалось, нельзя просто поменять значение в конфигурационном файле. Нужно, чтобы mysql заново создал эти файлы после остановки. Т.е. нужно остановить сервер, изменить значения директивы innodb_log_file_size, удалить или переместить старые файлы ib_logfile0/ib_logfile1, затем стартовать mysql. Приступим:

1. sudo service mysqld stop

2. Отредактировать /etc/my.cnf, изменив/добавив в секцию [mysqld]
innodb_log_file_size = 64M

3. cd /var/lib/mysql; sudo mv ib_logfile0 ib_logfile0_1; sudo mv ib_logfile1 ib_logfile1_1

4. sudo service mysqld start

5. Проверить лог-файлы, что все стартануло нормально:
*****
InnoDB: Setting log file ./ib_logfile0 size to 64 MB
InnoDB: Database physically writes the file full: wait...
111210 15:18:33  InnoDB: Log file ./ib_logfile1 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile1 size to 64 MB
*****


Литература:
http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_log_file_size
http://www.mysqlperformanceblog.com/2011/11/21/should-mysql-update-the-default-innodb_log_file_size/
http://www.mysqlperformanceblog.com/2008/11/21/how-to-calculate-a-good-innodb-log-file-size/
http://greenmice.info/ru/node/92

четверг, 8 декабря 2011 г.

Проблема с запрещением LRO в RHEL6.2

Вообщем, сегодня столкнулся с проблемой после обновления RHEL 6.1 -> 6.2. RHEL - виртуалка, хост - ESXi.

Собственно, вот что вылезло в /var/log/messages

Dec  8 10:30:18 vTestFW kernel: ------------[ cut here ]------------
Dec  8 10:30:18 vTestFW kernel: WARNING: at net/core/dev.c:1234 dev_disable_lro+0x7b/0x80() (Not tainted)
Dec  8 10:30:18 vTestFW kernel: Hardware name: VMware Virtual Platform
Dec  8 10:30:18 vTestFW kernel: Modules linked in: ppdev parport_pc parport microcode vmware_balloon i2c_piix4 i2c_core sg shpchp ext4 mbcache jbd2 sd_mod crc_t10dif sr_mod cdrom vmxnet3 vmw_pvscsi pata_acpi ata_generic ata_piix dm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
Dec  8 10:30:18 vTestFW kernel: Pid: 799, comm: sysctl Not tainted 2.6.32-220.el6.x86_64 #1
Dec  8 10:30:18 vTestFW kernel: Call Trace:
Dec  8 10:30:18 vTestFW kernel: [<ffffffff81069b77>] ? warn_slowpath_common+0x87/0xc0
Dec  8 10:30:18 vTestFW kernel: [<ffffffff81069bca>] ? warn_slowpath_null+0x1a/0x20
Dec  8 10:30:18 vTestFW kernel: [<ffffffff8142a10b>] ? dev_disable_lro+0x7b/0x80
Dec  8 10:30:18 vTestFW kernel: [<ffffffff8149118d>] ? devinet_sysctl_forward+0x14d/0x190
Dec  8 10:30:18 vTestFW kernel: [<ffffffff811e4ca7>] ? proc_sys_call_handler+0x97/0xd0
Dec  8 10:30:18 vTestFW kernel: [<ffffffff811e4cf4>] ? proc_sys_write+0x14/0x20
Dec  8 10:30:18 vTestFW kernel: [<ffffffff811765d8>] ? vfs_write+0xb8/0x1a0
Dec  8 10:30:18 vTestFW kernel: [<ffffffff810d46e2>] ? audit_syscall_entry+0x272/0x2a0
Dec  8 10:30:18 vTestFW kernel: [<ffffffff81176fe1>] ? sys_write+0x51/0x90
Dec  8 10:30:18 vTestFW kernel: [<ffffffff8100b0f2>] ? system_call_fastpath+0x16/0x1b
Dec  8 10:30:18 vTestFW kernel: ---[ end trace 38ebf833f6a2bfcc ]---
Dec  8 10:30:18 vTestFW kernel: ------------[ cut here ]------------


Недолгое гугление приводит к советам VMware отключить LRO (Large Receive Offload) на сетевых интерфейсах (http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1027511).
Пробую:

# ethtool -K eth1 lro off
Cannot set large receive offload settings: Operation not supported


Мда, забавно. Ищем в базе знаний RedHat - может чего такого уже есть - и таки да, решение найдено.
1 - Временно использовать драйвер e1000 вместо vmxnet3
2 - Запретить LRO на уровне хоста ESXi.

Я попробовал оба способа - особой разницы не заметил - оба работают. Ошибки в логах пропали, особой потери производительности нет.

PS: Как запретить LRO на уровне ESXi:

Перейти настройках Software->Advanced Settings->Net setting.
Найти параметр Net.VMxnet3SwLRO и поставить 1 вместо 0.

Дальнейший разбор полетов в RedHat продолжается, ждем нормального решения.

Литература:
RedHat KB.

суббота, 3 декабря 2011 г.

Chroot php-fpm в rhel6.


Возникла необходимость поставить php-fpm в chroot для увеличения безопасности одного популярного движка сайта. Небольшой рассказ о проделанной работе и возникших проблемах. Итак, php-fpm обладает замечательной возможностью запускать скрипты в chroot-окружении. Немного wikipedia: chroot — операция изменения корневого каталога в Unix-подобных операционных системах. Программа, запущенная с изменённым корневым каталогом, будет иметь доступ только к файлам, содержащимся в данном каталоге. Поэтому, если нужно обеспечить программе доступ к другим каталогам или файловым системам (например, /proc), нужно заранее смонтировать в целевом каталоге необходимые каталоги или устройства.
Немного об используемом ПО. Все крутится под 64-битной RHEL6. Настроена связка php-fpm + nginx, о настройке которой, наверно, будет рассказано в другой заметке. Сайт лежит в /data/www/DOMAIN.COM. Используются популярные библиотеки/программы для работы с видео/графикой, т.е. ffmpeg и ImageMagick.

Установка php-fpm.
a) Установить репозиторий remi:
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6.rpm
b) Импорт GPG-ключа
rpmimport http://rpms.famillecollet.com/RPM-GPG-KEY-remi
c) yum -y install php-fpm

Настройка php-fpm.
Отмечу только те моменты, которые стоит изменить.

cat /etc/php-fpm.d/www.conf
; Название пула процессов
[www]
****
; Задаем пользователя, под которым будет работать php-fpm.
user = pf
; Тоже самое для группы.
group = pf
; При старте делать chroot в заданную директорию.
chroot = /data
chdir = /www/DOMAIN.COM
; Путь и параметры для отправки почты с помощью функции php mail()
php_admin_value[sendmail_path] = /usr/bin/mini_sendmail -t -fUSER@DOMAIN.COM -s192.168.0.x

****

Настройка nginx.

Параметры, которые будут передаваться FastCGI-серверу, т.е. Php-fpm. Обратите внимание, на закомментированные и рабочие строки. Nginx должен передать php-fpm параметры относительно корня chroot, т.е. НЕ /data/www/DOMAIN.COM, а /www/DOMAIN.COM.

cat /etc/nginx/fastcgi_params

fastcgi_param DOCUMENT_ROOT /www/DOMAIN.COM;
#fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SCRIPT_FILENAME /www/DOMAIN.COM$fastcgi_script_name;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Создание окружения для запуска скриптов (папки, файлы, библиотеки...)

Одна из самых интересных частей. Суть ее заключается в следующем: создаем необходимые папки в chroot-окружении, копируем необходимые библиотеки/файлы для работы сайта. Объем библиотек достаточно большой, надо внимательно скопировать нужные, в сети много скриптов, которые могут сделают за вас эту работу, но в первый раз рекомендую сделать вручную, чтобы понять что к чему.

# cd /data/
# mkdir -p /data/{bin,etc,var,lib64,tmp,usr}
# mkdir -p /data/usr/{share,bin,lib64}
# chmod 1777 tmp
для запуска ffmpeg и convert php требуется shell, придется копировать внутрь chroot bash или dash на ваш выбор.
# cp /bin/bash bin
# ln -s bash bin/sh
# cp /etc/{hosts,localtime,nsswitch.conf,resolv.conf} etc
# cp -R /usr/share/zoneinfo usr/share
# cp /usr/bin/{ffmpeg,convert} usr/bin
# cp /lib64/libnss_dns* lib64
# cp /lib64/libnss_files* lib64

Теперь важный момент — часто php-скриптам требуется определять днс-имена и временные зоны. Нужно скопировать в chroot-окружение библиотеки libnss. Для проверки определения имен я использую print_r(dns_get_record('google.com'));
Для каждого выполняемого файла в chroot-окружении необходимо скопировать нужные библиотеки (если только файл не скомпилирован статически, что бывает достаточно редко).
# ldd /usr/bin/ffmpeg
# ldd /usr/bin/convert
# ldd /bin/bash
На экран будет выведен список необходимых библиотек для указанных программ. Данные библиотеки вместе с символическими ссылками копируете в chroot-окружение (то, что лежит в /lib64 -> /data/lib64; то, что лежит в /usr/lib64 -> /data/usr/lib64).

Запуск и разбор возникающих ошибок

1. Функция php mail().
Для использования в php-скриптах функции mail() нужно либо копировать sendmail со всеми необходимыми библиотеками, либо статически слинковать mini_sendmail. Поскольку готового пакета mini_sendmail для rhel6 в репозиториях нет, придется качать и компилировать вручную.


# make
Если нижеследующей ошибки не возникает — можно пропустить.
gcc -O -s -static mini_sendmail.o -o mini_sendmail
/usr/bin/ld: cannot find -lc

Решение:
Нужно установить пакет glibc-static, который содержит все необходимые библиотеки для статической линковки программ.
# yum install glibc-static

Необязательный пункт, но все же.
Отредактируйте файл mini_sendmail.c, найдите строку:
username = getlogin();
заменить на:
username = "mini_sendmail";//getlogin();
Причем, на что вы измените имя юзера (username) роли не играет, просто это позволит избежать вызова функции getlogin() для определения вызывающего пользователя.
Для запуска необходим bash (sh) - нужно скопировать в chroot-директорию, а также скопировать нужные ему библиотеки.

2. Ошибка «php timezone database is corrupt»
Проверьте скопировали ли вы файлы /usr/share/zoneinfo в chroot.

3. Не пишутся логи ошибок php-fpm
проверьте есть ли директория /var/log/php-fpm/ внутри chroot и есть ли права у пользователя, под которым запускается php-fpm, на запись/создание файлов в данной папке.

4. Пляски вокруг ImageMagick
Появляются ошибки вида:

convert: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/589.

Пришлось много гуглить, кто предлагает переустановить ImageMagick, кто скачать и перекомпилировать исходники, кто пользоваться библиотекой gd, вообщем рецептов много — выбирай на вкус. Оказалось все гораздо проще — надо скопировать необходимые конфигурационные файлы (*.xml) из папки /usr/lib64/ImageMagick-$version/ в /data/usr/lib64/ImageMagick-$version/

5. Сессии.

Почти внезапно перестали работать сессии. Связано с тем, что необходимого каталога нет в chroot-окружении. Выходов есть несколько: либо вести сессии в базе данных, либо создать необходимые папки с правами в chroot-окружении, либо изменить значение пути где хранятся сессии на /tmp.

Литература: