Архив

Шутка дня

<!‐‐[if lte IE 7]> <style> * {font-family: "Comic Sans" !important;} </style> <![endif]‐‐>

Почему жилье дорожает

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

Я Вам сейчас очень просто объясню, почему дома подорожали к зарплате - бензин тут ни при чем. Допустим, мы - я, Вы и Хроноскопист летели на самолете через Тихий океан. В пути мы втроем накушались абсента, надебоширили, отломали дверь от туалета, и нас за это выкинули в море через аварийный выход. По счастью, рядом с местом нашего падения обнаружился маленький безымянный полинезийский остров. Выбравшись на берег, мы посовещались, и решили считать его новым государством под названием Соединенные Штаты Абсента (США).

Когда нас выкидывали из самолета, то багажа нам, естественно, не выдали. Поэтому, всех материальных и нематериальных активов у нас - только туалетная дверь, которую Вы таки прихватили с собой. И вообще, несмотря на абсент, Вы у нас оказались самым запасливым - в бумажнике у Вас, совершенно случайно, обнаружилась банкнота в $100. Таким образом, в наших США имеются нефинансовые активы - дверь, и финансовые активы, они же денежная масса - $100. Это все наши сбережения. Поскольку у нас больше вообще ничего нет, то можно сказать и так - у нас есть один материальный актив - дверь, обеспеченный денежной массой в $100. Т. е. наша дверь стоит $100.

Немного протрезвев, мы решаем, что надо как-то обустраиваться. Самый быстрый из нас оказался Хроноскопист. Он тут же объявил, что создает банк и готов взять в рост имеющиеся у населения денежные сбережения под 3% годовых - ну не сидится человеку без дела. Вы отдаете ему $100, и он их записывает в блокнот в статью "Пассивы - Дипазиты". Но я тоже не лаптем щи хлебал - зря я что ли столько времени занимаюсь расследованием экономического мухлежа - я знаю как изъять у Вас и дверь и $100. Я предлагаю Вам взять Ваши $100 в рост под 5% годовых. Вырываю листик из своего блокнота и пишу на нем - "Аблегиция на $100 под 5% годовых". Вы чувствуете, что Вам поперло. Забираете деньги у расстроенного Хроноскописта с дипазита и отдаете их мне в обмен на мою аблегацию.

Я беру Ваши $100 и кладу их на дипозит в банк обратно обрадованного Хроноскописта.
По хорошему, на этом можно было бы и успокоиться и пойти всем заняться делом - пальму потрясти или за моллюсками понырять, снискать себе хлеб насущный, так сказать. Но Вы ж знаете - я неуемный финансовый гений, такие пустяки как кокосы и устрицы меня не интересуют. Помыкавшись по нашему острову - 50 шагов от южного побережья до северного, и 30 с запада на восток, я придумываю гениальную комбинацию. Я подхожу к Вам и предлагаю на пустом месте заработать еще 1% годовых. Взять в банке Хроноскописта кредит под 4%, и купить у меня еще одну аблигацию под 5%. Вторую аблегацию на $100 я тут же выписываю на блокнотном листике, и машу ею у Вас перед носом. Недолго думая, Вы бежите в банк и берете кредит $100 под залог моей первой аблегации на $100. Они там есть - я их туда положил на дипазит. Вы отдаете мне заемные $100 и прячете вторую аблегацию к себе в бумажник - теперь у Вас есть моих аблегаций на $200. А $100 я кладу в банк - теперь у меня там $200 на дипазите. Хроноскопист аж подпрыгивает от радости - кредитный бизнес попер.

Думаете я на этом остановлюсь? Ага, сейчас - я уже выписал Вам третью аблегацию. Бегом в банк за кредитом под залог второй аблегации. Ближе к вечеру, набегавшись по острову с этой сотней баксов и изодрав все листочки из блокнота на аблегации, мы имеем следующую картину. У Вас на $5000 моих аблегаций, а у меня на $5000 дипазитов в банке. Теперь, я чувствую, что пришло время прибрать Вашу дверь к рукам. Я предлагаю купить ее у Вас за $100. Но Вы вредничаете - дверь-то всего одна, и заламываете цену в $1000. Ну, $1000 так $1000 - в конце концов у меня на депозите лежит целых $5000. Я на последнем блокнотном листочке направляю платежное поручение Хроноскописту, перевести $1000 с моего дипазита на Ваш, и забираю Вашу дверь.

Если нашу бухгалтерию отдать американскому экономисту с гарвардским дипломом, он сообщит нам, что наши США располагают $1000 материальных активов в виде двери, и $10000 финансовых активов в виде аблегаций и дипазитов. Т. е. что стоимость нашего совокупного имущества увеличилась за день в 110 раз.

Менее тонкий и образованный человек сказал бы, что мы - три дебила, у нас как была одна дверь и $100, так и осталось, и что только конченные дебилы могли целый день рвать листочки из блокнота, вместо того, чтобы нарвать кокосов. Кто из них прав - решайте сами. Но механизм относительного роста цен на дома именно такой, что в США, что в Японии, что в России.


Percona Server Configuration Wizard

Возможность генерировать удобный конфиг для mysql прямо на сайте перконы для меня стало открытием. Есть возможность указать различные характеристики железа и роль данного сервера, а сайт постарается подобрать оптимальные настройки.

percona

Проходим небольшой тест, отвечая на вопросы и на выходе имеем подобный конфиг:

# Generated by Percona Configuration Wizard (http://tools.percona.com/) version REL5-20120208
# Configuration name zlo generated for gmail@rpsl.info at 2012-07-05 10:31:23

[mysql]

# CLIENT #
port                           = 3306
socket                         = /srv/mysql/mysql/mysql.sock

[mysqld]

# GENERAL #
user                           = mysql
default_storage_engine         = InnoDB
socket                         = /srv/mysql/mysql/mysql.sock
pid_file                       = /srv/mysql/mysql/mysql.pid

# MyISAM #
key_buffer_size                = 32M
myisam_recover                 = FORCE,BACKUP

# SAFETY #
max_allowed_packet             = 16M
max_connect_errors             = 1000000
skip_name_resolve
sysdate_is_now                 = 1
innodb                         = FORCE

# DATA STORAGE #
datadir                        = /srv/mysql/mysql/

# CACHES AND LIMITS #
tmp_table_size                 = 32M
max_heap_table_size            = 32M
query_cache_type               = 0
query_cache_size               = 0
max_connections                = 500
thread_cache_size              = 50
open_files_limit               = 65535
table_definition_cache         = 1024
table_open_cache               = 256

# INNODB #
innodb_flush_method            = O_DIRECT
innodb_log_files_in_group      = 2
innodb_log_file_size           = 128M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table          = 1
innodb_buffer_pool_size        = 1456M

# LOGGING #
log_error                      = /srv/mysql/mysql/mysql-error.log
log_queries_not_using_indexes  = 1
slow_query_log                 = 1
slow_query_log_file            = /srv/mysql/mysql/mysql-slow.log

Ну и в качестве бонуса, рекомендую почитать доклад "Optimizing MySQL Configuration" от Percona


Nginx allow POST static files

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

Мое решение лучше тем, что оно не требует поднятия второго сервера на отдельном порту и вообще эстетически красивое.

Кратко о проблеме:

Все знают о том что в Facebook'e есть iframe страницы, но не все знают что Facebook эти страницы запрашивает через POST, а не через GET, как делают все остальные. Поэтому все fb:iframe приложения запрашивая у Nginx'а страницы в ответ будут получать ошибку:

405 "Method Not Allowed"

Вариант который предлагает dotZero выглядит примерно вот так (это я для истории и поисковых запросов оставлю):

upstream fb_static {
    server localhost:8001;
}

server {
    listen       443;
    server_name  _;

    #allow_static_post on;

    error_page 405 =200 @405;

    location @405 {
        proxy_method GET;
        proxy_pass http://fb_static;
    }
}

server {
    listen 8001;
    server_name _;

    location / {
        root "/var/www/fb";
    }
}

Вариант конечно хороший и самое главное рабочий. Но давайте попробуем так:

server {
    listen  80;
    server_name _;

    # Тут мы описываем поведение
    # для нашей кастомной ошибки
    error_page 405 = $uri;

    # Дефолтный location
    location / {
        access_log off;
        root    /srv/path
        try_files $uri $uri/index.html /index.php$is_args$args;
    }
}

Что тут происходит? Мы складываем весь статический контент который будет запрашивать facebook в отдельную директорию, просто, для красоты. Определяем location для этой директории, который будет всегда возвращать код ошибки, например, 599. И определяем поведение для обработки этой ошибки, как попытку отдать данные по этому урлу.

Вот и все, работает. Читайте мануалы.

UPD: вернул конфиг до состояние обработки напрямую 405 error_page, т.к. поведение описанное до этого, не совсем соответствовало реальности. Таким образом, после запроса файла через POST, будет выдана 405 ошибка, которая обработается в error_page 405 = $uri и будет отправлена в location /

То есть либо файл найдется и будет отдан, либо управление будет передано в index.php.


PHP: detect UTF-8

Пару недель назад, мне кто-то доказывал, что mb_detect_encoding, работает в разы быстрее своих надуманных конкурентов. Задача простая, проверить входящую строку на принадлежность к UTF-8. Логика простая, либо UTF-8, либо нет. В повседневной жизни, обычно не приходится выбирать из зоопарка кодировок и, чаще всего, строка либо в utf8, либо в cp1251.

Сделал простой синтетический тест. Прогнал определение через функцию 10000 раз. Посмотрел кто быстрее.

Вариант 1, который мне нравится:

$s = microtime(true);

for( $i=0; $i<10000; $i++ )
{
    $string = 'sdf;gklaj;skdjf;sdkfls;dfjk';

    if( preg_match('//u', $string ) )
    {

    }
}

$e = microtime(true);

echo "\n\n" . $e-$s;

Средний результат выполнения скрипта на моей машине ~0.020 сек. Сравнивал я его с более правильным решением, которое выглядит так:

$s = microtime(true);

for( $i=0; $i<10000; $i++ )
{
    $string = 'sdf;gklaj;skdjf;sdkfls;dfjk';

    mb_detect_encoding( $string, array('UTF-8'), true );
}

$e = microtime(true);

echo "\n\n" . $e-$s;

Средний результат выполнения скрипта на моей машине ~0.050 сек. После этих тестов, решил прогнать на больших объемах данных, сгенерировал текст размером 10к байт и пропустил через функции. Для preg_match время выполнения составило ~0.120 сек, для mb_detect_encoding ~0.7 сек. Из этих изысканий можно сделать вывод, что определение через preg_match работает в разы быстрее чем стандартные механизмы, но, вероятно, проигрывает в количестве доступых фич.

На самом деле, есть еще три миллиона разных способов решить эту задачу, расскажите чем пользуетесь вы?