Участник: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 Гб (на данный момент - 13), из них многое - из-за постоянных тестов. Эффективность кэша на момент 8 Гб - порядка 80 процентов, что мало. Итого, если выделить даже по 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 для carid на вебах
- Аудит модулей Апача на вебах, удаление лишних (показ загруженных: 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 вынести с вебов (он везде одинаковый и генерит одну картинку, которую можно просто создавать на мастере)