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

четверг, 28 мая 2020 г.

PHP: Асинхронность и производительность

     Никогда не думал что буду когда-нибудь снова писать про PHP. Но Жизнь напоминает что никогда нельзя говорить никогда. Итак: последния веяния программистской моды докатились с 5-ти летним опозданием до PHP. Лучше поздно чем никогда, заметит PHP программист и с этим трудно не согласится. 
      Если погуглить "promises in php" то реализация https://github.com/guzzle/promises окажется на 3-ем месте по популярности. Ничего удивительного что одноименный HTTP клиент вызывает у php-коммьюнити дикий восторг. Асинхронный, на промисах... и похеру что внутри сидит все тот же curl_multi_exec(если быть совсем честным не только он. есть еще варианты fall-back-а в случае недоступности curl).  В общем с точки зрения архитектуры GuzzleHTTP и в правду не плох. Но вот производительность он убивает напрочь. Я заменил в одном из нагруженных хенджлеров GuzzleHTTP на примитивный синхронный HTTP клиент(тоже curl based) и получил прирост примерно в 2 раза меньшее время ответа. Реально вместо 1000-1200ms стало 500-600ms. Отсюда вывод - не надо усложнять. Если вам нужно сделать всего 1-2 HTTP запроса - вам не нужна асинхронность, промисы и прочие красивые штуки. И если вам важно время ответа - то асинхронность вам скорее всего тоже не нужна. Асинхронность - это оптимизация пропускной способности, возможность одновременно сделать 20 запросов. А если вам нужно только 2 - сделайте их последовательно и будет сильно быстрее(как это не парадоксально).
      И вообще кажется я становлюсь ретроградом. Но это пока не точно.  Возможно просто новые технологии гавно. 

среда, 24 июля 2013 г.

Век живи, век учись

       Раньше думал что после 7-ми лет программирования на PHP меня уже ничем не возможно удивить, а оказалось что нет. Задумался я тут как BIGINT значение из MySQL таблички будет хранится в PHP -  в int то оно может и не влезть. Оказалось что в случае переполнения PHP автоматом конвертирует int во float:

четверг, 31 января 2013 г.

Garbage collection PHP vs CRuby vs Go

    Раньше меня интересовало - а есть ли вообще сборщик мусора в PHP. Нет, я понимал что он должен был быть где-то - но он настолько херово работал до недавнего времени - что казалось что его вообще нет.  Нормально он заработал только после версии 5.3 когда он научился определять циклические ссылки. Вообще странно что мало кто пишет об этом очень важном для практического программирования нововведении. О позднем статическом связывании и замыканиях разве что ленивый не написал, а об этом ни слова. Хотя может я не там читал. Ради интереса прочитал статью про сборщик мусора в CRuby:
    Rare Are GC Talks   - на английском, но написана очень простым языком. Еще один плюс этой статьи - она объясняет все базовые алгоритмы сборки мусора на простых примерах. Если лень читать - то в кратце:
1. Ruby используется алгоритм mark & sweep
2. Они рассматривают 3 варианта новых сборщиков мусора
Для сравнения:
     В PHP используется алгоритм подсчета ссылок(Основы подсчета ссылок) - с дополнительным алгоритмом определения циклических ссылок (Сбор циклических ссылок)
     В Go также используется алгоритм mark & sweep, но в параллельном варианте. Еще одной особенностью его реализации является то что он совершенно не оказывает влияния на производительность если программа не выделяет память.

суббота, 19 января 2013 г.

Бага в PHP PDO Mysql

      Наткнулся  на замечательную багу в PHP PDO Mysql - после обновления PHP c 5.3.1 до 5.3.2  последний rowset в пакетном SQL запросе просто перестал возвращатся. В общем случае возможность выполнять несколько SQL запросов за одно соединение не часто используется - в основном в силу сложности аггрегирования несвязных запросов в один пакет. Но в моем случае mysql соединение использовалось для выполнения запросов к Sphinx. А в sphinxQL к примеру для того чтобы получить общее количество документов удовлетворяющих критерию - без учета выражения LIMIT необходимо отправлять сразу два запроса в одном пакете - непосредственно запрос по выборке документов и "SHOW META". Также если вы отправляете несколько схожих запросов одним пакетом - то сфинкс может их оптимизировать, кэшируя общие поддеревья. В общем пока придется дописывать в каждый пакет дополнительный запрос "SHOW META" чтобы как-то обходить это ограничение - другого решения этой проблемы я пока не знаю.

пятница, 23 ноября 2012 г.

Go(golang) vs PHP по взрослому

      Я давно хотел устроить сравнение скорости Go и PHP на какой-нибудь реальной задаче  и в условиях близких к боевым. Интернеты кишат синтетическими тестами - например  вычисление квадратных корней в милион потоков  - причем эти тесты чаще всего выполняются на ноутбуке. 
    Итак, есть реальная задача - backend для автосаджеста городов. На вход передается набранная строка - возвращается список возможных городов в JSON. Сами города находятся в sphinx, в количестве 30 тысяч. 
Что с чем сравниваем:
    Текущая реализация написана на PHP c использованием фреймворка Yii. Состоит буквально из 10 строчек, 5 из которых комментарии. Естественно используется opcode cacher.  
   Go реализация занимает чуть побольше - 35 строчек кода. Тестировалось 2 варианта FastCGI и HTTP. Различаются они фактически только подключаемой библиотекой - "net/http" или "net/http/fcgi".  Забегая вперед сразу скажу - разница между этими реализациями лежит в пределах погрешности - менее 1 сотой секунды.
    На чем собственно проводилось тестирование: PHP реализация была разложена на 2-х фронтах(Intel Xeon 8CPU/32GB RAM/Ubuntu 12.xx).  Go реализация была разложена только на одном фронте - потому как деплойный скрипт написан именно под PHP, а раскидывать ручками больше чем на один сервер было лень.
       Как тестировалось: был сгенерирован список URL для siege, состоящий примерно из 250 тысяч различных запросов к автосаджестеру. siege запускался с одного из фронтов - чтобы не учитывать сетевые задержки. Тестировалось с 30, 40 и 50 одновременных соединений.
        Итак результаты:
При 30 одновременных соединениях
Среднее время ответа: PHP - 0.36 секунд, Go - 0.01 секунда.
Самая длинная транзакция: PHP 12.04 секунды, Go - 5.02 секунд.
Самая короткая транзакция: PHP 0.02 секунды, Go - 0.00 секунд.

При 40 одновременных соединениях
Среднее время ответа: PHP - 0.65 секунд, Go - 0.09 секунд.

При 50 одновременных соединениях
Среднее время ответа: PHP - 0.96 секунд, Go - 0.22 секунд.

Выводы:
1. Переписывание на Go данной задачи выглядит более чем оправдано.  
2. При увеличении числа одновременных подключений разница между GO и PHP сильно сокращается. Объяснение этому одно - начинает засасывать sphinx - который запущен только на одном сервере. Также на это повлияло то что siege был запущен на одном из фронтов. 

Также я сравнивал варианты когда обращение идет к Go серверу напрямую и через Nginx: результат порадовал - среднее время ответа различается буквально на 0.01-0.02 секунды. Что в общем еще раз доказывает что проксирование через Nginx работает очень быстро.

Еще я проводил сравнение при разных GOMAXPROCS: результат фактически не изменился. Чего собственно и следовало ожидать в данных условиях.

   

вторник, 23 октября 2012 г.

Handlersocket клиенты для PHP

У меня долго не хватало времени написать этот пост, но поскольку сегодня у нас в офисе внезапно вырубилось электричество у меня неожиданно образовалось парочка свободных часов и я решил посвятить его написанию своего гневного обзора HS клиентов для PHP. Итак начнем.

1. php-handlersocket (http://code.google.com/p/php-handlersocket/) Во многих статьях по HS рекомендуют именно этот экстеншен. Я тоже его до поры до времени использовал. Ровно до тех пор пока дело не дошло до нагрузочного тестирования.   По сути в рамках этого проекта существуют две разные реализации клиента hsclient and native. Одна из которых(hsclient) вообще не работает(за что ей большое человеческое спасибо). Она просто вызывает segmentation fault при обращении к соответсвующим функциям. На то чтобы разбиратся с ней я убил всего пол дня - после сравнительно непродолжительного секса с участвием strace я  понял что дело это гиблое и решил скомпилировать этот же модуль но с использованием native реализации. Эта реализация оказалась гораздо коварнее - она очень хорошо работает в ситуации когда и MySQL и веб сервер находятся на одной машине - то есть на машине разработчика и на тестовым сервере. Но как только дело дошло до нагрузочного тестирования - и MySQL сервер оказался на другом физическом сервере и в другом сегменте LAN (возможно это тоже сыграло свою роль) я заметил проблемы. Примерно 10% запросов к странице заканчивались 500 ошибкой. Смотрю в логи - PHP ругается что в записях получаемых через HandlerSocket нехватает полей. В базе все поля в наличии - а Handler Socket читает их не до конца в некоторые рандомные моменты времени. Причем только при большом количестве одновременных соединений. С помощью tcpdump я сдампил все пакеты между MySQL сервером и выяснил что нужные данные всетаки приходят в полном объеме - но Handler Socket их не читает. На этом мое терпение кончилось и я решил отказатся от этого разширения. Посмотрев на его страницу внимтельнее я обнаружил большое количество баг репортов - но ни один из них так и не был отвечен с апреля месяца. Очевидно что данное разширение не поддерживается больше - так что если вы не хотите внезапно переписывать весь проект на другой экстеншен перед релизом - не стоит с ним связыватся.

2. Следующим на очереди Net_HandlerSocket (http://openpear.org/package/Net_HandlerSocket). После непродолжительных  попыток заставить его работать я понял что эта возьня не стоит свечь.  Плагин очень давно не обновлялся, генерирует кучу варнингов и вообще не содержит тестов.

3. HSPHP (https://github.com/tz-lom/HSPHP) - единственный работающий кандидат. Да это не модуль PHP поэтому он будет работать гарантировано медленнее чем первый клиент, но хотябы работает.  Плюч ко всему архитектура этого выглядит наиболее продуманной среди всех вариантов. Сразу видно людей знакомых с пэттернами проектирования.