A configuration server for shared settings

One JSON document.
Every service reads it.

Clients read and write paths such as product.name over HTTP or a line-based TCP protocol. Writes go to an append-only file, and several nodes can run as a Raft cluster.

$ docker run -p 23456:23456 shonhen/simpleconf
1.02M
HTTP GET/s at 200 connections
16.5M
TCP GET/s, 64 commands pipelined
10 ns
keyed read, whatever the document size
3
fsync modes, from always to no

Features

For settings that are read often
and changed occasionally.

Feature flags, endpoints, limits. One binary, MIT licensed.

  • Key paths

    Read and write paths such as friends.0.last. Over TCP, reads also take gjson queries such as friends.#(age>45)#.first.

  • HTTP and TCP

    A plain HTTP API, and a line-based TCP protocol that answers pipelined commands in fewer writes.

  • Append-only file

    A background writer batches records. You choose when it fsyncs: always, everysec or no.

  • Raft cluster

    Writes are committed through the leader. Followers pass writes on to it over the Raft port.

  • Peers mode

    A simpler option kept for existing deployments: each node queues its writes and sends them to the others.

  • Fails loudly

    When the disk breaks, writes are refused or the server exits, as Redis and PostgreSQL do.

Performance

1.02M GET/s over HTTP.
16.5M over pipelined TCP.

Requests per second for one key, wrk -t4 -c200, every server on the same machine. Higher is better.

HTTP requests per second for one key, wrk -t4 -c200
OperationServerRequests per second
GETsimpleconf1.02M
Consul 1.21162k
etcd 3.644k
PUTsimpleconf674k
Consul 1.2146k
etcd 3.633k

simpleconf fsyncs once a second by default; etcd and Consul fsync every write before replying, so these gaps overstate the difference in code. Setup, Valkey results and caveats: docs/benchmarks.md.

Durability

You choose when it fsyncs.

db.fsyncSurvives kill -9Survives power lossCost
alwayswrites wait for the fsync
everysec (default)up to 1s of writes lostnegligible
nolost until the OS flushesnone

With Raft, raft.fsync decides instead: by default a write is acknowledged once a majority of nodes have fsynced it.

Get started

Up in one command.

$ docker run -p 23456:23456 -v simpleconf-data:/data shonhen/simpleconf

Data lives in the /data volume. linux/amd64 and linux/arm64.

Or talk to it over TCP

+product.name
"Demo"
+OK
=product.name
$6
"Demo"
TCP protocol

When something else fits better

Use etcd or Consul if you need:

  • Watches on keys
  • Per-key access control or TLS
  • Data that does not comfortably fit in memory

Start with one node. Add Raft when you need it.