Участник: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.

Ссылки

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 указать максимальный приоритет, для других узлов - меньший).

Тест латентности сети

Провел небольшой тест на латентность сети при работе с мелкими данными в кэше.

Скрипт:


<?php

$m = new Memcached();
$m->addServer("$argv[1]", "$argv[2]");

for ($i = '1'; $i <= "$argv[3]"; $i++) {

$m->set("$i", "rand()");
}
?>

Для Ъ: создание указанного 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 на веб-серверах сейчас работает через права группы (контент под carid:users, Апач - под apache: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).
  • Использовать open_basedir - сейчас доступ к файловой системе через PHP для основного сайта никак не ограничен; для доменов на mail.carid.com кое-где указан, но "/tmp" используется общий для всех сайтов

FTP

  • /etc/proftpd.conf@mail.carid.com: Umask 027
Ссылки

Общее

Сервисы

Общее

  • Полностью выпилить Mail-сервера (smtp, pop/imap) на вебах и DB-серверах, перейти на nullmailer-like пересылку с форвардом на mail.carid.com - избавление от лишних потенциально уязвимых сервисов, требующих обслуживания.
  • Убрать automount. Идет в дефолтной поставке и на серверах не выполняет ничего полезного. После этого можно будет убрать каталоги /misc, /net
  • Определиться с софтом, необходимым хостеру. На данный момент непонятный статус у следующих процессов:
Web:

dsm_*
rhnsd
snmpd

Mail:

+ brcm_iscsiuio
+ iscsid
+ *simpana* (cvd, EvMgrC)

----

+ miniserv WebMin'a
  • Сделать аудит crontab'ов и периодически запускаемых процессов в них, расписать, зачем нужен каждый скрипт и кем (по чьему запросу) он был добавлен.
  • После удаления лишних сервисов удалить ненужные, временные и т.п. аккаунты.

Web

  • Убрать vsftpd (FTP на веб-серверах не нужен, все изменения делаются через мастер-сервер, для того, чтобы забрать какой-то файлик с веба (логи, например) есть NFS)
  • Убрать xinetd (не несет никакой полезной нагрузки, просто лишний сервис)
  • atd (вроде нигде не используется)
  • mysqld (не используется, нет ни одной базы)

Mail

  • После изменений архитектуры определить, нужен ли отдельный mysql-сервер на mail.carid.com - как минимум определиться с тем набором баз, которые в данный момент на нем есть.
Вроде используется для CPanel, но кроме него в базе есть еще куча мусора.
  • Убрать xinetd: через него запускаются только почтовые сервисы (qmail и т.п.), ftp и rsync. Почта и FTP используются постоянно, у нас не так мало ресурсов, чтобы использовать суперсервер, поэтому можно перевести их в standalone-режим. rsyncd как демон теперь не используется.
  • Убрать rsyncd. Заменен lsync'ом, который работает с rsync через ssh.

SQL-DB-сервера

Определиться с тем, какие у нас сервера будут работать (в т.ч. определиться по архитектуре и требуемой мощности серверов), потом смотреть сервисы

NOSQL-сервер (memcached)

Потенциально можно убрать вообще. На данный момент, помимо перечисленного в общем разделе, из лишнего там работает:

  • vsftpd
  • mysqld
  • xinetd

Файловая система

  • Сделать лучшую разбивку дискового пространства на разделы, использовать запрещающие опции монтирования для разделов, доступных на запись, использовать квоты.
  • На вебах и 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 неприменим для базы.

Что сделано

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

  • inotify-based синхронизация контента между 6 (master -> web{1,3}/import/backup) серверами. Практически не вызывает нагрузки, контент копируется в реальном времени.