Phalcon 2 i projekt Zephir

Zephir

Nie tak dawno temu opisywałem Wam możliwości oraz niespotykaną wcześniej wydajność Phalcon. Zaraz po publikacji tamtego wpisu, twórcy frameworka opublikowali na swoim blogu post dotyczący przyszłości Phalcon oraz wersji 2, a także projektu Zephir.

Na wstępie posłużę się cytatem z bloga, który najlepiej oddaje myśli twórców:

Despite being a PHP extension implemented in C and its young age, Phalcon offers the same or better features than other frameworks that have been around a lot longer. Phalcon is a fast, robust, secure, extendable PHP framework for everyone to use.

Since we have created a great framework, framework’s development is an every day task, constant improvement and evolution is required to deliver more and better applications.

Twórcy Phalcon dostrzegają ogromny potencjał w rozwijaniu swojego dzieła. Rosnąca społeczność wyraźnie o tym świadczy. Ze względu na wykorzystanie języka C, występują problemy w łataniu dziur oraz rozwoju całego frameworka. Widać wyraźnie, że w tym wypadku wsparcie jest mniejsze niż w przypadku pozostałych frameworków, które pisane są w czystym PHP.

Zephir

W związku z powyższym, zespół Phalcon zdecydował się stworzyć projekt Zephir. Jest to nowy język programowania, który pomóc ma w tworzeniu, wspieraniu oraz rozwoju całego ekosystemu.

Jak określają twórcy, Zephir to:

It’s a high level language, something between C and PHP. It’s both dynamic and static typed and it supports just the features we need to create and maintain a project like Phalcon.

namespace Test;

class MyTest extends SomeNamespace\MyAnotherClass 
{
    public function someFunction(a, b) 
    { 
        return a + b;
    }
}

Cały kod w Zephir musi być umieszczony w klasach, które to umiejscowione są w przestrzeniach nazw (namespaces). Użycie $ nie jest wymagane. Zephir to także dynamiczne typowanie ( jak w PHP), ale istnieje także możliwość użycia statycznego typowania, które powodować będzie wzrost wydajności, ponieważ wykonujemy jedną z czynności kompilatora już podczas pisania samego kodu.

Dostępne typy to: long/int, double/float, bool oraz string, które konwertowane są do typów w języku C.

Deweloperzy zwolnieni zostali także z konieczności rezerwowania i zwalniania pamięci. Robi to za nich kompilator.

Składnia języka inspirowana była C, PHP, JavaScript oraz Rust, co bardzo wyraźnie widać na poniższym przykładzie:

namespace Test;

class MyTest 
{
    public function someMethod()
    {
        /* Variables must be declared */
        var fruits;
        int i = 0, length;

        /* Create PHP array */
        let myArray = ["hello", 0, 100.25, false, null];

        /* count the array into a 'int' variable */
        let length = count(myArray);

        /* Print value types */
        while i < length {
            echo typeof myArray[i], "\n";
            let i++;
        }

        return fruits;
    }
}

Bardzo ciekawe. Przyznam, że nie spodziewałem się takiego połączenia. Twórcy w swoim wpisie wspominają także o celach samego projektu Zephir, przyszłości Phalcon z tym związanej oraz opisują wyraźnie to, czym Zephir na pewno nie będzie. Zachęcam do lektury, a sam kibicuję zespołowi.

Phalcon = wysoka wydajność?!

Phalcon PHP

Phalcon is a web framework implemented as a C extension offering high performance and lower resource consumption.

There are many PHP frameworks nowadays, but none of them is like Phalcon (Really, trust us on this one).

To pierwsze dwa zdania, które wprowadzają nas w świat Phalcon przez ich autorów.

Phalcon znalazłem kilka dni temu. Miałem chwilę czasu, więc wykorzystałem ją na jego bliższe poznanie, bo.. zainteresowały mnie powyższe dwa stwierdzenia oraz grafika, która prezentowana jest na stronie głównej. Pokazano na niej wykres wydajności poszczególnych frameworków i oczywiście Phalcon znacznie przebija na nim konkurencję.

Ale jak?

Spędziłem kilkanaście minut na zapoznanie się z dokumentacją, gdzie twórcy wyjaśniają skąd wziął się pomysł na kolejny framework i dlaczego zbudowany został on w taki a nie inny sposób. Mianowicie chcieli oni wyeliminować wszystkie negatywne cechy istniejących frameworków, czyli między innymi:

  • dużą ilość potrzebnych zasobów, które muszą zostać stworzone i zarezerwowane by udostępnić podstawowe funkcjonalności – duża liczba inkludowanych plików i duże wykorzystanie dysku twardego
  • dużą ilość niewymaganych funkcjonalności, których nigdy nie wykorzystamy bądź nie są one potrzebne za każdym razem gdy przetwarzane jest żądanie HTTP – duża ilość pamięci ram, która potrzebna jest do załadowania tego wszystkiego
  • za każdym razem wszystkie pliki są interpretowane od nowa, a przecież kod frameworka nie zmienia się tak często jak część biznesowa odpowiedzialna za naszą aplikację – procesor za każdym razem musi się napocić by wykonać taką interpretację kodu PHP

Rozszerzenie w C!

Jak im się to udało? Przyjrzyjmy się zaletom rozszerzeń PHP w postaci bibliotek napisanych w języku C:

  • rozszerzenia napisane w języku C ładowane są RAZ razem z PHP podczas procesu startu serwera
  • wszystkie klasy i funkcje gotowe są do użycia w dowolnej aplikacji
  • kod nie jest za każdym razem interpretowany, bo został on już wcześniej skompilowany do postaci wykonywalnej na danej platformie i przez dany procesor

Run it on Phalcon!

Jak działa w takim razie Phalcon? Otóż jest to właśnie rozszerzenie do PHP napisane w języku C i ładowane jest tylko i wyłącznie RAZ – podczas startu serwera, który uruchamia także interpreter PHP. Dlaczego więc Phalcon?

  • wszystkie komponenty oraz klasy są ze sobą bardzo luźno powiązane – możemy dowolnie dobierać sobie funkcjonalności i wykorzystywać wszystko co daje nam framework lub tylko wybrane komponenty
  • optymalizacja na niskim poziomie
  • interakcja z bazą danych przy użyciu ORM napisanego w języku C
  • użycie natywnej obsługi PHP w języku C

Sami przyznacie, że wygląda to bardzo obiecująco.

Podsumowanie

Poza bardzo dobrą dokumentacją – twórcy przygotowali także ciekawe przykłady, które pokazują użycie Phalcon w różnych projektach, o różnych profilach działania.

Wyniki benchmarków, które prezentowane są oficjalnej stronie, pokazują, że taka budowa frameworka ma sens i rzeczywiście przyspiesza wykonywanie zapytań. Sam także pokusiłem się o przykład Hello World w Symfony 2.3.2, Slim oraz Phalcon. Wynik? Symfony i Slim ładują się jakieś ~50ms, a Phalcon ~10ms!

Zachęcam tym samym do zapoznania się z całą dokumentacją oraz własnych eksperymentów. Z pewnością nie jest to moje pierwsze spotkanie z Phalcon.

Aktualizacja

W odpowiedzi na komentarz, gdzie jego autor prosił mnie o dodatkowe testy przy wykorzystaniu Apache Benchmark. Testy wykonywane były na jednej maszynie w środowisku Windows w oparciu o instalację XAMPP (Apache 2.4.3 oraz Apache Benchmark 2.3). Testowane było wywołanie strony głównej za którą odpowiedzialny był jeden kontroler z jedną pustą metodą i widok z tekstem “Hello world!”. Jest to więc sytuacja bardzo podobna do przykładu twórców frameworka. Dodam też, że środowisko to tryb deweloperski z włączonym trybem debuggera oraz wyłączonym cache.

Poniżej skrócone wyniki dla:

  • 100 równloległych połączeń dla 1000 zapytań
    Concurrency Level:      100
    Time taken for tests:   5.626 seconds
    Complete requests:      1000
    Failed requests:        0
    Write errors:           0
    Total transferred:      429000 bytes
    HTML transferred:       213000 bytes
    Requests per second:    177.74 [#/sec] (mean)
    Time per request:       562.632 [ms] (mean)
    Time per request:       5.626 [ms] (mean, across all concurrent requests)
    Transfer rate:          74.46 [Kbytes/sec] received
  • 1000 równloległych połączeń dla 10000 zapytań
    Concurrency Level:      1000
    Time taken for tests:   13.292 seconds
    Complete requests:      1000
    Failed requests:        8
       (Connect: 8, Receive: 0, Length: 0, Exceptions: 0)
    Write errors:           0
    Total transferred:      429000 bytes
    HTML transferred:       213000 bytes
    Requests per second:    75.23 [#/sec] (mean)
    Time per request:       13291.760 [ms] (mean)
    Time per request:       13.292 [ms] (mean, across all concurrent requests)
    Transfer rate:          31.52 [Kbytes/sec] received
  • 100 równloległych połączeń dla 100000 zapytań
    Concurrency Level:      100
    Time taken for tests:   219.302 seconds
    Complete requests:      100000
    Failed requests:        0
    Write errors:           0
    Total transferred:      42900000 bytes
    HTML transferred:       21300000 bytes
    Requests per second:    455.99 [#/sec] (mean)
    Time per request:       219.302 [ms] (mean)
    Time per request:       2.193 [ms] (mean, across all concurrent requests)
    Transfer rate:          191.04 [Kbytes/sec] received

Przy większej ilości równoległych połączeń dla liczby zapytań większej niż 1000 moja instalacja Apache niestety nie dawała rady. Widać jednak, że wydajność Phalcon nie jest przesadzona.