Pinboard: A Free, Self-Hosted APM Dashboard That Refused to Die
Zabbix tells you the server is on fire. Who tells you what lit the match?Every ops team has infrast 2026-7-21 11:40:10 Author: hackernoon.com(查看原文) 阅读量:1 收藏

Zabbix tells you the server is on fire. Who tells you what lit the match?

Every ops team has infrastructure monitoring — CPU, disk, load average, ping. Ours (Zabbix) has served faithfully for years. But when a client calls saying "the site got slow after lunch," infrastructure graphs give you a shrug: CPU is fine, memory is fine, and something is still slow.

The answer to "which page, which code path, since when" lives one layer up — in application performance monitoring. The SaaS market will happily sell you that layer: Datadog APM starts at roughly $31–40 per host per month, New Relic meters you by data ingested and per seat. For a company running dozens of client sites on its own servers, that's a five-figure annual bill — plus a subtle catch: your production traffic metadata now lives in someone else's cloud, which for many European and enterprise clients is a compliance conversation you'd rather not start.

At Intaro, where I lead backend development as deputy head, we've had that layer for over a decade without paying a cent for it: Pinboard, an open-source dashboard for Pinba, born in our own repository in 2013. It sits next to Zabbix, watching dozens of production sites live. When something degrades, Zabbix says where, Pinboard says what exactly — down to the URL, the timer group, and the moment it started.

What Pinboard adds: a memory

Parts 1 and 2 of this series left us with a superpower and a flaw. The Pinba engine aggregates every request from every PHP server in real time, queryable by SQL — but it holds only a sliding 15-minute window in RAM. Brilliant for "what's happening now," useless for "compare with last Tuesday."

Pinboard's core is one elegantly boring idea: every 15 minutes, photograph the live data and file the photos. A scheduled aggregate command reads Pinba's in-memory views and writes timestamped snapshots into ordinary InnoDB tables (the ipm_* family) that live as long as you want — a month by default:

  • ipm_report_by_server_name, ipm_report_by_hostname, ipm_report_by_hostname_and_server — traffic, request time, CPU and memory per site, per host, and per site-on-host;
  • ipm_report_2_by_hostname_and_server — request-time percentiles (p90/p95/p99) history, the honest metric that averages hide;
  • ipm_req_time_details, ipm_mem_peak_usage_details, ipm_cpu_usage_details — the top-10 slowest, most memory-hungry and most CPU-hungry pages of each interval, with their exact URLs;
  • ipm_status_details — pages that returned HTTP errors, so 5xx spikes come with names attached;
  • ipm_timer and ipm_tag_info — history for your custom timers and tags from Part 2.

On top of that sits a web UI: dashboards per site with request-time and traffic graphs, percentile charts, error pages, slow-page drill-downs — and e-mail alerts when error pages appear or when p90/p95 suddenly degrades between snapshots (with per-site thresholds when one project is allowed to be slower than another).

My favorite technical detail in the whole stack lives at the boundary between Pinboard and the engine. How do you ask Pinba for "request-time percentiles per virtual host"? You don't write that query. You create a table:

CREATE TABLE `ipm_pinba_report_by_server_90_95_99` (
  req_count INT,
  req_time_total FLOAT,
  ru_utime_total FLOAT,
  -- ...
  p90 FLOAT, p95 FLOAT, p99 FLOAT
) ENGINE=PINBA COMMENT='report2:::90,95,99';

The report definition is smuggled inside the table comment. The engine parses it, and from that moment maintains this aggregation incrementally in RAM as UDP packets arrive — histograms and all. Selecting from the table is a lookup, not a computation. Pinboard's migrations create a set of these virtual tables (per-server, per-host, and tag-based reports like tagN_info:group,__server_name::90,95,99), and the aggregator simply harvests them every 15 minutes. The heavy lifting happens where the data already is; the dashboard stays a thin, cheap reader. That's the architecture in one sentence: the monitored sites do almost nothing, the engine does the math in memory, Pinboard just remembers.

The load on your production fleet? One UDP packet per request. The extension doesn't add measurable latency, and the sites can't even tell whether the dashboard exists. This runs on real client sites, all day, every day.

A project frozen in 2013's amber

Pinboard was created at Intaro by Ilyas Salikhov and open-sourced in April 2013. It found its audience — 475 GitHub stars, 89 forks, community patches from a dozen contributors. It was also, unmistakably, a 2013 artifact: PHP 5.3, the Silex microframework, Twig 1, Swiftmailer.

Then history repeated the engine's fate one layer up. Active development faded after 2016; the last commit landed in 2018 — the same year Silex was officially discontinued. The project didn't just age, it fossilized: you couldn't legally composer install it on a modern server without a séance. And since upstream Pinba was itself stuck on MySQL 5.x, the whole stack quietly drifted toward "runs only on servers we're afraid to touch."

Yet inside the company it kept running, and kept being useful — a decade-old dashboard still catching real regressions on real sites every week. Tools like that earn a rescue.

The 2026 rewrite

Having revived the engine and the extension (Parts 1 and 2), I picked up Pinboard in 2026. This wasn't a port — it was a rewrite standing on the old project's shoulders: same proven data model and reports, new everything else.

  • Backend: Symfony 8, PHP 8.4/8.5, Doctrine DBAL 4 — with PHPStan at level 10, the strictest it goes. A codebase last typed in the PHP 5 era now passes maximum static analysis.
  • Frontend: rebuilt on Webpack Encore with pnpm — modern assets instead of 2013-vintage jQuery soup.
  • Operations: a Docker Compose stack — nginx, PHP-FPM, a separate cron container for aggregation, and the Pinba engine itself (the MySQL 8.4 LTS / MariaDB fork from Part 1). One .env, one docker compose up -d.
  • Trust infrastructure: CI with tests and coverage, CodeQL security scanning, Dependabot, automated releases. Thirty accumulated dependency advisories were flushed out in one sweep.
  • The rewrite also fixed long-standing subtleties the old code carried for years — stale aggregation locks after crashes, a tag-history cleanup bug, per-user server access filtering.

The project lives where it always did — github.com/intaro/pinboard, in Intaro's open repository under the MIT license — and the Docker image is pulled about 700 times a month.

The whole stack, one command, zero invoices

Step back and look at what these three parts add up to. A PHP extension that instruments production with two lines of config. A database engine that aggregates the entire farm in RAM with SQL on top. A dashboard that keeps history, draws graphs and sends alerts. All open source, all self-hosted, all maintained again as of 2026 — and the running costs are your own hardware plus exactly zero license fees, for any number of hosts, with your traffic data never leaving your network.

git clone https://github.com/intaro/pinboard && cd pinboard
cp .env.public.example .env   # set APP_SECRET and passwords
docker compose -f docker-compose.public.yml up -d

Point pinba.server in your PHP config at the stack, wait one 15-minute aggregation cycle, and your first production dashboard appears.

Thirteen years after its first commit, Pinboard is doing what it was built for — quietly telling developers which page lit the match. Some tools don't need reinventing. They need someone who refuses to let them die.


文章来源: https://hackernoon.com/pinboard-a-free-self-hosted-apm-dashboard-that-refused-to-die?source=rss
如有侵权请联系:admin#unsafe.sh