1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# Example tephra-server configuration.
#
# Every value shown is the built-in default, so an empty file behaves identically to running
# with no config at all. Pass this file with `--config tephra.example.toml`. Any key can also
# be set from the environment as TEPHRA__<SECTION>__<KEY>, upper-cased, e.g.
# TEPHRA__WRITER__MAX_BATCH_BYTES=16777216. The command line only carries --bind, --data-dir,
# and --log, and those override whatever is set here.
# Address the TCP listener binds.
= "127.0.0.1:9000"
# Directory holding the log (and index) segment files.
= "tephra-data"
# Tracing filter. Omit to fall back to TEPHRA_LOG, then to "info".
# log = "tephra=debug"
[]
# Total size of each segment file in bytes, including its header.
= 268435456 # 256 MiB
[]
# Bounded request-queue depth. When full, an append blocks (backpressure). Keep it well above
# max_batch_records or it caps the achievable batch size.
= 16384
# Most requests folded into one group-committed batch. The main throughput-vs-latency dial.
= 2048
# Byte budget for one batch. Clamped down to the segment capacity at startup, so it can never
# exceed a shrunk segment.size.
= 8388608 # 8 MiB
# Recent-position window width for the durable tips map (a memory bound only).
= 1000000
# Resolve the append-condition durable arm with the log scan instead of the index existence
# check. An operational escape hatch: the log is the source of truth, so the scan is always
# safe, just slower.
= false
[]
# The planner's K: the index is chosen only when the post-pruning range is at least scan_bias
# times the estimated result count, so larger values bias toward scanning at the margin. This
# only changes which correct path runs, never the answer.
= 4
[]
# Largest single frame accepted or produced, in bytes.
= 16777216 # 16 MiB
[]
# A streamed read (or subscription) is flushed as a frame once it holds this many events.
= 1024
# ...or once its buffered events reach this many bytes.
= 524288 # 512 KiB
# Reusable worker threads in the shared read pool. 0 = auto (one per logical CPU). Warm reads are
# short and CPU-bound, so one per core reaches the read-parallelism ceiling; raise it for
# slow-client streaming-read workloads.
= 0
[]
# How often an idle subscription's blocking wait wakes to re-check server shutdown, in
# milliseconds. Keeps a subscription with no events flowing responsive to shutdown without a
# heartbeat frame.
= 250
# Most live subscriptions a single connection may hold at once; one over the limit is rejected.
= 64
[]
# Most appends + reads a single connection may have in flight at once. Once reached, the reader
# blocks (backpressure) until one finishes, bounding read threads and the append-reply backlog.
= 256
# Depth of a connection's outbound bulk frame queue (read/subscription frames buffered before
# backpressure). Small control frames (acks, stats, errors) use a separate priority lane.
= 256
[]
# Most connections served at once, across all clients. Each connection costs a few OS threads, so
# this caps total server resources independent of any per-connection budget. A connection over the
# cap is closed immediately, before a request is read. 0 = unlimited (an explicit opt-out).
= 1024
[]
# TCP keepalive idle time before the first probe on an accepted connection, in seconds. The OS
# default (~2h on Linux) is too long to reap a silently-dead subscription promptly.
= 60
# Interval between TCP keepalive probes once they start, in seconds.
= 15
[]
# Seconds a partial request frame may take to finish once its first byte arrives, before the
# connection is reaped. Defends against a slow-loris trickle (which a per-read socket timeout misses,
# since it resets on every byte). Only ever touches a partial frame in flight, so a connection idling
# silently at a frame boundary is unaffected. 0 disables it.
= 30
# Seconds a freshly accepted connection may take to send its first complete frame before being
# reaped. 0 disables it (the default). Off by default because a pooling client (such as the async
# client's idle bulk sockets) legitimately opens a connection and sends nothing until its first read;
# enable it only where clients do not hold connections open before using them.
= 0
# Seconds a connection with no request in flight and no live subscription may sit idle before being
# reaped. 0 disables it (the default), for the same pooling reason as handshake_secs. Subscriptions
# and in-flight requests count as activity, so a long-lived subscription is never reaped.
= 0
[]
# Address for the Prometheus /metrics HTTP endpoint, on its own port. Omitted (disabled) by
# default; set it to expose metrics, e.g. for scraping from an internal network only.
# bind = "127.0.0.1:9100"
[]
# Server-authenticated TLS. Set both to a PEM certificate chain and its private key to serve TLS;
# omit both (the default) to serve plaintext. Setting only one is a startup error.
# cert = "server.crt"
# key = "server.key"
[]
# Bearer-token authentication. With no tokens (the default) the server is open. Add one table per
# accepted token; any of them authenticates a connection in its opening Hello. List several to
# rotate without downtime: add the new token, roll clients over, then remove the old.
# [[auth.tokens]]
# token = "a-long-random-secret"
# [[auth.tokens]]
# token = "the-next-secret-during-rotation"
#
# Tokens are secrets, so by default they require TLS. Set this to permit them over a plaintext
# listener, for a deployment that terminates TLS at a proxy or mesh in front of tephra.
# allow_insecure = false