10 июня 2014 в 16:06

Phalcon Framework на продакшене из песочницы

PHP*
Последним временем известность набирает необычный в среде php фреймворк Phalcon, который является расширением языка. Думаю, что многим интересно узнать, каков фреймворк в бою, однако по тем или иным причинам не могут позволить себе использовать его в разработке. В моей компании решились на такую авантюру и я спешу поделиться увиденным и нащупанным. Добро пожаловать под кат.

Откуда ноги растут


В компании есть проект, для которого требуется диспетчер. Грубо говоря, это механизм проксирования и балансировки виджетов в зависимости от предпочтения пользователя. Текущий диспетчер достался в наследство толи от инков, толи ацтеков, что породило внутри коллектива убеждения, что диспетчер был всегда и без него будет тоже, что с Землёй без календаря Майя. Иными же словами, код страшен, запутан, но работает и требует поддержки. Написан диспетчер на Zend Framework 1, расположен код на нодах Amazon, а именно на c3.xlarge, используется APC. При пиковых нагрузках доходит до 8-10 тысяч хитов в минуту и в такие моменты работают 5 нод. Меня это положение вещей совсем не устраивало, так как сам диспетчер не содержит в себе сложного функционала, работа с БД на примитивном уровне, результаты которой кешируются, да и все, что можно — сложено в кеш. Основная нагрузка — это php и Zend. От php отказаться не получится, а вот со вторым вариантом можно попробовать, тем более что для диспетчера мощности и гибкости фреймворка совершенно не требовалось, а на первом месте в приоритете стояла скорость работы и потребление ресурсов.

За ходом разработки Phalcon я следил давно, потому что его benchmark, еще, и и еще мне очень нравились и хотелось попробовать его в чем-то нагруженном. Что ж, настал его черёд и я на скорую руку, переписав критично важный код диспетчера на Phalcon, решил погонять его на тестовой ноде (m3.medium) с APC. Для тестирования я использовал jmeter, создал простые нагрузочные тесты и запустил их в 500 потоков.

Нагрузочное тестирование показало, что расход памяти уменьшился в два раза, по сравнению с Zend. Мерял каждый запрос с помощью memory_get_usage().

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

Framework Threads Loop Hits Max load average Test runtime Average response, ms Median, ms Min, ms Error
Zend 500 60 30000 125 03:30:00 3,083 2,028 271 2.83%
Phalcon 500 60 30000 76 01:55:00 1,549 947 138 0.86%


Релиз

Результаты порадовали и было решено переносить проект на Phalcon. После небольшого рефакторинга кода, внедрения DI контейнера код был протестирован и готов к продакшену.

Хочу подчеркнуть, что код не был значительно оптимизирован, во многих местах код получил только косметический рефакторинг. Когда настал час «Ч» с замиранием сердца выкатил на ноды код и стал мониторить за состоянием системы. Вот какой график получился:

image

Что мы видим: релиз был в пиковое время по нагрузке — работало 5 нод на Zend, c нагрузкой по CPU под 80%. После обновления 5 нод на Phalcon, нагрузка упала ниже 20%. На графике видно, что есть возврат к 5 нодам Zend — это было сделано для того, чтобы убедиться, что все графики мониторинга Zend совпадают с Phalcon. Все было хорошо, потому решил отключить три ноды и посмотреть, как будет справляться Phalcon. Две ноды использовали чуть более 45% CPU, что позволило попробовать авантюру и оставить одну ноду. CPU упёрлось в 100% и пошли 500-е ошибки, однако проблема была не с Phalcon, а с Nginx, которому стало тяжело держать большое количество соединений. Сразу же вернул в балансировщик одну ноду, и поставил себе задачу на будущее подкрутить Nginx. Замена Zend на Phalcon позволила перейти с 5 нод на 2 ноды, что снизило расходы на Amazon, а также облегчило деплой и мониторинг системы.

Несколько слов о самом фреймворке

Не буду описывать сам фреймворк, так как документация на сайте хорошая, есть на русском и цель статьи другая.

На момент рефакторинга, актуальная версия фреймворка была 1.2.6, которая и использовалась. Фреймворк нисколько не показался сырым — никаких багов с функционалом, который нам требовался замечено не было. Также замечу, что Phalcon умеет достаточно много чего и работало все в соответствии с документацией.

Использовал работу с моделями со встроенным Active Record. Модели мощные, умеют много чего — валидация, кеширование, связи, виртуальные внешние ключи и так далее. Для изощренных запросов есть свой мета-язык PHQL. Для заинтересовавшихся — ссылка на документацию.

Во время разработки были проблемы с кешом — в какой-то момент я заметил, что очень странно кешируются данные, соединение с memcache происходит более одного раза, не всегда кеш есть, хотя в memcache данные попадают. Проблема оказалась в том, что я не верно использовал DI container. Я кеш добавлял через метод set(), и при обращении к DI контейнеру каждый раз получал новый экземпляр класса, с новым соединением к мемкешу.
А для того, чтобы возвращался каждый раз один и тот же объект, нужно класть его в контейнер вот так:
$di->setShared('cache', $cacheObject);
Исправив ошибку, все заработало как ожидалось. Данный подход позволил отказаться от всех Singleton в проекте, что и было с удовольствием сделано.

После релиза, вышла в свет следующая версия фреймворка — 1.3, которая без проблем установилась и работала с кодом проекта. Пришлось подправить только пару мест с DI контейнером, чтобы завести приложение.

Работа с CLI

Работа с консольными тасками в Phalcon совсем простая и пока что не имеет больших возможностей, по сравнению, например с Zend. Нет возможности указать параметры по умолчанию, а обязательные — попросить дописать при вызове таска прямо в консоли. Работа с параметрами сводиться к самостоятельному парсингу $argv; Также нет никаких красивостей с цветными текстами, фонами, так что разукрасить консоль радугой не получится. Но с другой стороны, хоть функционал не богат, но все же свою функцию исполняет. А со временем появятся примочки и свистелки.

Немного дёгтя

Расстроило отсутствие в фреймворке элементарного LogNull для логирования, который пришлось дописать на php.
Также удивило отсутствие возможности мерджить конфиги.
UPD: как подсказали в комментарии — возможность есть

Из недостатков, которые могут быть для кого-то серьёзным аргументом отказаться — это невозможность поправить код фреймворка. Если вы обнаружите уязвимость, то ничего не сможете с этим сделать — исходники скомпилированы. Однако разработчики переписывают Phalcon на Zephir (подробнее о Zephir попытаюсь написать отдельную статью), что даст возможность править сам фреймворк, а также писать для него расширения на C.

Это будет сделано в версии Phalcon 2.0, которая на сегодня имеет состояние Beta 1. Надеюсь, что в скором времени мы увидим стабильный релиз.

Есть что ещё рассказать о фреймворке, однако думаю, что это тема для отдельной статьи, потому подведу вкратце итог использования на нагруженном проекте Phalcon:
— производительность не сравнимая с Zend (аналогичными php фреймворками)
— прост в изучении, если есть опыт работы с фреймворками
— фреймворк не выглядит сырым и недоделаным, однако есть куда расти и развиваться
— невозможно поправить код фреймворка
Павел Веснин @PaulBardack
карма
7,0
рейтинг 0,0
программист
Похожие публикации
Самое читаемое Разработка

Комментарии (33)

  • +1
    > Также удивило отсутствие возможности мерджить конфиги.
    docs.phalconphp.com/ru/latest/api/Phalcon_Config.html
    public merge (Phalcon\Config $config)
    • 0
      Спасибо за замечание. В ходе написания статьи забыл, что проблема была не с мерджем конфигов, а наследованием
  • +1
    $di->setShared('cache', $cacheObject);
    или
    $di->set('cache', $cacheObject, true);
  • +1
    От php отказаться не получится

    Есть такая замечательная вещь как PHP-CPP, которая может помочь вынести нагруженные места в С++ без сильной головной боли из-за сложного Zend Engine.
  • +2
    Почему не попробывали hhvm? B php работает и с++ апи вполне хорош
    • +1
      Это он в рекламе дает прирост. На практике прирост производительности в лучшем случае будет пара десятков процентов, но скорее всего и вовсе не будет.
      Нужно тестировать с конкретным приложением.
      • 0
        подтверждаю, на чистом yii он раза в 1.5-2 медленнее обычного fpm и раза в 2.5 в простом варианте синтетического теста, в котором я в цикле увеличиваю счетчик и веременную добавляю чмсло в степени счетчика и так до 100000. запускал по 100 раз через hhvm и через php cli и там разница была просто огромная в пользу cli. но это на конфигах из коробки.
        • 0
          Тоже видел бенчмарки, которые совсем не радовали. И все же не думаю, что в FB зря потратили время. Возможно не правильно готовят
          • 0
            Полностью согласен. Что-то упущено в инфе от ФБ, но я сразу оговорился, что использовал базовые конфиги, возможно хитрое шаманство позволит разогнать hhvm…
            • 0
              Возможно всему виной то, что Yii во всю использует магические методы (_get/__call). HHVM инлайнит геттеры, так что вызов геттера или обращение напрямую к свойству будут одинаково быстры. Магические методы же медленнее чем просто вызовы методов, ну и плохо поддаются оптимизациям. Хотя это не должно было повлиять настолько сильно. Ну и крайне интересно как вы получили грустные результаты на математических операциях. Возможно просто слишком маленькое количество итераций, или не учитывалось время старта HHVM и т.д. Словом — слишком расплывчато. Я пока не видел ни одного бенчмарка с сильно грустными результатами.

              Хотя в итоге все равно нужно видеть код. Вообще было бы неплохо написать простое приложение (желательно RESTFull-сервис) на нескольких фреймворках (например покрыть весь функционал Behat-тестами дабы нивелировать различия) и уже имея на руках несколько различных реализаций (причем желательно включить и Phalcon туда-же) уже делать какие-то выводы… Ну и эксперементировать с различными подходами. Да и будет наглядное сравнение о том как тот или иной функционал реализуется в контексте разных фреймворков. Так же было бы неплохо резюмировать статистику о времени затраченном на разработку функционала (приблизительно).
    • 0
      Главная причина — отказаться от тяжелого и ненужного Zend, потому выбирал из фреймворков.
      По поводу hhvm — технология слишком молода, чтобы в компании решились бы на ее использование.
      • –1
        А фалкон значит не молода, или может у HHVM беда с суппортом, команды нету, фэйсбук их не форсит… А есть еще hippyvm (который основан на PyPy), который по заверению разработчиков в 7 раз быстрее стандартной реализации PHP(правда на синтетических тестах).

        Хотя можно рассматривать HHVM и HippyVM как быстрый способ ускорить приложение, так сказать за не дорого, без необходимости переписывать все и вся.
        • 0
          Сравнивать HHVM и фалкон не корректно. Фалкон это просто framework, и задача была сменить framework. Как известно универсальные методы ускорения никогда не сравнятся с оптимизацией кода.
          • 0
            С оптимизацией кода — сравнится, а с оптимизацией архитектуры — нет. Фалкон — попытка оптимизации архитектуры приложений за счет выноса большей части сервисного слоя на уровень API языка. HHVM, HippyVM, phpng — так же являются глобальными оптимизациями архитектуры самого PHP. Можно так же выкинуть Zend и ORM и получить схожий профит, но поддержка подорожает.

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

            Подходы с использованием сторонних реализаций или внедрение JIT в сам PHP дадут более ощутимый профит для всех, так как интерпритируемые языки и создавались для добавления слоя абстракции и независимости от платформы. В противном случае лучше подумать о сегментации проекта и реализации тяжелых его частей на golang/rust/d.
            • 0
              А какие риски увеличиваются выбрав фалькон вместо того же зенда?
              «Серьезные проекты» это, извините, фраза ни о чем, что вы подразумеваете под серьезными проектами, какие метрики?
              • 0
                Проекты хотя бы на 10К+ часов разработки и с большим временем жизни/поддержки, в основном какие-то корпоративные решения, стартапы и т.д. Если выбирать писать приложение требующее высоких нагрузок на PHP+HHVM или просто на PHP+Opcache, и Phalcon я бы выбрал для начала PHP+Opcache и потом бы смотрел в сторону HHVM и подобных решений (тот же HippyVM предлагает коммерческую версию с суппортом), а критичные к нагрузкам вещи переписал бы на golang/rust.
  • 0
    Если вы обнаружите уязвимость, то ничего не сможете с этим сделать — исходники скомпилированы

    Унаследовать/переписать класс, поправить уязвимость/баг и использовать его( пока не поправят в фреймворке).
    Имея DIC несложно подсунуть свой класс.
    Ну и зефир на подходе, да.
    • 0
      Да, как вариант. Но тогда теряется то, ради чего выбирается фреймворк. Вдруг компонент тяжелый окажется? Или его реализация не очевидна и не известно, как нужно реализовать.
      • –1
        Нас поначалу тоже это смущало, но потом мы пришли к выводу, что это надуманная проблема.
        Вероятность ошибки в фрейморке достаточно низкая, т.к. он покрыт тестами и находится уже в стабильной версии (мы начинали вообще с версии 0.8 и уже тогда всё работало хорошо).
        А если уж вдруг так повезло и вы упёрлись в баг, то его можно пофикисть заменив функции фрейморка на свой или другим фреймворком и отписав в баг-трекер. Или, совсем если уж припёрло, можно залезть в исходники и там поправить и пересобрать.

        Но, повторюсь, это очень маловероятно и не стоит на этом зацикливаться. Я в своей практике ещё не встречал проблем, которые совсем никак не решались;)

        P.S.: ещё можно добавить, что в самом PHP полно багов, и ничего, работает же
        • +2
          Меня это не смущало, потому что я считаю, что править сторонний код фреймворка — опасное дело. Только пул-реквесты.
          Ну и не мог же я не указать никаких проблем, надо же быть объективным :)
          На меня Phalcon произвел очень позитивное впечатление, не дождусь 2.0 версии.
  • 0
    Также нет никаких красивостей с цветными текстами, фонами, так что разукрасить консоль радугой не получится

    Консоль можно легко раскрасить радугой самостоятельно: www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/
    • 0
      Можно. Я говорю о функционале из коробки.
  • +2
    Мне очень нравится что фалкон следует логике написания функций PHP:
    public function Adapter::update($table, $fields, $values, $whereCondition=null, $dataTypes=null) bool
    public function Adapter::insert($table, $values, $fields=null, $dataTypes=null) bool
  • +1
    … однако проблема была не с Phalcon, а с Nginx, которому стало тяжело держать большое количество соединений…

    nginx не в состоянии держать ~500 соединений? Что-то невероятное. Можно поподробнее?
    • 0
      Нет, nginx не справлялся с 25к соединений. 500 соединений было открыто на тестовой ноде, где для него проблем не было.
      • +2
        Тюньте ваш nginx. 25к он может выдавать на обычном относительно новом офисном компе.
        • 0
          Собственно это я и имел в виду в статье, как следующий этап оптимизации.
          • +1
            Следующая статья будет целиком посвящена открытию директивы worker_connections? =)
            • 0
              Плюсанул бы, если б мог :) Подумаю.
  • 0
    del
  • +1
    • 0
      502 Bad Gateway
    • +1
      Спасибо за отзыв. В статье я указал, что работа с БД была на примитивном уровне — никаких связей, потому лично я не столкнулся с такими ошибками.
      Роутинг, DIC, простые модели (get/set, кеширование), консольные таски, логгирование — работает без нарицаний.

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