Analitycs

Показаны сообщения с ярлыком mysql. Показать все сообщения
Показаны сообщения с ярлыком mysql. Показать все сообщения

воскресенье, 21 июля 2013 г.

Почему я не люблю ORM? или ORDER BY RAND() и все-все-все

Сервак тормозит так, что приехали, в базе - очередь как за колбасой в 1992 году.

SELECT TOP 1 g2_ImageBlockCacheMap.g_itemId FROM 
 g2_ImageBlockCacheMap LEFT JOIN
 g2_ImageBlockDisabledMap ON 
 g2_ImageBlockCacheMap.g_itemId=g2_ImageBlockDisable
 dMap.g_itemId WHERE g2_ImageBlockCacheMap.g_userId = 6 
AND g2_ImageBlockCacheMap
 .g_itemType = 1 AND g2_ImageBlockDisabledMap.g_itemId 
IS NULL ORDER BY RAND()

НИКОГДА!! СЛЫШИТЕ - НИКОГДА!! Не делайте "ORDER BY RAND()" на каждой странице(!) сайта под нагрузкой!!!

Екарный бабай, это ж FAQ любого собеседования.

 Вот именно поэтому я не люблю ORM и прочих "паразитов".

понедельник, 1 июля 2013 г.

В продолжение темы MySQL InnoDB

Так как Google+ не дает ответить на комментарий, то приведу кусок одной реплики тут

Отвечаю на свой же вопрос: можно. Тут вот есть описание миграции: http://dev.mysql.com/doc/refman/5.6/en/innodb-migration.html

Однако, я все же отказался от InnoDB в пользу MyISAM, после того, как сделал 30 Гб-ый дамп InnoDB базы и она восстанавливалась из дампа 8 дней (на Core i7 с 32Гб RAM).
Советовал бы всем кто столкнется с таким выбором, забить базу тестовыми данными ожидаемого объема и попробовать с ней поиграться: сделать дамп, восстановиться и т.д. Это наилучший показатель производительности..

Сейчас я работаю с MyISAM базами по 250-500 Гб, не хочу даже себе представлять, сколько бы занял перенос базы через mysqldump при использовании InnoDb..

Не все так однозначно.

 Для начала - перед восстановлением большого дампа InnoDB нужно отключить в сервере индексы и транзакции. Иначе - да, нужно много и долго ждать.

 >Это наилучший показатель производительности.

"Запорожец лучший в мире автомобиль, потому что влезает в самый маленький гараж" (c) ;-)
Это не так.

среда, 4 июля 2012 г.

Как восстановить ну ОЧЕНЬ большой dump MySQL?

Если дамп базы с боевого сервера MySQL весит НУ ОЧЕНЬ много, то для ускорения импорта в mysqld имеет смысл ВРЕМЕННО выставить следующие значения в my.cnf

set autocommit=0

unique_checks=0

foreign_key_checks=0

и перезапустить сервер

#sudo service mysqld restart

После импорта дампа -  нужно вернуть на место родные значения.

Для восстановления из бекапов - этот способ не рекомендуется,  он скорее - для разработческих серверов/копий.

понедельник, 14 мая 2012 г.

Как установить MySQL SSH tunnel?

Если вам нужно приконектится к внешнему MySQL, а его порт 3306 закрыт firewall, то быстрейший способ получить желаемое (кроме установки пива админу) - это установить свой собственный SSH tunnel - с гейшами и шахматами.

Делается это так.

ssh -f -L 8080:my.super.puper.host.ru:3306 -l remote_user another.my.super.system.org sleep 60

Понятно, что SSH на firewall должен быть открыт.

После установки туннеля - уже обращаемся к самому себе:

mysql -h 127.0.0.1 -P 8080 -u user -p database

Можно жить.

среда, 25 апреля 2012 г.

MacOS X - использование mysql из Zend Server

Для использования MySQL клиента из Zend Server под MacOS вместо установленного из портов (зачем тащить еще один порт - если mysql уже есть в системе? ) нужно сделать следующее:

1) проверить есть ли /etc/zce.rc -

$ /usr/local/zend/mysql/bin/mysql
/etc/zce.rc doesn't exist!

2) создать/отредактировать его

ZCE_PREFIX=/usr/local/zend
if [ -z "$LIBPATH" ];then
   LIBPATH=/lib:/usr/lib:/usr/local/zend/lib
else
   LIBPATH=$LIBPATH:/usr/local/zend/lib
fi
export LIBPATH
APACHE_VER=2.2.11
WEB_USER=qtmhhttp
WEB_GROUP=nogroup
APACHE_PID_FILE=
PRODUCT_NAME=ZendServer
PRODUCT_VERSION=5.0.0
export INSTALLATION_UID=091708121207
DIST=pe
JB_EN=true
ZEND_TMPDIR=/tmp

3) Сделать симлинк на зендовский клиент

sudo ln -s /usr/local/zend/mysql/bin/mysql  /usr/bin/mysql

Теперь можно работать - ну или собираем из портов, либо ставим MAMP (не люблю).

суббота, 17 марта 2012 г.

MD5 проверка PHP, Python и MySQL

Несколько лет поймал одну особенность - md5 суммы посчитанные в PHP и MySQL отличались(!!!) - но хоть убей не помню на каких версиях.

Из-за этого, кстати были большие проблемы... Сейчас решил проверить на всякий случай - совпадают.

PHP

php -r "echo md5('domains.txt');"
aeae2f628c54f10054e5c70076e1237b

md5sum

# echo -n "domains.txt" | md5sum
aeae2f628c54f10054e5c70076e1237b 

Python

# echo "import md5;print md5.md5(\"domains.txt\").hexdigest()" | python
aeae2f628c54f10054e5c70076e1237b

MySQL

SELECT MD5('domains.txt');

aeae2f628c54f10054e5c70076e1237b

Уф, отпустило ;-) Приступ паранойи навеян вот этой заметкой.

пятница, 20 января 2012 г.

Как полноценно включить UTF-8 для MySQL?

Что нужно добавить в /etc/my.cnf для полноценной поддержки UTF-8 в MySQL, включая вывод данных в консоли mysql


[mysqld]
default-character-set=utf8
default-collation=utf8_general_ci
character-set-server=utf8
collation-server=utf8_general_ci
init-connect='SET NAMES utf8'
 
[client]
default-character-set=utf8
 
[client]
default-character-set=utf8

среда, 18 января 2012 г.

mysqldump: Got error: 1449: The user specified as a definer ('user'@'x.x.x.x') does not exist when using LOCK TABLES

Диагноз

При попытке сдампить базу MySQL получаем ошибку

mysqldump: Got error: 1449: The user specified as a definer ('user'@'x.x.x.x') does not exist when using LOCK TABLES

Причина - отсутсвует пользователь который прописан в хранимых процедурах/триггерах.

Похоже, что эта ошибка возникает, когда исходный/изначальный дамп MYSQL импортируется в сервер с ключем "force" (-f - который игнорирует ошибки), а потом его пытаются сохранить с этой машины.

Лечение

Вариант 1

Правим хранимую процедуру и дампим заново

use mysql;
select * from proc;

Вариант 2

1. Создаем пользователя

GRANT ALL PRIVILEGES ON *.* TO 'misseduser@*' IDENTIFIED BY 'some_pass' WITH GRANT OPTION

2. Дампим базу

3. Правим в дампе куски с отсутсвующими пользователями на CURRENT_USER Ищем что-то типа

/*!50013 DEFINER=`missed user`@`some_host` SQL SECURITY DEFINER */

и

DEFINER=`some_user`@`some_host`

заменяется на

DEFINER=CURRENT_USER

По мотивам этой заметки.

пятница, 13 января 2012 г.

Установка Ubuntu с помощью Wubi - редкостное гуано

Мое знакомство с десктопными Linux (в отличие от серверных) обычно происходило достаточно эпизодически - поставил-настроил-поигрался-забыл.

Еще в 90 годы несколько раз пытался полноценно мигрировать на Linux различных версий - BlackCat, RedHat и т.д. обычно эти попытки заканчивались тем, что потрахавшись с настройкой Иксов, модема и прочего - я настраивал все что можно, успешно выходил в интернет через модем и через пару недель возвращался обратно в Windows, а Линукс тихонько гнил на своем разделе.

Уже в 2000 было примерно тоже самое с Mandrake, Fedora и Ubuntu, потом я пересел на Mac и ставил Ubuntu как десктоп исключительно на рабочих машинах - когда не было возможности получить привычную среду.

Поэтому, получив ноутбук Lenovo T420s с Windows 7 на борту я честно (но без особого успеха) попытался работать на нем пару недель в чуждой среде, но сдался и решил воткнуть туда Ubuntu... Увы - первая установка сдохла при попытке установить пакет с Compiz.

Вторую установку я решил сделать через  Wubi - никогда им не пользоватся -  посмотрел, идея вроде интересная - "поставить Никсы прямо из Винды" - удобно.

Ну а дальше - вроде ничего страшного... Разбил диск на разделы, поставил, настроил, попользовался несколько недель, начал кодить  - все вроде работает нормально.

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

Непонятненько, ну да ладно, подождем.

Затем начинаю вкатывать дамп в базу - и машина умирает снова - LA до 4, все приложения реагируют с огромной задержкой, в топе висит mysql и какой-то процесс префикс_не_помню.ntfs. Я в непонятках - какое, казалось бы, ntfs отношение имеет к mysql?

Отключаю все подключенные виндовые диски - не помогает. Подумав с коллегами - решаем его кильнуть - этот странный мифический процесс

sudo kill xxxx.ntfs

Через 2 секунды - kernel panic... У меня ступор - начинаю думать, перегружаюсь, и что-то мне начинает не нравится - я начинаю подозревать неладное.

Вообщем, немного поковырялся - и мы все начали истерически ржать.

Выяснилось, что эта хрень под названием Wubi создает раздел на NTFS как файл и монтирует его как ext3 через FUSE!!! В результате все это работает... даже не скажу - во сколько десятков раз медленней, чем обычно, и разумеется - вкатывание дампа на много-много ..байт приводит к полным тормозам.

Итог
1) "убить упрямую тварь" (с) и ставить Бубунту обычным путем. Не уверен - удастся ли нормально мигрировать ЭТО хотя бы в виртуалку VirtualBox
2) ВНИМАТЕЛЬНО читать - чего пишет незнакомые софтинки, особенно - мелким шрифтом ;-)

пятница, 6 января 2012 г.

Как оптимизировать RunCMS? или Оптимизация CMS для начинающих

Решил перевыложить свою старую статью - она местами уже потеряла актуальность, да и RunCMS практически уже умерла, к сожалению - оставив после себя несколько веток-форков -на одной из которых и работает ScaleModels.ru, но люди спрашивают. Увы - некоторые вещи, приведенные тут уже устарели за несколько лет, некоторые - спорны, но  пусть будет в этом блоге - до кучи. 

RunCMS - достаточно неплохая система, дружественная для новичка в Web, которая позволяет худо-бедно, но решить большинство типовых задач для небольшого сайта одним приемом - «из коробки». Однако сайты имеют свойство либо умирать, либо развиваться, и в случае когда ваш ресурс выходит из категории «homepage про меня и моего хомячка Вову» (c) - начинаются проблемы с производительностью. Ситуация осложняется тем, что большие и серьезные CMS (такие как Drupal или Joomla) давно прошли этот этап «детских болезней» и способы решения подобных проблем для них давно известны и доступны. К сожалению, крупных проектов на RunCMS встречается не много, и информации о ней очень мало. На правах бывшего coreteam разработчика RunCMS я хочу рассказать о способах увеличения ее производительности.

Данная статья не предназначена для полных новичков - подразумевается, что вы в состоянии отличить PHP от Perl, способны разбираться в чужом коде, и примерно представляете архитектуру RunCMS (или XOOPS-like систем). Желательно, чтобы вы знали что такое my.cnf и где его искать ;-)

Есть два варианта хостинга - обычный и VPS/VDS.

Обычный хостинг

В плане оптимизаций - это жопа (если вкратце). Особенно если у вас провайдер, который не хочет ставить дополнительный софт и его настраивать. Начиная этак от 500 уников в день - готовьтесь к прессингу с его стороны - «давайте-ка переедем на выделенный сервер» (с) Один мой прошлый хостер на просьбу установить поддержку mbstring на свой шаред-хостинг спросил - «А зачем он вам нужен?» Но в принципе, мигрировать на свой сервер - это логичный вариант.

Что можно сделать для оптимизации RunCMS непосредственно в ней самой на SHARED хостинге?

MySQL таблицы для сессий

Находим MySQL таблицу sessions и конвертируем ее в тип MEMORY (если стоит PHPBB - то такая судьба должна постигнуть и phpbb_session) Этим мы выиграем небольшое количество скорости - но на КАЖДОЙ страницы сайта. Единственный минус - после перезагрузки сервера всем пользователям прийдется перелогиниваться, но результат того стоит.

Кэш страниц для гостей-анонимусов

Включаем кэширование страниц для гостей на как можно большее время - однако учитывайте, что для этого нужно хотя бы 50-100 мб свободного места на диске?

Включаем кэширование MySQL средствами класса DB

class/database/mysql.php

<?php

    var $file_cache = true;

?>


Это то, что можно было сделать нормальными ШТАТНЫМИ способами RunCMS, а теперь начинаем экспериментировать

Файл-кэш SELECT запросов

Изучаем код сайта и модулей, добавляя для тяжелых запросов кэширование через метод

<?php

$db->query($sql, false, false, ‘имя_файла’,  время_кэширования)

?>


ставя подходящие значения. Учитывайте только то, что кэш отрабатает только в том случае если результат запроса будет прогнан через fetch_row или fetch_array , а вот fetch_object в текущей версии не кэшируется?

Скомпилированное ядро

Включаем экспериментальное компилированное ядро (класс RCCoreApi) файл class/core.php

<?php

var $compiling = true;

?>

Данное «ядро» была введено мной в версии 1.6.1 - оно позволяет сэкономить примерно 6 SQL запросов на каждой странице, но несколько повысит нагрузку на PHP.

Побочный эффект - не будут задействованы новые изменения в таблицах блоков, модулей и т.д. так что перед подобными действиями эту опцию нужно выключать. Логика работы следующая - поставили модули, настроили блоки, сайт работает нормально - включили скомпилированное ядро. Нужно поставить модуль - выключили компиляцию, поставили модуль, удалили файл кэша, включили заново.

Вообще если вы любознательны и способны экспериментировать и разбираться с чужим кодом - внимательно изучайте стандартные классы RunCMS 1.6.1 и 1.6.2.

Немного яда и кидания какашек

Несмотря на то, что netshark просто вышвырнул меня из разработки RunCMS и вычеркнул из списка живых team, а впоследствии - передал код в лапы Farsus, который ее успешно и угробил :-) - в коде осталось много экспериментальных неофициальных настроек для увеличения производительности сайта

Например -

Кэш деревьев

Установить в классе xoopstree.php

<?php

define('RC_TREE_CACHE', 1); 

?>

это сильно поможет при работе с большими деревьями категорий - в таких модулях, как news, например

Кэширование блоков

Если внимательно посмотреть на табличку newblocks - вы увидите поле cache_time. При установке его в целое положительное значение N, блок будет закэширован на N минут. Обратите внимание - кэшировать имеет смысл только те блоки, которые выглядят ОДИНАКОВО для всех пользователей - если содержимое блока будет разным, то возможен конфликт.

RCCache и RCCachedPage

Использование классов RCCache и RCCachedPage, написанных совместно с Shurik2k5. В репозитории RunLiveCMS можно найти версии этих классов не только для файлового кэша (как в RunCMS), так и в базу MySQL и Memcache - что предпочтительней, с (или без) serializing данных

Настройка выделенного сервера (VPS/VDS)

Если же вы понимаете, что сайт будет расти дальше - то предстоит часть вторая - настройка выделенного сервера.

Ниже только ОБЩИЕ рекомендации, куда стоит смотреть
  • Имеет смысл поставить PHP акселератор - на моем сервере стоит Zend Optimizer + eAccelerator. 
  • Тщательно настроить сервер MySQL - не забывайте про кэш запросов самого сервера и ограничение по времени медленных запросов
  • После настройки Apache - отключите access логи на картинках, оставив для них только error
  • Имеет смысл избавиться от .htaccess файлов, снеся все редиректы и настройки непосредственно в httpd.conf
  • Повесить на front-end (перед Apache) nginx и настройте его на отдачу статических файлов (таких как картинки, CSS, JS) - либо вообще отказаться в пользу Nginx + PHP-FASTCGI.
  • Используйте RAM-диск для критичных файловых кэшей - в моем случае туда сохраняется файловый кэш класса DB, compiled_kernel, блоки и кэши некоторых страниц
  • Обязательно используйте программы top, mtop и apachetop для мониторинга своей системы - ведь лучше вас ее не знает никто

По настройке выделенных серверов написано достаточно много, в частности тут - про Nginx, PHP, Memcache и тут про MySQL и насморки.


В моем случае - самый сильный выигрыш был от введения (по порядку важности)
  • Гостевое кэширование
  • Nginx
  • настройка MySQL
  • RAM диски на кэши кусков страниц, блоков и темплейтов форума /modules/forum(ну или phpBB2)/cache (всего около 200МБ RAM) - у меня форум, статьи и главная страница - основная нагрузка
  • eAccelerator
  • Таблицы сессии в MySQL MEMORY

Все остальное, честно говоря - из разряда "экономить на спичках" - не помешает, но без этого можно обойтись

Возможно, кому-то эти советы покажутся детским садом и «мурзилкой», но кому-то - сэкономят несколько минут «гугления» и чесания в затылке.

Изначально было опубликовано тут.

среда, 4 января 2012 г.

Стартапы: Одевайте штаны по вашему размеру (Нецензурно)


Еще один перевод... далее неполиткорректно и вообще - с матом (из песни слов не выкинешь) ;-) Так что нервных и беременных женщин прошу не читать.

Я работал с большим количеством инженеров из Силиконовой долины - некоторые из которых были ДЕЙСТВИТЕЛЬНО гениальны, а некоторые - эту гениальность просто хорошо подделывали. И одна из тенденций, которые я заметил - что большое количество действительно хороших инженеров замечены в том, что они любят меряться членами - когда дело доходит до практических реализаций.

Вы начинаете проект с одним из подобных парней, и первая проблема, которую вам нужно решить - это то, что MySQL не собирается нормально масштабироваться... А в результате - нужно понять - как именно вы ВООБЩЕ  будете писать свою собственную систему хранения данных.

После того, как этот вопрос "устаканится" - вам понадобится собственный объектно-реляционный маппер - и, заодно, вы можете также сделать и свой собственный веб-язык шаблонов... не - просто потому что это КРУТО, и он хорошо впишется в вашу архитектуру.

Это, господа - мерянье членами, и это для стартапа - самая колоссальная трата времени.

Сейчас в Северной Калифорнии хорошо известен факт - что я величайший программист, который когда-либо жил, но я даже стал жертвой этого явления. На моем последнем стартапе мы были абсолютно уверены, что мы загнали себя себя в угол, используя MySQL - поэтому мы написали наши собственные хранилища данных. Это начиналось как обертка RPC вокруг некоторого волшебного key/value хранилища на Erlang (параллелизм, ебать его), и в конечном итоге - закончилось как различные обертки вокруг RPC BerkeleyDB. В общем, это это хранилище прошло через три крупных переписывания, а конечный продукт был тем, для разработки чего потребовалось всего несколько месяцев - и он упадет при сравнительно умеренной нагрузке.

Но стойте, ведь это была ДЕЙСТВИТЕЛЬНО прикольная архитектура.

Как еще один небольшой пример - опять же на последнем стартапе в один прекрасный день  я потратил несколько часов на написание упреждающей нейронной сети на Java - просто, чтобы попробовать свои силы в реализации алгоритма. Опять же - небольшая трата времени, но на самом деле - наибольшей проблемой было мое отношение к ней, что означало более серьезную проблему: Я хотел посмотреть, насколько я крут (ответ: довольно-таки охуенно крут).

И жертвами подобного становятся не только стартапы в квартирах. Kosmix, хорошо финансируемый научный проект, который обманул сам себя, думая, что он  может быть основным игроком в поиске, написал собственное хранилище данных на C++. Это был в основном клон GFS Google, потому что - "эй, если Google делает это, то мы должны тоже", не так ли?

Кто знает, сколько времени, сил и денег было потрачено на это мерянье детородными органами? И ведь все это - время, деньги и энергия, которые могли бы пойти в создание своего конечного продукта - и это уже не шутка.

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

К счастью, многие высокоуровневые инженеры не подверженны подобному распылению и мерянью. Или - к сожалению?

В моем текущем стартапе у нас есть бизнес-ориентированное руководство. У нас есть хорошая команда, техники, и мы не позволяем нашему высокомерию высосать из нас лучшее. Среди стартапов есть очень немного случаев, когда ДЕЙСТВИТЕЛЬНО  нужно будет написать что-то свое - вроде новой файловой системы, и мы явно не один из них.

Как предприниматель, вы должны быть горды вашей идеей, но теперь вы оцените - насколько велик член у вашего компилятора?

Весьма вольный перевод вот этой заметки. Спасибо автору.

Как адекватно перевести в данном dick-swinging - я так и не понял. Решил остановиться на варианте "мерянья детородными органами"

воскресенье, 25 декабря 2011 г.

Как оптимизировать сервер? - реальные данные - теория без практики мертва

Это судьба - вслед за вчерашней заметкой про оптимизацию выделенного сервера на сайте были опубликованы весьма интересные материалы, которые привели к росту просмотров страниц на 54 тысячи - это составляет рост примерно 140%.

Итак, график LI

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


Трафик, прокачанный через firewall - разумеется, вырос, причем - значительно



Процессы и потоки - увеличились



MySQL немного изменился в пределах погрешности; коннекты - не изменились.





Memcache немного подрос, но незначительно


А самое главное - ЦПУ и Load Average практически не изменились

Вывод

nginx с кешом HTML страниц сильно спасает от резких скачков нагрузки от незарегестрированных пользователей.

Рискну предположить, что создатели многих супер-пупер-мега-стартапов, постоянно падающих от пресловутого великого и ужасного Хабраэффекта, об этом не знают ;-)

З.Ы. Люблю, когда теоретические выкладки подтверждаются практическими данными.


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

Как настроить сервер? или оптимизация сайтов на PHP (Nginx, PHP, MySQL, Memcache)

Если вы владелец приличного сайта - то рано или поздно вам прийдется подкручивать свой выделенный(виртуальный) сервер, на котором разросшийся за несколько лет веб-проект начинает подтормаживать.

Если же вы еще и не профессиональный HighLoad Linux-админ, а, например, разработчик (как я), то в процессе настройки прийдется ловить много-много граблей...  ;-)

Хочу немного улучшить состояние вашего лба, рассказав про те шишки, что набивал самостоятельно или с помощью более "администых" друзей. Специальные оптимизации на уровне правок PHP-кода не рассматриваю, это отдельная тема, сейчас - только сервер, консоль и вы, ну может где пару PHP скриптов немного поправить понадобится - буду считать, что свою CMS вы чуть-чуть знаете.

Ниже рассматривается достаточно часто встречаемая комбинация для сайтов: nginx + php (nginx+apache c php немного отличается - вместо fastcgi_xxx будет proxy_xxx).

Да, и считаем, что сейчас все компоненты вашей системы (nginx, php, mysql, memcache) крутятся на одной машине - как оно обычно и бывает на частных ресурсах.

PHP


  • Пускаем как fastcgi через сокет
  • Pconnect к базе - спорно
  • Не забываем акселератор (моя юзает eAccelerator) - хотя тоже есть спорные моменты

eAccelerator


Только для production машин можно отключить проверку Modified time - это абсолютно не подходит, если на сервере идет отладка скриптов - иначе будете ловить постоянные глюки и проблемы - включать только после того как сайт стал стабилен.

eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="0"
eaccelerator.shm_only="1"

Временые диски

tmpfs для /tmp и сессий PHP - все это сносится в память, если ее достаточно. В /etc/fstab добавляем

tmpfs                   /tmp                    tmpfs   defaults        0 0
tmpfs /var/lib/php tmpfs size=200M,nr_inodes=1m,nosuid 0 0

MySQL

  • Проверяем, включен ли query кэш
  • Также используем сокет
  • Если в вашей CMS используется таблица сессий - ставим для них тип MEMORY (если нет текстовых полей) - это приведет к сбросу всех залогиненных пользователей при перезагрузке сервера, но добавит немного скорости. Ну или если это неприемлемо - то надеюсь, она уже переведена в InnoDB? ;-)
  • Определяем оптимальное количество коннектов - статистика хотя бы за месяц (я юзаю munin). Ставим в 1.5-2 раза больше среднего.
Более подробно про оптимизацию MySQL можно прочитать тут.

Memcache

Если вся солянка крутится на одной машине - то также используем коннект через сокеты (по умолчанию не используется - стоит ip адрес). В таком варианте работы memcache возможны проблемы с некоторыми средствами мониторинга memcache (которые работают также по IP).

Не забываем в PHP использовать сжатие при работе с MEMCACHE.

Nginx

Ограничиваем число коннектов и запросов, особенно на ресурсоемкие скрипты
http {
...
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    limit_zone three $binary_remote_addr 10m;

Включаем кэширование для неавторизованных гостей

http {
...
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=wholepage:50m inactive=15d max_size=5000m;
        location ~ .*\.php$ {
            limit_conn three 20;
            include         /etc/nginx/fastcgi.conf;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass    unix:/var/run/php-fastcgi/php.socket;
            #access_log  /var/log/nginx/domain.access.log  my_combined;
            fastcgi_cache wholepage_guest;
            fastcgi_cache_valid 301 302 304 10m;
            fastcgi_cache_valid 200 360m;
            fastcgi_cache_valid 404 5s;
            fastcgi_cache_key "$request_method|$host|$request_uri";
            fastcgi_pass_header "Set-Cookie";
            fastcgi_ignore_headers "Cache-Control" "Expires";
            fastcgi_cache_bypass $cookie_phpbb_session $arg_nocache $arg_PHPSESSID;
            fastcgi_no_cache $cookie_phpbb_session $arg_nocache $arg_PHPSESSID;
    }
Где phpbb_session - имя куки по которой идет авторизация

Все запросы с ?nocache=1 и PHPSESSID попадают на PHP-бэкенд сразу без кэша не забываем открыть скрипт, по которому идет авторизация (в том числе и всякие капчи - их можно переписать на ?nocache=1) - тут возможно прийдется немного поковыряться и в коде CMS тоже.

        location /register.php {
                limit_conn three 20;
                include         /etc/nginx/fastcgi.conf;
                fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass    unix:/var/run/php-fastcgi/php.socket;
        }

Nginx - общие рекомендации

Очень нежелательно использовать location с регекспами - только простые префиксы вида
location /mymodule {}
Если от регекспов никак не избавится - то лучше их обрамлять простым location (Причина - сложноуловимые перехлесты в логике парсинга URL - кто за кем будет следовать)
location /mymodule {
  location ~ \/mymodule\/(.*)\.php$ {
    чего-то
  }

}

Отрубаем access лог для картинок

Разумеется - это только основные моменты оптимизации, на самом деле их гораздо больше. А какие трюки для уменьшения нагрузки на сервер знаете вы? Пишите в комментах.

вторник, 25 октября 2011 г.

Сравнение нагрузки PyCurl vs HTTPClientFactory+Deferred в сервисе на Twisted

Решил перевыложить с хабры свое небольшое старое исследование по поводу производительности Twisted при использовании  PyCurl и HTTPClientFactory - пусть лежит все в одном месте, раз уж начал активно писать в блог.

В процессе разработки одного проекта на Python+Twisted (распределителя запросов между несколькими СМС гейтами Kannel) пришлось переписать вызов URL различных сервисов с разных серверов c блокирующего вызова через PyCurl на неблокирующий (client.HTTPClientFactory + deferred). Чтобы иметь перед глазами реальные данные о нагрузке, решил дать много запросов и посмотреть на результаты

Описание теста

Использовался Jakarta/Apache Jmeter - очень полезная софтинка, к сожалению, почему-то применяют ее для тестов достаточно редко (может, просто не знают о ее существовании?), но мне она весьма нравится - ибо возможности у нее большие и даже краткое описание наврядли влезет в несколько постов - если кому интересно, могу потом пробежаться по ней вкратце.
В 200 потоков прогнано 100 запросов на один и тот же сервер, но со случайными данными (чтобы исключить кэширование). Прогонялось на обыкновенной рабочей машине с GUI под Ubunta — так, для примерной оценки.

Результаты теста

Одна ошибка — не справилась база, так что погрешностью можно пренебречь.

Графики распределения

Блокирующий (PyCurl)
Неблокирующий (deferred)

Итоги

Как видно из результата теста — при одинаковой нагрузке при использовании defered минимальное значение отклика сервера почти в 2.5 раза меньше (из-за отказа базы), а максимальное — меньше в два раза, чем у блокирующего. Среднее значение - также меньше в 2 раза.

Америку я, конечно, не открыл, но по-крайней мере — теперь на руках конкретные цифры по производительности. Надеюсь, кому-нибудь они пригодятся.

понедельник, 24 октября 2011 г.

Как включить MySQL innodb_file_per_table?

В продолжение темы насморков и гильотины оптимизации MySQL привожу рецепт по включению такой полезной функции как innodb_file_per_table.

Зачем это нужно?

MySQL по умолчанию все таблички innodb хранит в одном файле - когда их накапливается приличное количество - файл значительно разрастается. Плюс не забывайте, что при удалении данных в innodb - размер файла не уменьшается - он растет только в большую сторону. Так что если данных в базе у вас много или идет активное удаление - рано или поздно вы задумаетесь о том, чтобы выполнить подобное разделение

Что нужно сделать?

  1. Прежде всего - отрубаем нагрузку, выключаем связь сервер с внешним миром  - php и прочее беспокоить вас не должны - процесс не быстрый
  2. Теперь тщательно делаем ПОЛНЫЙ бекап всех баз данных и конфига
  3. Удаляем все таблицы из БД
  4. Выключаем mysqld
  5. В /etc/my.cnf удаляем старое значение innodb_data_file_path
    и добавляем

    innodb_data_file_path=ibdata1:10M:autoextend
    innodb_file_per_table=1

  6. удалаем cледующие файлы
    • /var/lib/ibdata1
    • /var/lib/ib_logfile0
    • /var/lib/ib_logfile1
    или сколько там файлов ibdata - оставлять старые logfile нельзя!!
  7. запускаем mysqld
  8. вкатываем таблицы обратно
  9. проверяем наличие свежесозданных файликов *.ibd
  10. PROFIT!!
Да, разумеется - операция опасная по сути, поэтому - бекап, бекап и еще раз бекап.

суббота, 22 октября 2011 г.

Немного о сборке программ с dylib в MacOS

Узнать, какие зависимости у файла к библиотекам

$ otool -L yourFile

На примере злополучной библиотеки MySQL для Qt

$ otool -L /Developer/Applications/Qt/plugins/sqldrivers/libqsqlmysql.dylib
/Developer/Applications/Qt/plugins/sqldrivers/libqsqlmysql.dylib:
 libqsqlmysql.dylib (compatibility version 0.0.0, current version 0.0.0)
 /opt/local/lib/mysql5/mysql/libmysqlclient_r.16.dylib (compatibility version 17.0.0, current version 17.0.0)
 QtSql.framework/Versions/4/QtSql (compatibility version 4.6.0, current version 4.6.2)
 QtCore.framework/Versions/4/QtCore (compatibility version 4.6.0, current version 4.6.2)
 /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
 /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 438.0.0)
 /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)

Включить показ динамически загружаемых библиотек runtime

# export DYLD_PRINT_LIBRARIES=1

В результате

$ nano dylib.log
dyld: loaded: /usr/bin/nano
dyld: loaded: /usr/lib/libncurses.5.4.dylib
dyld: loaded: /usr/lib/libSystem.B.dylib
dyld: loaded: /usr/lib/system/libmathCommon.A.dylib

Потом, разумеется, не забываем выключить в 0.

Изменить путь линкуемой библиотеки

$ install_name_tool -change /Developer/Applications/Qt/plugins/sqldrivers/libqsqlmysql.dylib @executable_path/libqsqlmysql.dylib ./dist/MyApp.app/Contents/MacOS/MyApp



Спасибо MikhailEdoshin

пятница, 21 октября 2011 г.

Настройка медленного MySQL - о насморках и гильотине

Последнее время часто вижу советы по оптимизации MySQL, в которых авторы сразу (не глядя на ситуацию) сразу рекомендуют - поставить Percona, поставить SSD.

Нет, конечно - варианты обновления софта и железа помогут - но этот как-то... лечить насморк гильотиной - быстро и точно пройдет. ;-) Давайте вспомним стоимость SSD - для компаний как бы пофиг, а для частного вебмастера - сумма в 500$ на дороге не валяется.


Мониторинг - всему голова

Разговор об оптимизации, на мой взгляд совершенно неразумно вести без мониторинга и построения графиков нагрузки по времени - я использую munin, кто-то любит zabbix, есть и другие. Ну да выбор - вопрос в большей степени религиозный, суть-то в следующем - некоторые админы очень любят поднять преждевременную панику при затормозившем сервере - дескать, вот я зашел!! у меня все тормозит !!!! и срочно кидаются все оптимизировать.

Стоять! ;-) Выдыхаем и думаем, теперь вдыхаем и продолжаем думать.

Вот если вы временно заболели насморком - следует ли вам прямо сейчас делать операцию по удалению гайморита? Вот и с сервером - не нужно делать скоропалительных выводов, основываясь на единичном срезе времени. В текущий момент может быть все что угодно - случайный всплеск активности ботов, забытый кем-то cron скрипт бекапа и так далее. "Ширше надо смотреть, товарищи" (с) Так что ставим мониторинг и смотрим как себя машина ведет в течении нескольких суток/недели.

Теперь немного советов для тех, кто не торопится с брутальными методами "а-ля гильотина" (с)

Прежде всего - запускаем скрипт-анализатор mysqld, мне известны два основных
После выполнения они дают рекомендации - что стоит подкрутить/изменить. Обязательно - сервер mysql перед анализом должен проработать под нагрузкой не менее 2 суток, а вообще-то - чем дольше, тем точнее будут выборки и рекомендации.

Дальше список типовых проблем mysqld

  • мало памяти на индексы (особенно критична нехватка памяти для таблиц InnoDB, MyISAM переживает ее более спокойно). Как косвенный признак - сильная загруженность диска - из-за нехватки памяти mysql отчаянно свапится/пишет tmp таблички на диск
  • много постоянно открытых коннектов к базе - уменьшаем - но опять таки - смотрим по времени - сколько РЕАЛЬНО используется.
  • для PHP - часто рекомендуют включать pconnect, на мой взгляд - оно того не стоит.
  • для InnoDB включаем innodb_table_per_file. Процесс миграции описан тут.
  • СПОРНО - если памяти много - рекомендуют загнать /tmp в RAM -> улучшится скорость работы с таблицами tmp, хотя мое мнение - если памяти хватает лучше просто дать базе памяти побольше - и временные таблички будут не нужны
  • смотрим внимательно на CurrentLockRation в результатах скрипта анализатора
    Current Lock Wait ratio = 1 : 8943
    Чем больше второе число - тем лучше.

Как увеличить Current Lock Wait? 

Тщательно изучать структуру своих таблиц и запросы - если часто идет запись, которая лочит таблицу - переводим на InnoDB, MyISAM оставляем для редко обновляющихся табличек, добавляем индексы и т.д.

Медленные запросы SQL

Ну и понятное дело - не забываем включить slow_query_log и просто оптимизировать кривые запросы - поверьте, их больше, чем можно предположить. 

У меня был случай, когда хороший грамотный фриленсер сделал мне задачу с некоторыми запросами - причем программист действительно неплохой, просто с нормальной посещаемостью  не работал. 

Через некоторое время сервер начал загибаться. При просмотре запросов к базе у меня зашевелились волосы на всех участках тела - там было что-то в стиле  JOIN ... GROUP BY CONCAT(SUBSTR(), SUBSTR())  и т.д. - уже сейчас точно не вспомню. 

Разумется, на тестовой установке у него все отрабатывало мгновенно - данных нет, нагрузки нет - отлично думает он и шлет мне код. А я дурак, его особо не читаю - проверяю, работает  и вкатываю на живой сервер - проблемы начались месяца через четыре, когда данные накопились...

Ну и пришлось переписывать код самому - с помошью нескольких простых запросов и мемкеша.

Итог

  • Мониторинг по времени
  • Изучение
  • И только потом - оптимизация


четверг, 20 октября 2011 г.

Вопрос Python+Mac+Qt+MySQL+py2app

Джентельмены (ну и дамы, разумеется), а никто на Python под Мак/кросплатформенно, да еще и с особыми извращениями (Qt+MySQL) не пишет случайно? Да еще и все это извращение в приложения .app не собирает, случаем?

Есть проблемка, а спросить не у кого, приходится на StackOverflow постить вопросы.

Заранее спасибо!

Да, "мсье знает толк..." (с)

понедельник, 17 октября 2011 г.

py2app собирает .app с Qt4 без MySQL (libqsqlmysql.dylib)

Все чудесатей и чудесатей - сказала Алиса.
Все чудестраньше и чудестраньше

Мало того что, в Qt4 по умолчанию отсутствует поддержка MySQL - приходится докомпилировать  плагин из исходников, так еще и выяснилось, что при сборке .app пакета приложения py2app честно включает туда библиотеки Qt,  но забывает положить ее же plugins.

Лечение

$ macdeployqt ./dist/YourSuperPuperApplication.app


После непродолжительной ругани в консоли в .app появляется папка PlugIns - обратите внимание на большую I в центре названия.

Но разумеется - папка sqldrivers там не появилась (это было бы слишком просто ;-) ), приходится докопировать "ручками".


$ cp -R /Developer/Applications/Qt/plugins/sqldrivers ./distYourSuperPuperApplication.app/Content/PlugIns/

После чего приложение вроде бы подхватило MySQL и попыталось взлететь... но, к сожалению -  грохнулось на взлёте по другой причине.

Но это, уже как говорится - другая история... ;-)

Одно не понимаю - толи лыжи не едут, то ли я... чего то не понимаю - почему такие сложности на каждом шагу? ЧЯДН?