Участник:Rain/Заметки/Onyx

Материал из Linux Wiki
Перейти к навигацииПерейти к поиску

Заметки по серверам для 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) без каких-либо настроек в конфиге мускуля

Ссылки

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 Гбит

ToDo: Сделать тест для гигабитной незагруженной сети

Сеть 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

Результаты стабильно повторяемы.

Ссылки

Безопасность

ToDo: Заполнить

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 (не используется, нет ни одной базы)

Mail

  • После изменений архитектуры определить, нужен ли отдельный 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 неприменим для базы.
Тест на Mail-сервере
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 содержит только упомянутый скрипт (и его вариации), поэтому после зачистки можно каталог полностью удалить.

Лишние пакеты

Собирательный раздел для лишних пакетов (например, установленных, но неиспользуемых/нерабочих сервисов), а также сервисов, подлежащих удалению, согласно описанному выше.

Service Web (все) Mail 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. 1,0 1,1 работает, никуда не смотрит. Присутствуют конфиги для webalizer, squirrelmail и т.п.
  2. пытается запуститься, но фейлится на своей конфигурации
  3. 3,0 3,1 3,2 3,3 3,4 отключен в init-скриптах
  4. работает, есть конфиг для carid
  5. Mail и FTP перевести на standalone
  6. После перехода на nullmailer
  7. 7,0 7,1 7,2 7,3 7,4 7,5 7,6 установлен, но не запущен и не используется
  8. Не является отдельным пакетом, необходимо просто удалить запуск в xinetd и конфиги

Что сделано

На данный момент из полезного сделано:

Разное

  • ­done! inotify-based синхронизация контента между 6 (master -> web{1,3}/import/backup) серверами. Практически не вызывает нагрузки, контент копируется в реальном времени.
Мусор, выкинутый после введения lsyncd
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

  • ­done! /var/www/vhosts/carid.com/httpdocs/images/mcafee3.php вынести с вебов (он везде одинаковый и генерит одну картинку, которую можно просто создавать на мастере)