Участник:Rain/Заметки/Onyx
Заметки по серверам для carid.com:
Что хотелось бы сделать
Кодировки MySQL
Навести порядок с кодировками базы. Сейчас в настройках на большинстве серверов указан (а местами не указан, а просто используется старое дефолтное значение) latin1. При этом в коде явно указывается использовать юникод через
SET NAMES 'utf8'
(иначе бы не получалось сохранять всякие там "®" и прочие юникодные символы) - хотя кое-где стоит
SET NAMES 'latin1'
(но такие места не должны вызвать проблем, в дальнейшем их можно поправить). Т.е., реально настройки указываются одни, база в свойствах таблиц указывает latin1, а реально данные хранятся другие; как следствие - имеем проблемы при работе с дампами.
По-идее, в настройках сервера можно сходу указать правильные параметры подключения - это не должно сломать текущую логику работы (нужна проверка на тестовом сервере); кодировка все равно задается через set names (но не уверен, что именно происходит при репликации и в чем (и какими настройками это регулируется) там передаются данные). Для перехода на правильные настройки можно использовать следующий алгоритм:
- Прописать правильные настройки на Master-сервере
- Перевести slave-алиасы на мастер-сервер
- STOP SLAVE; на слейв-сервере
- Одновременно перезапускаем Master-сервер
- Заливаем дамп напрямую с Slave-сервера на Master-сервер, заменяя в потоке charset в дампе на юникодный и проверив, что льется юникодный поток.
- Снимаем уже правильный дамп с Master-сервера
- Настраиваем Slave-сервера на работу с юникодом
- Восстанавливаем работу Slave'ов
- Переключаем slave сайта на восстановленные слейвы.
По-идее, основная часть работы (и downtime сайта) займет время однопоточной заливки дампа (т.е., минут 30). Как вариант - написать скрипт, который будет дампить и заливать базы впараллель, тогда downtime уменьшится минут до 10.
- Дамп на бэкапе должен сниматься с default-charset=latin1 и skip-character-set
- Дамп на import.carid.com должен сниматься без ключей
- Заливаться дамп везде должен с default-charset=latin1
- На бэкап-сервере кодировки сервера и клиента различаются (latin1 и utf8) без каких-либо настроек в конфиге мускуля
Ссылки
- Вариант с использованием ALTER smth - не надо переливать данные, но придется перебрать все колонки всех таблиц.
- Русская статья по конвертации + см. комментарии. Вариант с ALTER может не работать.
- Полезная табличка с описанием переменных для кодировок
InnoDB
Перевод базы на InnoDB. Считаю, что это решит нашу текущую проблему с локами базы при смешной нагрузке (как в случае с мастером, когда маленький апдейт лочит все остальные select'ы и они отжирают все доступные подключения - пример такой ситуации у меня есть; так и в случае со слейвом, когда пришедший репликационный запрос лочит вычитку - а в этот момент, например, какой-то скрипт активно использует сервер - в итоге все надолго умирает и идет отставание репликации - по-идее, благодаря версионности InnoDB репликация должна проходить проще. Можно достаточно легко проверить, переведя какой-то слейв на InnoDB и запустив на нем тяжелый скрипт, делающий много вычитки). На данный момент сменить тип движка нельзя для следующих таблиц:
Используется FULLTEXT: xcart_categories_index xcart_extra_field_values xcart_make_model xcart_order_details xcart_order_messages xcart_products xcart_users_map Ошибка при конвертации: "ERROR 1075 (42000) at line 1: Incorrect table definition; there can be only one auto column and it must be defined as a key" в xcart_counters
- с ошибкой разобраться, для остальных таблиц потенциально можно вынести поиск в отдельную маленькую таблицу, оставив ее в MyISAM (требует правки кода, так что в крайнем случае можно оставить их как есть - все же лучше иметь 8 лочащихся таблиц, чем 300; однако среди них есть достаточно крупные с частым обращением).
Само по себе изменение остальных таблиц должно пройти гладко; на время конвертации можно переключить Slave-сервера на мастер (т.к. мастер мощный, а слейв могут долго работать с таблицей; как следствие - отставание репликации). Помимо ликвидации табличных локов, это позволит держать всю базу в оперативной памяти, т.е., будет не особо важно, насколько быстрый диск (остальные параметры на тему сброса данных на диск можно потюнить).
Момент, необходимый для рассмотрения - держать ли все таблицы в одном ibdata-файле или нет. С одной стороны работа с таблицами, разделенными по файлам проще (нагляднее, проще для восстановления, наглядно видно занимаемое и свободное место, можно мигрировать с диска на диск на ходу (а надо ли, если замена диска все равно подразумевает отключение сервера?) и т.п.), с другой - в случае использования одного файла можно указать в качестве файла полностью FIO Drive - без таблицы разделов (привет выравниванию) и без файловой системы (привет фрагментации).
До этого момента рассматривать варианты, вроде перехода на MySQL-кластер или Percona-сервер - бред, так как первое, фактически - мультимастер-сервер с синхронной репликацией (и не самым хорошим движком), второе хорошо прежде всего XtraDB (который модифицированный InnoDB - т.е., опять-таки упираемся в переход на InnoDB).
После решения проблем подобных миграций при недостатке производительности (но не ранее) можно рассматривать переход на другие базы (на случай, если векторы развития MySQL и остальных баз не изменится) - на данный момент это MariaDB+XtraDB или Percona Server.
Про Foreign Key к Богдану - момент не понял, ведь если его явно не задавать, то возможностью можно просто не пользоваться и проблем это не вызовет.
- Разобрались, просто не поняли друг друга.
Ссылки
Оптимизация использования MySQL-серверов, отказоустойчивость
Потенциально можно раскидывать запросы чтения с основного сайта с Master на Slave-сервер для разгрузки мастер-сервера. Подобные оптимизации можно делать только после ликвидации локов (что даст ускорение репликации и большую синхронность между серверами; как следствие - более корректную вычитку данных приложением).
Варианты реализации:
- На уровне приложения. Объявить новую переменную с подключением к слейву, подключения на вычитку данных цеплять на эту переменную. Требует правки кода и знания того, как работает сайт, поэтому пока труднореализуемо.
- Как подпункт: в дальнейшем в таком варианте можно сделать, например, балансировку на уровне DNS'a - объявить для алиаса несколько IP-адресов и он в round robin-режиме будет отдавать разные сервера.
- На уровне подключений:
- mysql-proxy. Без наведения порядка с кодировками не взлетит, так как раскидывает подключения на уровне запросов (т.е., set names может уйти на один сервер, а запрос - на другой и получим кашу. Как вариант - жестко задать настройки (пусть и неправильные), чтобы на любой коннект принудительно устанавливалась нужная кодировка (т.е., set names в конфиге сервера) - должно помочь, но требует проверки). Прост в настройке, может раскидывать запросы на запись и чтения по разным серверам (в т.ч. несколько серверов чтения)
- haproxy. Рулит подключениями на уровне TCP-соединений. Более навороченный вариант, требует больше настройки.
Еще оптимизация - можно сделать Master-Master-репликацию. Тут есть 2 подпункта:
- Можно вынести админку, с которой работают импортеры/апдейтеры и прочие отделы на другой мастер-сервер при условии малого пересечения таблиц, в которые пишет админка и сайт (подразумевается, например, что посетитель не пишет в таблицу с перечнем товаров, в которую пишет сотрудник и т.п. Как подвариант - пересекающиеся таблицы писать только на один сервер для исключения ситуации split brain'a)
- HA-кластер. Умирает один мастер - переключаемся каким-то средством балансировки на другой (через haproxy/mysql-proxy/heartbeat и т.п.). Пока второй мастер живой - используется для админки (1-й пункт) или как слейв. Плюс как слейв можно завести 3-й сервер (освободившийся от memcached, например). На пару с избавлением от центрального memcached получим полностью отказоустойчивую систему.
Memcached
Убрать единый сервер Memcached и создать собственный Memcached на каждом веб-сервере. Плюсы:
- Убираем единую точку отказа
- Убираем оверхед при перегонке мелких данных по сети.
- Не держим лишний мощный, но практически не используемый сервер
Недостаток такого варианта - выделение памяти на каждом сервере. На деле из 36 Гб на веб-серверах используется 2-3 Гб. Memcached за долгое время набрал данных лишь на 8 Гб (на момент написания текста), из них многое - из-за постоянных тестов. Эффективность кэша на момент 8 Гб - порядка 80 процентов (update: 80 процентов из всех выборок чтения. На деле доля удачных чтений из всех запросов на уровне 60 процентов), что мало. Итого, если выделить даже по 16 Гб под memcached на каждом сервере - этого с головой хватит и для нужд веб-сервера, и для memcached. По процессору - даже единый memcached практически не нагружает процессор (нагрузка на уровне пары процентов для одного ядра сервера). При разделении нагрузка на каждый отдельный memcached уменьшится до 3 раз на текущий момент. Когда начнем упираться в процессор на веб-сервере - наличие на нем memcached будет далеко не самой большой проблемой (иначе говоря, мы скорее заведем новый сервер впараллель к трем существующим, чем упремся в процессор).
Варианты реализации:
- Репликация данных: не затрагивает приложение, но repcached на данный момент умеет работать только в режиме master<->master или мастер с несколькими слейвами (кстати, пробовал репликацию цепочкой - не взлетело, да и не является отказоустойчивой). Для наших трех серверов не подходит. Из того, что протестировал между двумя серверами - плюс в том, что при восстановлении сервера реплицируются все данные, т.е., снова разогревать кэш не придется.
- Redis. Проблемы с репликацией те же, что и в первом пункте, в остальном вроде как является более быстрой альтернативой memcached (что пока не требуется).
- Использовать средства приложения: Богдан говорит, что приложение при легкой правке кода может принимать массив серверов, при этом можно указывать их вес (т.е., для 127.0.0.1 указать максимальный приоритет, для других узлов - меньший).
while sleep 1
do
clear
echo -e "stats\nquit" | nc localhost 11211 |
awk '
/cmd_get/{cg=$3}
/cmd_set/{cs=$3}
/get_hits/{gh=$3}
/delete_misses/{dm=$3}
/delete_hits/{dh=$3}
END {
t=cg+cs+dm+dh
dt=dm+dh
print "Report: \t[R: "cg/t*100"% (only "gh/t*100"% successful) + W: "cs/t*100"% + D: "dt/t*100"% (only "dh/t*100"% successful)] from "t" total requests"
}'
done
Тест латентности сети
Провел небольшой тест на латентность сети при работе с мелкими данными в кэше.
Скрипт:
<?php
$m = new Memcached();
$m->addServer("$argv[1]", "$argv[2]");
for ($i = '1'; $i <= "$argv[3]"; $i++) {
$a=rand().rand().rand();
$m->set("$i", "$a");
}
?>
Для Ъ: создание указанного 3-м параметром числа ключей и занесение в каждый из ключей рандомного числа.
Было сделано 4 тестирования - скрипт на локалхосте + memcached на локалхосте, скрипт на локалхосте + memcached на машине в локальной сети и для обоих вариантов скрипт и memcached менялись местами.
100 Мбит
Линк 100 Мбит (Реально сервер подключен к гигабитному свичу, но десктоп - к 100 Мбит. При случае протестирую на полностью гигабитной сети). Результаты повторяемые:
Тест на десктопе:
Все локально:
rain@debian:~$ time php /tmp/phpset.php localhost 22122 1000000 real 0m28.818s user 0m7.656s sys 0m6.068s
Memcached на другой машине в сети:
rain@debian:~$ time php /tmp/phpset.php 10.0.2.2 22122 1000000 real 1m58.699s user 0m7.284s sys 0m5.788s
Тест на удаленной машине:
Все локально:
rain@developer:~$ time php /tmp/file.php 10.0.2.2 22122 1000000 real 0m34.526s user 0m6.844s sys 0m12.541s
Memcached на другой машине в сети:
rain@developer:~$ time php /tmp/file.php 10.0.2.19 22122 1000000 real 2m0.241s user 0m12.253s sys 0m15.245s
1 Гбит
Сеть vs Сокет
Сделал еще тест для сравнения скорости работы через сеть и через unix-сокет. Правда, для этого пришлось перейти на php5-memcache (php5-memcached не хотел подключаться к сокету - или я что-то не так сделал). Соответственно, по правкам скрипта - new Memcache() и connect вместо addServer. Тест сделан на одной и той же незагруженной машине с двухядерным процессором. Результаты:
Сокет:
root@developer:~# time php file.php unix:///tmp/mem.sock 0 1000000 real 0m30.652s user 0m10.109s sys 0m9.465s
Сеть:
root@developer:~# time php file.php 127.0.0.1 22122 1000000 real 0m41.677s user 0m11.513s sys 0m15.353s
Результаты стабильно повторяемы.
Ссылки
- https://www.linux.org.ru/forum/admin/7465868 - пронаблюдать тред
- Аналогичная моей проблема c репликацией цепочкой
Безопасность
Web
Soft
- Apache/nginx на веб-серверах сейчас работают через права группы (контент под carid:users, Апач - под apache:users (почему-то :) кроме 2-го веба), nginx - через nginx:users), но контент часто имеет права 666 или 777. Определиться, нужна ли запись данных Апачем в каталоги сайта; если да - перевести Апач под пользователя сайта, если нет - просто переключить с users на выделенную группу (см. ниже).
- Запретить выполнение скриптов из каталогов аплоада файлов (/images, /files и вообще любых каталогов, где могут появляться файлы) (без разницы, аплоадятся они через веб или FTP). На данный момент в images/ есть ряд скриптов сомнительной нужности (в этом каталоге):
root@345735-web1:/home/carid/httpdocs/images# find . -iname "*.php" ./mcafee3.php ./ebay/left_menu.php ./ebay/contact.php ./ebay/header_menu_d.php ./gps-systems/garmin/downloads/script.php
- По возможности перенести их в другое место, а каталог закрыть.
PHP
- Позапрещать ненужные функции в настройках PHP. Сейчас свободно работают всякие там system, exec и прочее, что позволяет свободно пользоваться веб-шеллами (проверено). При использовании багов в коде сайта по серверу можно свободно разгуливать и запускать программы с правами apache (48).
- Набросок однострочников для поиска ненужных функций:
# Поиск функций в коде
LANG=C grep -hEIro --include="*.php*" "[ ^]\b[a-z0-9_]+\(" /home/carid/httpdocs/ | sed -r 's/\(|^ //g' | sort -u > carid_func_list
# вывод доступных функций в PHP
php -r '$functions = get_defined_functions();sort($functions['internal']);print_r($functions['internal']);' 2>/dev/null | awk '/[0-9]\] =>/{print $3}' > php_func_int
# Показ используемых встроенных функций
fgrep -x -f carid_func_list php_func_int
# Показ неиспользуемых встроенных функций
fgrep -x -v -f carid_func_list php_func_int
# Поиск функций в коде
echo list_of_functions | tr ' ' '\n' | while read i
do
grep -HrEnIo --include="*.php*" "[ ^]\b$i\(" /home/carid/httpdocs/ || echo "${i}: NOT_USED"
done | awk '/NOT/; /\($/{gsub(/\(/, "", $2); gsub(/:$/, "", $1); print $2": "$1}' > flist
На данный момент в коде найдена 631 встроенная функция.
При тестовом запуске заметил, что в коде бывает встречаются реально не используемые функции - например, в модулях Zend'a (TODO: запросить у программеров, какие модули Zend'a и прочих фреймворков реально нужны) или в каких-нибудь OS-специфичных проверках - например, в ./modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php попалось такое: if (OS_WINDOWS && isset($section_text['RETURNS'])) { ob_start(); system($cmd, $return_value); и это единственное место использования system() в коде. Соответственно, можно безопасно это отключить.
Наброски списка функций для отключения:
# Остатки нагугленных функций, которые отключали другие люди. Не удалил на всякий случай, может пригодится.
# disable_functions = eval, PHP_SELF, highlight_file, ini_restore, ini_set, posix_setpgid, posix_setsid
# Не найденные в документации функции.
# proc, dll, max_execution_time, proc_show, cpuinfo, meminfo, cmd, uname, ftp, debugger_on, debugger_off, listen, ioctl, leak, ssthru, view_size
# Разное
disable_functions = dl, posix_mkfifo, chown, link, symlink, phpinfo, ftp_exec, chgrp, ssh2_exec, posix_setuid, posix_setgid, posix_kill, escapeshellarg, escapeshellcmd
disable_functions = syslog, closelog, define_syslog_variables, openlog
# Требуется проверка - функции могут для чего-то использоваться
disable_functions = chmod, set_time_limit, php_uname, posix_uname, disk_free_space, diskfreespace, disk_total_space, get_env, ini_get_all, ini_get, error_log
# Зависит от используемого варианта PHP. Работает только в том случае, когда PHP подключен через mod_php
disable_functions = apache_get_modules, apache_get_version, apache_note, apache_setenv
# Выполнение команд
disable_functions = shell_exec, exec, system, passthru, popen, proc_open, proc_nice, proc_get_status, proc_close, proc_terminate
# Работа с процессами
disable_functions = pcntl_alarm, pcntl_exec, pcntl_fork, pcntl_getpriority, pcntl_setpriority, pcntl_signal_dispatch, pcntl_signal, pcntl_wait
disable_functions = pcntl_waitpid, pcntl_wexitstatus, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped, pcntl_wstopsig, pcntl_wtermsig
- Проверка показала использование в коде 73 функций из списка выше (без тех, что требуют проверки, но с php_uname и posix_uname), из них 2 - в комментариях.
pcntl_waitpid: NOT_USED pcntl_wexitstatus: NOT_USED pcntl_wifexited: NOT_USED pcntl_wifsignaled: NOT_USED pcntl_wifstopped: NOT_USED pcntl_wstopsig: NOT_USED pcntl_wtermsig: NOT_USED pcntl_alarm: NOT_USED pcntl_exec: NOT_USED pcntl_fork: NOT_USED pcntl_getpriority: NOT_USED pcntl_setpriority: NOT_USED pcntl_signal_dispatch: NOT_USED pcntl_signal: NOT_USED pcntl_wait: NOT_USED shell_exec: NOT_USED /home/carid/httpdocs/include/classes/class.upload.php:424 exec: /home/carid/httpdocs/include/classes/Zend/Db/Adapter/Pdo/Abstract.php:256 exec: NOT_USED /home/carid/httpdocs/include/classes/class.upload.php:424 exec: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Builder.php:378 exec: /home/carid/httpdocs/modules/HTML_PDF/dompdf/load_font.php:231 system: NOT_USED /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:449 passthru: NOT_USED popen: /home/carid/httpdocs/payment/cc_saferpay.php:65 popen: /home/carid/httpdocs/payment/cc_saferpay.php:137 popen: /home/carid/httpdocs/include/func/func.https_ssleay.php:103 popen: /home/carid/httpdocs/include/func/func.https_httpscli.php:100 popen: /home/carid/httpdocs/include/func/func.https_curl.php:169 popen: /home/carid/httpdocs/include/func/func.https_openssl.php:108 popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Builder.php:442 popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:454 popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:535 popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:724 popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:247 proc_open: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:125 proc_open: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:131 proc_nice: NOT_USED proc_get_status: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:168 proc_close: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:173 proc_terminate: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:156 apache_get_modules: /home/carid/httpdocs/m1info.php:926 apache_get_version: NOT_USED apache_note: NOT_USED apache_setenv: NOT_USED syslog: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:84 syslog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:265 syslog: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:84 closelog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:237 define_syslog_variables: NOT_USED openlog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:177 dl: /home/carid/httpdocs/kmp/admin/ci_system/libraries/Image_lib.php:1458 dl: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:743 dl: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:748 dl: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:743 dl: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:748 posix_mkfifo: NOT_USED chown: NOT_USED link: /home/carid/httpdocs/include/classes/Zend/Feed/Entry/Atom.php:243 link: /home/carid/httpdocs/include/classes/Zend/Feed/Entry/Atom.php:252 link: /home/carid/httpdocs/include/classes/Zend/Feed/Atom.php:121 link: /home/carid/httpdocs/include/classes/Zend/Feed/Atom.php:130 symlink: NOT_USED phpinfo: /home/carid/httpdocs/wde-master/admin/general.php:63 phpinfo: /home/carid/httpdocs/kmp/admin/application/models/bugreportmodel.php:54 phpinfo: /home/carid/httpdocs/include/classes/Zend/Tool/Framework/System/Provider/Phpinfo.php:35 phpinfo: /home/carid/httpdocs/include/classes/class.upload.php:491 phpinfo: /home/carid/httpdocs/include/classes/class.upload.php:2986 phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:180 phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:574 phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:662 phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:902 phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:357 phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:410 phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:454 phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:722 phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:968 ftp_exec: NOT_USED chgrp: NOT_USED ssh2_exec: NOT_USED posix_setuid: NOT_USED posix_setgid: NOT_USED posix_kill: NOT_USED escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_doc_lib.php:22 escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_rtf_lib.php:25 escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_pdf_lib.php:24 escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_ppt_lib.php:31 escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:440 escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:447 escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:525 escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:529 escapeshellarg: /home/carid/httpdocs/modules/HTML_PDF/dompdf/load_font.php:231 escapeshellcmd: NOT_USED php_uname: /home/carid/httpdocs/wde-master/admin/general.php:104 php_uname: /home/carid/httpdocs/m1info.php:595 php_uname: /home/carid/httpdocs/include/classes/CyberSorce/CYBERSOURCE.php:199 php_uname: /home/carid/httpdocs/include/classes/Zend/Mail/Storage/Writable/Maildir.php:417 php_uname: /home/carid/httpdocs/include/classes/Zend/Mail.php:1117 php_uname: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:311 php_uname: /home/carid/httpdocs/check_requirements.php:346 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/DependencyDB.php:452 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Dependency2.php:275 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Registry.php:780 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:26 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:88 php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:129 php_uname: /home/carid/httpdocs/modules/HTML_PDF/dompdf/include/functions.inc.php:205 posix_uname: NOT_USED
- Использовать open_basedir - сейчас доступ к файловой системе через PHP для основного сайта никак не ограничен; для доменов на mail.carid.com кое-где указан, но "/tmp" используется общий для всех сайтов
- По возможности актуализировать (и поддерживать в дальнейшем) версии используемых фреймворков и прочих веб-компонентов:
- /home/carid/httpdocs/include/classes/Zend/Version.php: текущая версия 1.11.7, актуальная: 1.11.11, changelog (и далее)
- /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2: текущая версия 1.7.2 (Rel: 2008-05-17), актуальная: 1.9.4 (Rel: 2011-07-07), changelog (+более ранние), + проверить используемые модули.
- /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php: текущая версия 1.7.1 (Rel: 2008-02-03), остальное аналогично предыдущему.
- Протестировать связку suhosin + mod_security + fail2ban
FTP
- /etc/proftpd.conf@mail.carid.com: Umask 027
Ссылки
Общее
Сервисы
Общее
- Полностью выпилить Mail-сервера (smtp, pop/imap) на вебах и DB-серверах, перейти на nullmailer-like пересылку с форвардом на mail.carid.com - избавление от лишних потенциально уязвимых сервисов, требующих обслуживания.
- Все bounced-письма или недоставленные сообщения должны собираться на mail.carid.com
- Убрать automount. Идет в дефолтной поставке и на серверах не выполняет ничего полезного. После этого можно будет убрать каталоги /misc, /net
- Определиться с софтом, необходимым хостеру. На данный момент непонятный статус у следующих процессов:
Web: dsm_* rhnsd snmpd Mail: + brcm_iscsiuio + iscsid + *simpana* (cvd, EvMgrC) ---- + miniserv WebMin'a
- Сделать аудит crontab'ов и периодически запускаемых процессов в них, расписать, зачем нужен каждый скрипт и кем (по чьему запросу) он был добавлен.
- После удаления лишних сервисов удалить ненужные, временные и т.п. аккаунты.
- Пообновлять пароли на серверах, перейти на sha512-хэши.
- Ввести политику использования ssh-ключей, запретить использование парольного входа, запретить рут-логин, (запретить туннели?).
- Избавиться от реальных пользователей для proftpd на mail.carid.com, перейти на виртуальных
- Определиться со списком нужных пользователей и тем, куда они должны ходить; далее либо перевести proftpd под nobody, а для каталогов сделать UserOwner/GroupOwner <юзер/группа сайта> (это сейчас не работает, хоть и встречается в конфиге), что попутно позволит избежать проблем с правами, либо (если заработает) использовать одного пользователя/группу в файле описания виртуальных пользователей.
Заработает. Делаем что-то вроде: AuthUserFile /etc/proftpd/auf # Или вообще выпилить обычных системных юзеров и разрешить только тех, которые описаны в файле выше - т.е., убрать mod_auth_unix.c AuthOrder mod_auth_file.c mod_auth_unix.c RequireValidShell off в конфиге сервера, после чего echo PASSWORD | ftpasswd --passwd --gid=2521 --file=/etc/proftpd/auf --md5 --not-system-password --name USER --shell /usr/sbin/nologin --uid 10001 --home=/bla/bla/images --stdin Получаем кучку виртуальных юзеров, работающих с контентом под одним пользователем, но с различающимися логинами. В GECOS можно загнать полные имена, чтобы потом проще было находить виновных :). Файлик читается юзером proftpd (или тем, кто определен в конфиге как User), т.е., он должен иметь права на чтение файла (думаю, есть смысл сделать proftpd:nobody 640)
- Перевод SUID-бинарников на группы
find / -xdev -perm -4000 -ls
groupadd -r suid
bins='/bin/su /bin/ping /bin/mount /bin/ping6 /bin/umount /usr/bin/chsh /usr/bin/chfn /usr/bin/newgrp /usr/bin/passwd /usr/bin/gpasswd /sbin/mount.nfs'
chown :suid $bins
chmod 4750 $bins
find / -xdev -perm -4000 -ls
Web
- Убрать vsftpd (FTP на веб-серверах не нужен, все изменения делаются через мастер-сервер, для того, чтобы забрать какой-то файлик с веба (логи, например) есть NFS)
- Убрать xinetd (не несет никакой полезной нагрузки, просто лишний сервис)
- atd (вроде нигде не используется)
- mysqld (не используется, нет ни одной базы)
- После изменений архитектуры определить, нужен ли отдельный mysql-сервер на mail.carid.com - как минимум определиться с тем набором баз, которые в данный момент на нем есть.
Вроде используется для CPanel, но кроме него в базе есть еще куча мусора, вроде старой копии базы для carid
- Убрать xinetd: через него запускаются только почтовые сервисы (qmail и т.п.), ftp и rsync. Почта и FTP используются постоянно, у нас не так мало ресурсов, чтобы использовать суперсервер, поэтому можно перевести их в standalone-режим. rsyncd как демон теперь не используется.
- Убрать rsyncd. Заменен lsync'ом, который работает с rsync через ssh.
SQL-DB-сервера
Определиться с тем, какие у нас сервера будут работать (в т.ч. определиться по архитектуре и требуемой мощности серверов), потом смотреть сервисы
NOSQL-сервер (memcached)
Потенциально можно убрать вообще. На данный момент, помимо перечисленного в общем разделе, из лишнего там работают:
- vsftpd
- mysqld
- xinetd
Файловая система
- Сделать лучшую разбивку дискового пространства на разделы, использовать запрещающие опции монтирования для разделов, доступных на запись, использовать квоты.
Кандидаты на вынесение на другой раздел: /home/ (особенно для Web'ов, где в /home хранится веб-контент) /var /var/log /usr (статический контент, можно даже сделать с RO, но надо проверить работоспособность бэкапа - или доработать скрипты) /tmp (кое-где уже есть) /var/qmail/ для Mail-сервера /var/lib/mysql/ вынести в отдельный каталог (по аналогии с master-серверами) и на отдельный раздел /home/carid/httpdocs/var/ на вебах вынести в /var/log/<что-то> или просто на отдельный раздел. /var/run и /var/lock - подумать насчет вынесения в tmpfs
- На вебах и master-сервере сменить права на контент на 640(750), раз в сутки делать поиск по cron'у файлов с кривыми правами и фиксить.
- Убрать дефолтную системную группу (users, 100) для веб-контента, использовать выделенную группу (завести группу carid, например, сделать ее основной для пользователя carid).
- nginx перевести в эту группу (ему надо только читать контент - хватит и группы с RO-правами)
Разное
Заметки на различные тематики / для сортировки:
- Варианты балансировки обращения к базе:
- mysql-proxy (ro, rw)
- haproxy (ro, rw)
- DNS round robin (ro)
- iptables DNAT range (ro)
- Оптимизация/изменение настроек MySQL:
- Увеличить время хранения бинлогов/relay-логов - должно с запасом покрывать выходные, т.е., 3-4 дня.
- Не запускать slave-сервер автоматом при перезапуске.
- Вынести каталог с сервер-специфичными файлами (в частности, var) из каталога httpdocs
- Было бы интересно собрать полную (в т.ч. User Agent'ы) статистику посещений сайта.
- LOW_PRIORITY_UPDATES актуально только для движков с табличными локами, т.е., на InnoDB апдейты будут идти с нормальным приоритетом.
- Перейти на RAID10 на Slave-сервере. 5-й сильно уж тормозит - дамп заливался несколько часов против 40 минут (при тесте на RAID10 на Mail-сервере). RAID5 неприменим для базы.
root@345731-mail1:~# time { pv carid_2012_02_20.sql.bz2 | pbunzip2 -c | mysql -hlocalhost -uroot -p'pass' raidtestdb ; }
1.85GB 0:40:09 [ 803kB/s] [===================================================>] 100%
real 40m20.638s
user 16m31.050s
sys 0m20.355s
- По работающей в данный момент почте на серверах:
- memcached: почта не работает совсем. Postfix шлет почту на полное имя, не может отрезолвить домен, бонсит мыло опять-таки на полный домен, которое тоже никуда не приходит. Про то, что он отвечает за *db2* - не знает, так как в базе mydestination - левый домен.
- old db: В конфиге есть mynetworks = 1.1.1.1/32. По использованию: шлются отчеты по обновлениям на rgerashenko
- slave: почтой явно давно не пользовались, в логах за последнее время пусто
- master: По использованию - аналогично с old db
- web1: в mydestination кривой домен получателя - стоит web2 (да еще и hostname!=mailname, что создает свои проблемы), но локально почта пытается работать благодаря тому, что @web1.carid.com резолвится. На деле - см. memcached. В конфиге разрешен релей для 1.1.1.1/32. "mail for web1.carid.com loops back to myself".
- web2: Полностью аналогичен web1, только в качестве левого домена указан web3
- web3: Домен в mydestination соответствует хостнейму (но не mailname, как и на остальных серверах), поэтому почта так же само зацикливается. Разрешенный релей - 1.1.1.1/32.
- monit на все основные сервисы на всех серверах
- Восстановить Nagios, скорректировать работу его и/или серверов для снижения текущего числа уведомлений.
- Максимально запретить crontab'ы, особенно на веб-серверах.
- Аудит модулей Апача на вебах, удаление лишних (показ загруженных: apachectl -t -D DUMP_MODULES 2>&1)
- Сделать ежедневный (минимум, а можно и несколько раз в день) снапшот контента веб-сайта на мастер-сервере (минимум (для быстрой развертки контента в случае аварии), как вариант - еще где-то на стороне, в изолированном от боевых серверов месте), хранить снапшоты хотя бы за неделю. В случае с мастером надо определиться с хостерской backup-системой, чтобы она не начала бэкапить 100500 снапшотов одного и того же контента по 100 Гб каждый.
td="/home/carid/snapshot/$(date +%Y/%m/%d)" ; mkdir -p "${td}" ; cp -al /home/carid/httpdocs/ ${td}
- Вспомнить, зачем на вебах apache в группе nagios'a (если это делал я)
- Повыявлять и сделать аудит существующих костылей "напарничка" на серверах; убрать лишние и то, что с ними связано. На данный момент из найденного:
- @web{1..3}: /etc/logrotate.d/maillog - cat'ает maillog в несуществующий файл, после чего запускает /home/carid/scripts/mailanalyse.sh. Тот в свою очередь пытается подключаться на старую офисную базу, обламывается, в результате чего на серверах днями висят ветки процессов cron->logrotate->mysql. Ненужность: 1) Оно в любом случае не работает; 2) maillog'ов на вебах не будет вообще.
- /home/carid/scripts содержит только упомянутый скрипт (и его вариации), поэтому после зачистки можно каталог полностью удалить.
- @web{1..3}: /etc/logrotate.d/maillog - cat'ает maillog в несуществующий файл, после чего запускает /home/carid/scripts/mailanalyse.sh. Тот в свою очередь пытается подключаться на старую офисную базу, обламывается, в результате чего на серверах днями висят ветки процессов cron->logrotate->mysql. Ненужность: 1) Оно в любом случае не работает; 2) maillog'ов на вебах не будет вообще.
Лишние пакеты
Собирательный раздел для лишних пакетов (например, установленных, но неиспользуемых/нерабочих сервисов), а также сервисов, подлежащих удалению, согласно описанному выше.
Service | Web (все) | Master | Old | Slave | Memcached | |
---|---|---|---|---|---|---|
httpd | X [1] | X [2] | X [3] | X [1] | ||
nginx | X [4] | |||||
autofs | X | X | X | X | X | X |
xinetd | X | X [5] | X | X | X | X |
subversion | X | X [3] | X [3] | X [3] | X [3] | |
postfix | X [6] | X | X | X | X | |
dovecot | X | X | X | X | X | |
squirrelmail | X | X | X | X | X | |
webalizer | X | X | X | X | ||
bind | X [7] | X | X | X | X | |
spamassassin | X | X | X | X | X | |
cyrus-sasl* | X | X | X | X | X | |
vsftpd | X | X | X | X | X | |
sendmail | X | X | X | X | X | |
ppp | X [7] | X[7] | X[7] | X[7] | X[7] | X[7] |
rsyncd | X [8] | |||||
mysqld | X | X | ||||
php-* | X | X | X | X |
- ↑ 1,0 1,1 работает, никуда не смотрит. Присутствуют конфиги для webalizer, squirrelmail и т.п.
- ↑ пытается запуститься, но фейлится на своей конфигурации
- ↑ 3,0 3,1 3,2 3,3 3,4 отключен в init-скриптах
- ↑ работает, есть конфиг для carid
- ↑ Mail и FTP перевести на standalone
- ↑ После перехода на nullmailer
- ↑ 7,0 7,1 7,2 7,3 7,4 7,5 7,6 установлен, но не запущен и не используется
- ↑ Не является отдельным пакетом, необходимо просто удалить запуск в xinetd и конфиги
Что сделано
На данный момент из полезного сделано:
Разное
- inotify-based синхронизация контента между 6 (master -> web{1,3}/import/backup) серверами. Практически не вызывает нагрузки, контент копируется в реальном времени.
www@import.carid.com
*/15 * * * * RSYNC_PASSWORD="djh8PKq" /usr/local/bin/rsync -rzt carid@50.56.1.164::images/ /www/import.carid.com/images > /dev/null 2>&1
0 */1 * * 1,2,3,4,5 RSYNC_PASSWORD="djh8PKq" /usr/local/bin/rsync --exclude 'phpmyadmin/' --exclude 'phpmyadmin3/' --exclude 'import2/' --exclude 'images/' --exclude 'import/' --exclude 'config.php' --exclude 'config/config.xml' --exclude 'index.php' --exclude 'files/' --exclude 'var/tmp/' --exclude 'var/log/' --exclude 'var/templates_c/' --exclude 'var/cache/' --exclude 'wde-master/admin/.htaccess' --exclude 'include/refine_search_detection.php' --exclude 'csv_parser/' --exclude '.htaccess' --exclude='.svn' -rzt carid@50.56.1.164::httpdocs/ /www/import.carid.com > /dev/null 2>&1 && /bin/rm -f /www/import.carid.com/var/templates_c/* > /dev/null 2>&1
root@mail
* * * * * /root/bin/ftpwatch2sql.sh
shell@mail>
fix /var/www/vhosts/carid.com/private/svn/svn_sync.sh
carid@mail
* * * * * /usr/local/bin/psqlftpfile.sh 2>>/tmp/sync.log
0 2 * * * rsync -trvn --del --exclude='wde-master' --exclude='.svn' --exclude='/config.php' --exclude='config/*' --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web3:/home/carid/httpdocs/ | mail -s "Master->web3 rsync report" team.admins@onyxenterprises.com
0 2 * * * rsync -trvn --del --exclude='wde-master' --exclude='.svn' --exclude='/config.php' --exclude='config/*' --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web2:/home/carid/httpdocs/ | mail -s "Master->web2 rsync report" team.admins@onyxenterprises.com
0 2 * * * rsync -trvn --del --exclude='wde-master' --exclude='.svn' --exclude='/config.php' --exclude='config/*' --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web1:/home/carid/httpdocs/ | mail -s "Master->web1 rsync report" team.admins@onyxenterprises.com
carid@web{1,2,3}
0 * * * * sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7 rsync -rqvt carid@192.168.100.164::files/ /home/carid/httpdocs/files >> /tmp/sync.log
0 * * * * sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7 rsync -rqvt carid@192.168.100.164::pages/ /home/carid/httpdocs/skin1/pages >> /tmp/sync.log
0 * * * * sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7 rsync -rqvt --delete carid@192.168.100.164::images/ /home/carid/httpdocs/images >> /tmp/sync.log
*/30 * * * * scp -rp mail1:~carid/httpdocs/authorized-installers ~carid/httpdocs/ > /dev/null 2>&1
0 8 * * 1,3,5 scp -rp mail1:~carid/httpdocs/sitemaps ~carid/httpdocs > /dev/null 2>&1
Web
- /var/www/vhosts/carid.com/httpdocs/images/mcafee3.php вынести с вебов (он везде одинаковый и генерит одну картинку, которую можно просто создавать на мастере)