$30 off During Our Annual Pro Sale. View Details »

FrankenPHP: A modern app server for PHP, written in Go

FrankenPHP: A modern app server for PHP, written in Go

https://frankenphp.dev

A new app server and a library to embed PHP in Go.

* Easy to Dockerize
* Early Hints Support
* Worker mode for performance
* Real-time with the built-in Mercure hub
* Symfony integration (Laravel coming soon)

Kévin Dunglas

October 14, 2022
Tweet

More Decks by Kévin Dunglas

Other Decks in Programming

Transcript

  1. A modern app server for PHP
    https://frankenphp.dev

    View Slide

  2. ➔ PHP
    API Platform creator,
    Symfony maintainer
    ➔ GO
    Go core contributor, Mercure.rocks
    and Vulcain.rocks creator
    ➔ C
    PHP core contributor
    Kévin Dunglas:
    Polyglot Dev
    @dunglas

    View Slide

  3. 02
    03
    04
    01 FrankenPHP?!
    What’s next?
    Internals
    Features

    View Slide

  4. FrankenPHP
    A modern app server for PHP
    ➔ Built for containers
    ➔ Worker mode
    ➔ 103 Early Hints support
    ➔ Real-time support (Mercure module)
    ➔ Compatible with all existing PHP apps:
    ◆ progressive enhancement

    View Slide

  5. PHP and Containers

    View Slide

  6. Containers: Which SAPI?
    Server Application Programming
    Interface: interface between the PHP
    interpreter and web servers
    ➔ Apache module
    ➔ FPM (FastCGI Process Manager)
    ➔ CGI (Common Gateway Interface)
    ➔ NGINX Unit (not the NGINX
    you’re used to)
    ➔ …

    View Slide

  7. ➔ Simple
    ➔ Web server + PHP = 1 service
    ➔ Default solution for containers
    DRAWBACKS:
    ➔ Works only with Apache
    ➔ Less performant than FPM
    Apache Module

    View Slide

  8. FPM
    ➔ Most popular SAPI
    ➔ Supported by most web servers:
    Caddy, Symfony CLI, NGINX, Apache…
    DRAWBACKS:
    ➔ External service
    ➔ Require a UNIX or a TCP socket
    ➔ Hard to containerize

    View Slide

  9. © sergioska
    FPM and
    containers

    View Slide

  10. Can We Do
    Better?!

    View Slide

  11. ➔ Secure and fast
    ➔ Easy to configure
    ➔ Cloud native:
    API, hot config reloading…
    ➔ Automatic HTTPS
    ➔ HTTP/2, HTTP/3, Early Hints…
    ➔ Extensible with modules:
    Mercure, Vulcain, OAuth, OIDC…
    ➔ Prod ready
    ➔ Written in Go 😻
    Caddy: The New Kid on the Block

    View Slide

  12. ➔ Perfect for containers
    ◆ Just 1 service
    ◆ No external dependencies
    ➔ Built on top of Caddy
    ◆ All Caddy features and modules
    ◆ Benefits from Go features
    ◆ Extensible: in Go, in C, in PHP
    ➔ Prod, CI and dev
    FrankenPHP: Modern PHP App Server

    View Slide

  13. ➔ Standalone Go library
    ➔ Embed PHP in your Go programs
    ➔ New SAPI for Go net/http
    ◆ Caddy, Symfony CLI, Traefik, K8S…
    ◆ Your custom Go app
    ➔ Caddy module using the library
    ➔ Unique features
    The ❤ of FrankenPHP: A New SAPI For Go

    View Slide

  14. 02
    03
    04
    01 FrankenPHP?!
    Features
    What’s next?
    Internals

    View Slide

  15. ➔ Compatible with existing PHP apps!
    ➔ 1 service, 1 container image 😍
    ➔ Also works without Docker
    ➔ Entirely configurable
    ◆ Caddyfile
    ◆ php.ini
    ➔ Free software
    (as in free speech ✊, and free beer 🍺)
    FrankenPHP: At a Glance

    View Slide

  16. Getting Started

    View Slide

  17. Getting Started

    View Slide

  18. FrankenPHP Superpower: The Worker Mode
    ➔ Boot your application once
    ➔ Keep it in memory
    ➔ Process incoming requests without having to
    boot your app again
    ➔ Relies on goroutines and channels
    ➔ Compatible with Symfony Runtime and
    Laravel Octane (soon)
    ➔ Somewhat similar to RoadRunner
    ➔ Unlike RR, uses plain old superglobals

    View Slide

  19. Worker Script

    View Slide

  20. Starting the Worker Mode
    By default, one worker per CPU is started.

    View Slide

  21. Symfony App in Worker Mode

    View Slide

  22. FrankenPHP: Worker Benchmark 🧪
    ➔ Setup:
    ◆ Hello World Symfony app (prod mode)
    ◆ Caddy Web Server (HTTP/2)
    ◆ 3000 requests, 100 connected users
    ◆ Benchmark tool: K6
    ➔ Average request duration:
    ◆ FPM: 9.45ms
    ◆ FrankenPHP (no worker): 12.72ms
    ◆ FrankenPHP (worker): 2.53ms

    View Slide

  23. 103 Early
    Hints

    View Slide

  24. Typical
    Web Page
    © Google

    View Slide

  25. 103 Early
    Hints
    © Google

    View Slide

  26. Early Hints: Not Possible With PHP

    View Slide

  27. Early Hints: Possible With Go

    View Slide

  28. Early Hints: Supported by FrankenPHP ⚡

    View Slide

  29. 03
    01
    Features
    Internals
    02
    04
    FrankenPHP?!
    What’s next?

    View Slide

  30. ➔ PHP scripts are interpreted
    ➔ The PHP interpreter is written in C
    ➔ php-src uses Zend Engine
    ◆ compiler (with Just In Time)
    ◆ executor (Virtual Machine)
    ➔ SAPIs
    ◆ Pass input from the web server to
    the PHP engine
    ◆ Pass output from the the PHP engine
    to the web server
    PHP Internals: the Basics

    View Slide

  31. The embed SAPI

    View Slide

  32. PHP as a C Library
    ➔ PHP can be used by C programs as a
    library
    ◆ It’s how the Apache module works
    ➔ The embed SAPI eases the process for
    simple cases
    ➔ The library can be linked
    ◆ dynamically (.so)
    ◆ statically

    View Slide

  33. ➔ Go is a compiled language
    ➔ Go programs can call C code
    ➔ Go and C files can be compiled in a single
    program
    ➔ The resulting binary can be static!
    ➔ The native package to call C code is called
    cgo
    ➔ Using cgo we can embed PHP in Caddy,
    Symfony CLI and other Go programs!
    C? Go? Cgo!

    View Slide

  34. C function to execute a
    PHP script

    View Slide

  35. Call the function from Go!

    View Slide

  36. Tadam!

    View Slide

  37. ➔ Go is especially convenient to build servers
    and network apps
    ➔ net/http: native package to create HTTP
    clients and servers
    ➔ Production-grade:
    optimized and secure
    ➔ Native HTTP/2 (HTTP/3 with a 3rd party lib)
    ➔ Used by Caddy, Symfony CLI, Kubernetes,
    Traefik, Google, Cloudflare…
    net/http

    View Slide

  38. A Web Server in 5 LOC

    View Slide

  39. A PHP SAPI for Go net/http
    ➔ SAPI: bridge between a server and the PHP
    engine
    ➔ Use cgo to call PHP with data coming from
    Go’s HTTP messages
    ➔ Extract data from
    Go’s http.Request, pass it to PHP
    ➔ Write data generated by PHP using Go’s
    http.ResponseWriter

    View Slide

  40. The Idea

    View Slide

  41. FrankenPHP SAPI
    module struct

    View Slide

  42. Delegating to Go

    View Slide

  43. We Have a Thread Safety Problem!

    View Slide

  44. ➔ net/http is based on the flagship feature
    of Go: goroutines
    ➔ Goroutines are lightweight threads
    ➔ Goroutines are executed concurrently
    ➔ Goroutines can run in parallel on
    different CPUs
    ➔ Go provides user-friendly synchronization
    mechanisms (channels)
    Goroutines

    View Slide

  45. PHP Process-based Model (non-ZTS)
    1 PHP process handles only 1 request concurrently.
    To handle requests simultaneously,
    start new OS processes. Model of FPM and CLI.

    View Slide

  46. Thread-based model (ZTS)
    With ZTS (Zend Thread Safety), the PHP interpreter is
    isolated into a thread.

    View Slide

  47. Recompile PHP with --enable-zts and…

    View Slide

  48. ➔ Goroutines are lightweight threads: a mix of
    real parallelism (system threads) and
    asynchronous I/O
    ➔ Several goroutines share the same OS thread
    ➔ Goroutines are lighter and faster than OS
    threads…
    ➔ …but ZTS isn’t enough to ensure PHP
    memory safety 😱
    PHP must run in its own threads!
    Goroutines Aren’t OS Threads

    View Slide

  49. Taming the Beast 🐘 (php-src)

    View Slide

  50. 🤩

    View Slide

  51. No OPcache? 🤔

    View Slide

  52. SAPIs supported By OPCache…

    View Slide

  53. Patch coming!

    View Slide

  54. 03
    01
    What’s next?
    02
    04
    Features
    FrankenPHP?!
    Internals

    View Slide

  55. Available right now:
    frankenphp.dev
    github.com/dunglas/frankenphp

    View Slide

  56. ➔ 🧪 Still highly experimental!
    ➔ Fix the remaining segfaults issues
    ➔ Test, test and test again
    ➔ Add support to Laravel Octane
    ➔ Use it in Symfony CLI
    ➔ Add Windows support
    ➔ Contributions welcome!
    What’s next?!

    View Slide

  57. Try it,
    give it a star on GitHub.
    Thanks!
    frankenphp.dev
    @dunglas

    View Slide