SOA with PHP and Symfony

457 views

Published on

Lesson learned during new project base on SOA architecture. Technology used in our project:
- Symfony 2.3
- PHPUnit
- SoapUI
- RabbitMQ
- MySQL (Percona)
- Elasticsearch
- Jenkins
- Memcached
- Nagios
- New Relic

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
457
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Nazywam się Michał Schroeder, dla zainteresowanych podaję też mój adres e-mail. Jakby ktoś się wstydził zagadać do mnie dzisiaj w przerwie, bądź też po prezentacjach, to może śmiało skontaktować się ze mną mailowo.
  • Opowiem Wam dzisiaj trochę o moim projekcie w którym uczestniczyłem przez ostatnie 12 miesięcy. W prezentacji poruszę kilka różnych tematów i zagadnień. Będzie o bazach danych, wydajności, Symfony2, architekturze i asynchronicznej komunikacji między niezależnymi komponentami. Część rzeczy będzie uniwersalna, które będzie można wykorzystać w projektach nie tylko opartych na architekturze SOA. Wiele rzeczy może się niektórym wydać oczywista, ale mam nadzieję że każdy wyniesie z tej prezentacji coś nowego i pożytecznego. Z drugiej strony nie będę się też wdawał w niskopoziomowe szczegóły i tłumaczył np. co to jest Vagrant, REST czy jak się powinno korzystać z tych narzędzi. W większości były już prezentacje na te tematy na poprzednich edycjach PHPers. Polecam notować sobie ewentualne hasła, które Was zainteresują i wtedy w przerwie bądź po prezentacjach dopytać o szczegóły jakie Was interesują. Aby nie tracić czasu, zaczynamy!
  • Zacznę od odpowiedzi na pytanie, co to jest SOA dla tych osób które nie miały styczności z tym pojęciem.
    Jest to service oriented architecture czyli architektura oparta o serwisy czyli małe klocuszki z których budujemy większa aplikację
    Komponenty komunikują się pomiędzy sobą przez ustalony protokół, przeważnie jest to protokół sieciowy w przypadku naszej aplikacji był to REST
    Głównym założeniem tej architektury jest to aby każdy komponent był reużywalny (np. komponent użytkownika, szkoły, klasy)
    Każdy serwis jest „czarną skrzynką” dla klientów, klient nie wie jak jakaś funkcjonalność jest zaimplementowana, w jakiej technologii itd. Dla niego ważne jest to że spełnia on swoją rolę.
    Każdy serwis jest też samodzielny i niezależny co oznacza np. bark powiązań na poziomie bazy danych. Brak JOIN-ów co powoduje zwiększoną ilość zapytań do bazy.

  • - Omówienie diagramu.
    - SOA była dla nas nowa, pierwsze nasze podejście do takiej architektury.
    - Frontend robiła firma zewnętrzna w Javie
  • Jest to tylko w draft więc nie można się na to zapinać bo nie wiadomo czy nie zostanie to np. docelowo usunięte lub nie pojawi się w ostatecznej specyfikacji pod inną nazwą
    Problem z narzędziami które to wspierają
  • Jak już wspomniałem wcześniej, na wcześniejszym jednym z pierwszych slajdów, architektura SOA opiera się na niezależnych komponentach. Jak zatem zapewnić spójność danych pomiędzy wszystkimi komponentami? Łatwo sobie wyobrazić sytuacje w której np. usuwamy użytkownika z naszego systemu ale cały czas zostają powiązania użytkownik-klasa czy użytkownik-szkoła.

    Myśmy w naszym projekcie wykorzystali do tego oprogramowanie RabbitMQ. Jak to działa?
    W skrócie jest to tak że mamy główny serwer RabbitMQ zainstalowany na serwerze który nasłuchuje na wiadomości. Przykładowo w komponencie USER po usunięciu użytkownika wysyłamy do tego serwera wiadomość „użytkownik został usunięty” wraz z jego ID. Serwer przekazuje dalej w świat taką wiadomość. Dodatkowo w systemie jest 5 innych komponentów, które nasłuchują takiej wiadomości. Po odebraniu jej mogą wykonać jakieś kroki, w naszym przypadku np. pousuwać powiązania użytkownika z szkołą, klasą itd.

    Czasem używaliśmy interfejsów które wystawiają poszczególne komponenty aby wykonać dodatkowo jakieś zadanie np. przy usuwaniu użytkownika. Minusem tego jest to że w ten sposób wiążemy komponenty, tzn komponent USER musi wiedzieć że jest tam gdzieś komponent szkoła czy klasa gdzie trzeba też tego użytkownika usunąć. Dodatkowo jest to też czas potrzebny na wszystkie żądania.

    Kolejnym rozwiązaniem jest możliwość stworzenia zadań CRON które w nocy będą usuwać wszystkie zbędne „śmieci”

    Czasem bywa też tak że takie powiązania i „śmieci” nam nie przeszkadzają w żaden sposób. Wtedy po prostu się tym nie przejmujemy.
  • Problem jaki się pojawił to jak wygenerować raport, który bazuje na dwóch lub więcej komponentach? Załóżmy że mamy wyświetlić raport wyników ucznia z danej szkoły w którym będzie imię, nazwisko, klasa do której należy oraz wyniki ucznia wg przedmiotów. W normalnej jednoklockowej aplikacji wykorzystalibyśmy JOIN-y na bazie danych. Jednak tutaj nie możemy tego zrobić, więc jak w takim razie podejść do tematu?

    Po raz kolejny rozwiązaniem tego problemu okazał się w naszym wypadku RabbitMQ. Załóżmy że mamy ucznia który sobie zapisuje wyniki swojego zadania. Wyniki te wysyłamy na kolejkę RabbitMQ i komponent RESULT zapomina o tym. Z tej kolejki dane o wyniku pobiera 5 raportów, są to osobne consumery, które zapisują lub aktualizują swoje dane.
  • Wyłączamy niepotrzebne i nieużywane w naszej aplikacji komponenty
    Wyłączamy logowanie w Doctrine
    Okroić logowanie Symfony2
    Zbyt duża ilość listnerów na requesty HTTP
    Używać cache przy autoloaderze
  • Kolejny problem jaki się pojawił był związany z RabbitMQ. W sumie to nie był problem z Rabbitem a naszym podejściem do pisania consumerów. Potraktowaliśmy konsumery jak typową aplikację webową gdzie mamy request do serwera, coś tam przetwarzamy, pobieramy z bazy czy coś do niej zapisujemy wysyłamy odpowiedź i to koniec życia requestu.

    Przyczyn było kilka jednak najważniejsza
  • SOA with PHP and Symfony

    1. 1. • Service-oriented architecture • Communication over protocol (typically network) • Reusable components • Services are a „black box” for a clients • Each component is independent and self- contained
    2. 2. • E-learning platform for primary school • Addition to books • Teaching by playing – Gamification – Team working – Personalization (dynamic avatars) – Virtual currency
    3. 3. • Producer send message to RabbitMQ server • Consumer can pick up selected messages • Consumers are run in CLI • Consumers can be run in different modes • We are running consumers in endless loop
    4. 4. Problem: We have fixed date when project will go live but team wants to work in Agile methodology. Solution: Spend few days/weeks for analysing requirements and plan all sprints to the deadline.
    5. 5. Problem: Data consistency between all independent and self-contained components Solution: - Advanced Message Queuing Protocol. We have used RabbitMQ - Communication with components using their external interface - Using cron jobs for clearing data at nights - Ignore this, it's not always important and critical for your application Improve/explore : ESB - Enterprise Service Bus
    6. 6. Problem: How to generate reports based on two or more self-contained components? Solution: RabbitMQ
    7. 7. Problem: How to test all components? What about integration tests of our orchestration level? Solution: • PHPUnit in components (mock external components) • Automated tests written by our testers in SOAP UI Improve: • More tests  • Behat • PHPSpec
    8. 8. Problem: Performance of the whole application doesn’t satisfy us Solution: • Disable unused components like: Session, Security • Disable Doctrine logging • Proper configuration of Symfony logger • Always use Composer class loading optimization • Too many listeners on HTTP requests • Use APC, Xcache or any other PHP accelerator • Use ApcClassLoader or XcacheClassLoader • HTTP cache (Varnish)
    9. 9. Problem: Processing of messages was very slow and memory leaks in consumers. Solution: Clean up after yourself • Use unset() method • Doctrine methods: free(), detach(), clear()
    10. 10. Problem: MySQL errors: • 2013: Lost connection to MySQL server • 2006: MySQL server has gone away • 2003: Can't connect to MySQL server Solution: Catch all those exceptions and try to reconnect to the database server. We have set up also some timeout between all retries.
    11. 11. Problem: Can I trust consumer scripts? What with situation when consumer will have problem with connection with database etc. Exception is thrown and message can be lost. Solution: • Creat failover files • Catch all exceptions • Log message into that file. • Create mechanism for processing failed messages
    12. 12. Problem: We are using Memcached but QPS (Query Per Second) of the MySQL server doesn't satisfy us Solution: Configure read/write split in your database and prepare separate connections in your application
    13. 13. Problem: Performance of the database layer still doesn’t satisfy us Solution: Monitor database queries during development How: • Use Symfony profiler • Log all database queries to the temporary file on your dev environment. Then use „tail –f” command to monitor all queries during requests • Use EXPLAIN on more complicated queries
    14. 14. Problem: Doctrine performance is unsatisfactory. Moreover Doctrine create many unnecessary queries. Solution: • Use DQL instead Doctrine findAll() method • Use native query for more complicated queries • Avoid entity mapping when it’s not necessary (hydration mode) • Use „extra lazy” fetching strategy for associations • For big collections fetch only necessary fields
    15. 15. Problem: How to monitor application? How detect problems before they will become a serious? Solution: Monitoring software • New Relic • Nagios Improve: Logstash + Kibana + Elasticsearch
    16. 16. • Symfony 2.3 • PHPUnit • SoapUI • RabbitMQ • MySQL (Percona) • Elasticsearch • Jenkins • Memcached • Nagios • New Relic
    17. 17. • First project on new framework • First use of Doctrine
    18. 18. • Run all Symfony2 console commands with --env=prod parameter • Write your own wrappers to all main external libraries • Use Vagrant or Docker • Run load tests on filled database • Automate your processes (ie. Ant + Jenkins) • Add created_date and modified_date to all tables (use MySQL triggers)
    19. 19. Quetions?

    ×