Skip to content

perfcached 0.6.0

Choose a tag to compare

@Lt-Flash Lt-Flash released this 11 Oct 15:01
· 1 commit to master since this release

perfcached - found fast, kept safe

A multithreaded, self-clustering cache for Linux, with its own encrypted protocols and a Redis-compatible door. New here? Start with the README.

This page covers 0.6.0. 0.5.7.1, 0.5.8 and 0.5.9 have pages of their own without packages: coming from 0.5.6.6, the last release with packages, read those too. The ChangeLog has the detail.

A rolling restart. From 0.4.5, 0.6.0 joins a fleet one node at a time; use SET IFEQ/IFNE and DELEX once every node runs 0.5.0 or later. A config that uses [mail] (0.5.9) is refused by an older release: to roll back, put the old config back with the old binary.

io_uring by default

  • The workers receive into provided buffers, with one multishot receive per connection, and send their replies with the turn's single io_uring_enter(): no read() and no write() a request.
  • At start the daemon tries io_uring for real and falls back to epoll where the kernel (before 6.0), kernel.io_uring_disabled or a container's seccomp profile refuses it. The reason is logged and shown in /stats (io.backend), and perfcached -C says so beforehand. [daemon] io = epoll forces epoll.
  • On 16-vCPU VMs with multiqueue NICs, against epoll: 41% more RESP and 63% more native requests a second one at a time, 12% more pipelined, and a third less CPU a request.
  • On epoll, a short read ends a wakeup's reads: one read() a request instead of two.
  • PRODUCTION.md section 7: one NIC queue per CPU on the nodes and the clients, irqbalance, and the daemon unpinned.

A fast writer with a slow reader is throttled, not closed

  • At 4 MB of replies unread, a client's further requests wait and its socket is not read, until the backlog drains below 1 MB. One that reads nothing for output_stall_s (default 30) meanwhile is closed as a slow consumer.
  • The log says throttling client <ip:port> the first time, and the disconnect line counts the throttles. /stats (clients.output) and /metrics count them. A slow consumer's close now says so; it used to read "peer closed".

Busy polling, opt-in

  • busy_poll_us and busy_poll_prefer, per worker (kernel 6.9+), off by default. Its effect on perfcached is not measured yet: measure it on your own NIC before you keep it.

Stats

  • /stats io and /metrics count the system calls against the work they moved: waits, reads and writes, io_uring enters, completions, receives and sends, and UDP datagrams a call. perfcached_io_worker_ops_total has each worker's I/O.

Packages

Debian 12 and 13, Ubuntu 20.04 and 24.04, amd64:

  • perfcached: the clustered daemon, every cluster mode.
  • perfcached-standalone: the single-node edition, built from the same tree without the cluster code. A [cluster] section in its config is refused rather than ignored.
  • libperfd0: the client library, libperfd.so.0.
  • libperfd-dev: its header, static archive, libperfd.so link and libperfd.pc. A program built against it links the shared library by default.

The two daemon packages install the same files and replace each other. They do not need libperfd0: install it, or libperfd-dev, for your own programs.

sudo apt install ./perfcached_0.6.0-1+deb13_amd64.deb
sudo apt install ./libperfd0_0.6.0-1+deb13_amd64.deb ./libperfd-dev_0.6.0-1+deb13_amd64.deb   # to build against libperfd

Each distribution's packages were built on that distribution: Debian 13 (gcc 14.2), Debian 12 (gcc 12.2, in a container), Ubuntu 20.04 (gcc 9.4) and Ubuntu 24.04 (gcc 13.3). Every build ran noisetest, the selftest and a deliberately broken-lock build that must fail. Each set was then checked in a clean container of its distribution:

  • the version and revision perfcached -V reports, and the systemd unit;
  • the daemon starting and answering ping, set and get over its encrypted native door from perfcli, on epoll under the container's default seccomp profile and on io_uring without it;
  • a program built against libperfd-dev through pkg-config, linking libperfd.so.0;
  • the shipped config passing perfcached -C, a [cluster] section refused by the standalone edition, and the two editions replacing each other;
  • an upgrade over the published 0.5.6.6 perfcached package.

Alpine 3.24 (musl), x86_64, both editions, as tarballs of the tree's make install layout: binaries in usr/bin, libperfd (shared and static) with perfd.h and libperfd.pc, the example config, and the docs. No systemd unit or OpenRC service is shipped; run the daemon under your own supervisor.

apk add libsodium libcurl
tar -xzf perfcached-0.6.0-alpine3.24-x86_64.tar.gz
cp -a perfcached-0.6.0-alpine3.24-x86_64/usr perfcached-0.6.0-alpine3.24-x86_64/etc /

Built with gcc 15.2 in a clean Alpine container behind the same three gates, then checked in a second clean container: -V and the musl interpreter, the round trip on epoll and on io_uring, the libperfd program, the shipped config and the [cluster] refusal.

libperfd for Alpine: libperfd and libperfd-dev as .apk, signed with the perfcached release key. Trust the key once (its public half is attached here and in contrib/alpine/keys), then install:

cp yury@kfi.net.au-6aca2bb6.rsa.pub /etc/apk/keys/
apk add ./libperfd-0.6.0-r0.apk ./libperfd-dev-0.6.0-r0.apk

Checked in a clean container that trusts only that key: both install, pkg-config reports 0.6.0, a program links the shared or the static library and pings a 0.6.0 daemon, and without the key apk refuses them.

SHA256SUMS covers every file on this page.

Known

  • In a container under Docker's or podman's default seccomp profile, io_uring is refused and the daemon runs on epoll. perfcached -C and the log say which.
  • Busy polling's effect is not measured yet.
  • No lists, sets, sorted sets or streams yet. Keys hold strings, counters, JSON documents or hashes (a hash is one value, under 58,000 bytes).
  • discovery = unicast (clouds, Kubernetes) is tested in lab network namespaces that drop IP fragments and block UDP, not yet in a real cloud deployment. spread mode has not yet carried production traffic.
  • In eager mode a delete made on one side of a network partition can be undone when the partition heals.