Analitycs

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

FG2241 Rei Ayanami Ballgown on Knees (anime Evangelion)

"Что это мы? все без молока и без молока.... так и помереть можно..." Кот Матроскин
"Чувствуешь запах? Это Mr.Surfacer, сынок. Больше ничто в мире не пахнет так." (с)

Чтобы у новых читателей блога не сложилось ощущения, что я сугубо технический человек, упёртый только в код и конфиги, разбавлю рабочие заметки моей "тёмной стороной" - очередным законченным заказом. Люблю я, знаете ли, запах грунта и краски по утрам... ;-)

Больше фото и подробностей тут.

И вообще - стоит ли тут давать анонсы подобных вещей - или "мухи - отдельно, котлеты - отдельно?" (с) и никому это неинтересно?

вторник, 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 г.

Как демонизировать(daemon) проект на Twisted?

Есть три способа демонизировать проект на Twisted.

1) использование родного демона twistd. По идее - это более "методически грамотный" способ, но в свое время что-то не завелся у меня "в лоб", по этому до сих пор применяю второй.

2) скрестить старый работающий демон с реактором Twisted

#!/usr/bin/python                                                                                               
import sys
import src.daemon
import procname

class YourServer(twisted.web.server.Site):
    pass

class YourDaemon(Daemon):
    name   = 'yourserverd'
    site   = None
    server = None

    #--------------------------------------------------------------------------
    def __init__(self):
        self.server = YourServer()
        Daemon.__init__(self, pidfile='/var/run/%s.pid' % (self.name.lower()) )
        procname.setprocname(self.name)

    #--------------------------------------------------------------------------
    def run(self):
        self.server = YourServer()
        reactor.listenTCP(self.server.port, self.server)
        reactor.run()

if __name__ == '__main__':
      daemon = YourDaemon()
      daemon.processAction(sys.argv)

Да, procname служит для переименования процесса, о чем писал тут.


3) есть еще правда и python-daemon (PEP-3143), надо бы повнимательней изучить, но думаю что родной twistd оптимальней.

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

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

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

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

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