Heavy Lifting

6f676db35d9c4a3b701ca41f266d693c?s=47 Mario Mueller
September 07, 2012

Heavy Lifting

6f676db35d9c4a3b701ca41f266d693c?s=128

Mario Mueller

September 07, 2012
Tweet

Transcript

  1. Heavy Lifting trivago goes Symfony

  2. Intro Foto: probe.ch / flickr

  3. Mario Müller

  4. Worum geht's? • Bestandsaufnahme • Zielsetzung • Evaluierung • Konzept

    / Umsetzung • Lesson Learned
  5. None
  6. trivago business facts • Hotel Meta-Suche mit ~130 Partnern und

    mehr als 550.000 Hotels • bis zu 1.000.000.000 PHP Req. / Monat • > 20 Sprachen • aktuell 30 Länder-Plattformen
  7. trivago Teilbereiche • Hotelsuche und Preisvergleich • Community mit Bewertungen

    und Bonusprogramm (UGC) • Hotelier Plattform (UGC) • Partner Plattform mit Statistiken und Informationen zur jeweiligen Partner- Anbindung (non-pulic)
  8. trivago Technik • PHP 5.3 / JavaScript / Java /

    C / Bash • FreeBSD • Apache / Percona / Memcache / Redis • Diverse CDN Provider • Direkte Level 3 / NTT Anbindung
  9. Foto: (c) ibikenz / flickr

  10. • PHP 5.2 kompatibler Code • ca. 1.2 Mio. Zeilen

    • Teilweise > 5 Jahre alt • Ein Mix aus prozedualem, teilw. objektorientiertem und "Ninja" - Code mit $GLOBALS, global und einer Menge "&". "Legacy"
  11. Zielsetzung • Hohe first-byte Performance (um oder unter 200ms, aktuell

    175-350ms) • Steigerung der Wartbarkeit und Erweiterbarkeit • Testbarkeit des Codes sicherstellen • Auftrennung des Codes nach OOP Mustern (SOC, IOC, ...)
  12. Evaluierung

  13. • Ist für trivago technisch der wichtigste KPI • Alle

    PHP Requests (weltweit) werden aus Düsseldorf bedient. • Kein CDN / HTTP Caching für HTML • Pro Suche zwischen 10 und 100 AJAX Requests (Polling, Filtering, etc.) Performance
  14. Zend Framework 2 • Performance- Overhead ~60ms • Wenig Dokumentation

    • Unklare API Stabilität, da Beta Kontrahenten Flow 3 • Performance- Overhead ~300ms • Akzeptable Dokumentation
  15. Symfony 2 • Performance Overhead ~60ms • Akzeptable Dokumentation •

    2.0 mit mehreren Patch-Releases • Bonus: Bisherige Architektur Planung passt gut in das Symfony Konzept
  16. Cherry-Picking • Config / Routing / Event Dispatcher • HttpFoundation

    • Service Container • Twig • Assetic
  17. Allerdings ... • Kein Doctrine ◦ Zu langsam für unsere

    Bedürfnisse ◦ Bei stark denormalisierten Daten macht ein ORM keinen Spaß mehr • Kein Monolog im "prod" Env. • XML statt YAML (XSDs, weniger anfällig)
  18. Architektur

  19. Konzept Idee • Separation of Concerns !important; • Web Framework

    von Business Code trennen (Physikalisch & Architektur) • trivago's Business Code enthält keine Referenzen auf Symfony APIs • Ausnahme: Symfony APIs mit eigener Impl. (Security, Event Listener, Twig Extensions).
  20. • Components ◦ Keine Queries (Kosten / Nutzen) ◦ Keine

    Entities (Dürfen keine Dependencies haben) • Services • Business Cases • Traits als alternativer Ansatz Service Container
  21. Grundlegender Aufbau Components (DB Pooling, Locale/Lang Handling, etc) Query (pro

    Query eine Class) Entities ("dumme" Klassen mit public Properties) Services (Datenbeschaffung durch Components, Cache Steuerung, Aggregation mehrerer Services) Business Cases (Modellierung der Geschäftslogik durch die Verwendung von Services) Symfony2 Controller In manchen Fällen erw- eist sich ein Business Case als ineffizient
  22. Unsere "Evolution"

  23. Vorab • Die XML Beispiele in der Online-Doku sind häufig

    unvollständig, die XSDs sind die bessere Doku. • Konfiguration pro Hostname + config_local für lokale Überlagerung macht Sinn • Versioniertes Cache-Dir (Release ID) um zwei Stände gegen einander zu halten + Rollback wenns brennt
  24. Alpha Version • Konnte noch nicht viel, gemessen am Projektziel

    • Brauchte 900 - 1500ms bis first-byte • Ajax Calls lagen bei ~600ms • Company-interner Test mit ~80 Usern.
  25. Symfony 2 • Listener zusammengefassen, weniger ist mehr • Serverseitiges

    Rendern von HTML für AJAX veringert, durch json_encode ersetzen • Erster Versuch: Universal Classloader ggn XCacheClassloader ersetzen. #fail • Statischer Autoloader (@arneblankerts) #win
  26. Beta Version • Konnte schon ein Bisschen mehr • First-byte

    bei 600 - 700ms • Ajax Calls bei 400 - 460ms • Erster Live-Test in Frankreich
  27. • Mehrere AppKernels + eigenen AbstractAppKernel bringen Ordnung (und Performance)

    • Konfigurationen mit mehr als 4 Environments sucken • addClassesToCompile() nutzen! Symfony 2
  28. Twig • Autoescape abschalten. Händisch escapen +15% Performance • ext/Twig

    nutzen! Twig's getAttribute ist teuer! • Macros vermeiden, besonders in Loops!
  29. Release Candidate • Funktionalität produktionsreif • First-byte bei ~300ms •

    Ajax Calls bei < 200ms • Mehrere Live-Tests in Frankreich und Deutschland
  30. Assetic • Base URLs shuffeln ist machbar, reicht uns aber

    nicht • Base URL - Bestimmung zur Laufzeit nach Locale notwendig • Haben wir selbst gebaut auf Basis von Assetic, ist (noch) nicht Open-Source
  31. Und dann ... fingen wir an das JavaScript für den

    IE zu "optimieren" ... ... aber das ist eine andere, längere Geschichte.
  32. Vielen Dank