Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

  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
  3. 02 03 04 01 FrankenPHP?! What’s next? Internals Features

  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
  5. PHP and Containers

  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) ➔ …
  7. ➔ Simple ➔ Web server + PHP = 1 service

    ➔ Default solution for containers DRAWBACKS: ➔ Works only with Apache ➔ Less performant than FPM Apache Module
  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
  9. © sergioska FPM and containers

  10. Can We Do Better?!

  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
  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
  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
  14. 02 03 04 01 FrankenPHP?! Features What’s next? Internals

  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
  16. Getting Started

  17. Getting Started

  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
  19. Worker Script

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

    is started.
  21. Symfony App in Worker Mode

  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
  23. 103 Early Hints

  24. Typical Web Page © Google

  25. 103 Early Hints © Google

  26. Early Hints: Not Possible With PHP

  27. Early Hints: Possible With Go

  28. Early Hints: Supported by FrankenPHP ⚡

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

  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
  31. The embed SAPI

  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
  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!
  34. C function to execute a PHP script

  35. Call the function from Go!

  36. Tadam!

  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
  38. A Web Server in 5 LOC

  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
  40. The Idea

  41. FrankenPHP SAPI module struct

  42. Delegating to Go

  43. We Have a Thread Safety Problem!

  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
  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.
  46. Thread-based model (ZTS) With ZTS (Zend Thread Safety), the PHP

    interpreter is isolated into a thread.
  47. Recompile PHP with --enable-zts and…

  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
  49. Taming the Beast 🐘 (php-src)

  50. 🤩

  51. No OPcache? 🤔

  52. SAPIs supported By OPCache…

  53. Patch coming!

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

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

  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?!
  57. Try it, give it a star on GitHub. Thanks! frankenphp.dev

    @dunglas