Luther Monson, Staff Software Engineer at SUSE

Luther Monson

Go by way of PHP · Containers · VMs · Windows · Kubernetes

P99 From 280 ms to 58 ms by Making the Queue Fair

ePHPm had the best throughput in a Laravel runtime comparison and the worst tail of the fast group. The cause was a bounded channel that let new requests cut in line.

9-Minute Read

Bar chart of P50, P75, P90 and P99 latency for FIFO versus barging admission in ePHPm worker mode

A third-party Laravel runtime comparison put ePHPm’s worker mode at the top on throughput. It was about 19% ahead of FrankenPHP on /api/static. It was also at the bottom of the fast group on tail latency, with a P99 of 157 ms against FrankenPHP’s 57 ms. Best throughput plus the fattest tail is a shape worth chasing, because fast execution can’t produce it. Making requests faster lowers the mean and the tail. Only waiting can pull them apart. Specifically, unfair waiting.

Stop Running PHP on tokio's spawn_blocking - Own Your Thread Pool

Why ePHPm moved PHP execution off tokio's generic blocking pool onto threads it owns. How the switch rolled out behind a knob and what it did to memory, throughput and overload.

10-Minute Read

Bar chart of server RSS at 32, 128 and 512 concurrent clients: spawn_blocking grows with concurrency, the owned pool stays flat

For most of its life, ePHPm ran every PHP request on tokio’s spawn_blocking pool. It works. It passes tests and it serves benchmarks fine. It’s the first thing anybody reaches for when they need to call blocking code from async Rust. It’s also quietly wrong for a language runtime. The problems only show up under overload or after a crash. Over the last three weeks it got replaced with a pool of OS threads that ePHPm owns. That pool shipped first behind a config flag, then as…

PHP Signal Safety - The Init Ordering Bug Nobody Warns You About

Embedding PHP in a multithreaded server means PHP's timeout signals can land on any thread. How ePHPm got that under control.

11-Minute Read

Thread timeline: the main thread installs PHP's signal handlers during php_embed_init, a PHP thread later arms ITIMER_PROF, and SIGPROF is delivered to a tokio worker that has no PHP state

Last week I wrote about why ePHPm embeds PHP from Rust and promised the signal bug its own post. Here it is. It’s the kind of bug where the fix is about ten lines and the explanation is the whole post. Nothing in PHP’s embed documentation (there’s barely any) tells you that initializing PHP has process-wide side effects. Those side effects assume PHP is the only thing in the process.

Recent Posts

Categories

About

Luther is a 20+ year software veteran specializing in backend APIs and architecting products. Employed at SUSE as the Team Lead for the Containers on Windows Team working on Rancher + Kubernetes