Berserk Docs

Storage

Local disks of Berserk services — the query segment cache, working storage, encryption at rest and node scheduling

Berserk services use local disk for caching and working storage. S3 holds all segment data (Dependencies), so losing a local disk means a cold cache, not data loss.

Query Service

The query service keeps a local segment cache, so it does not fetch segments from S3 on every query. Use a local SSD or NVMe disk. The cache is mounted at /segment_cache.

The cache is partitioned across query nodes rather than replicated — each segment has one owning node that caches and scans it. Segment Placement covers how ownership is decided and what adding or removing a node does.

Size the cache for the days of data you want available for fast searches: ingest per day / compression x cache days, with compression around 10x depending on your data. One TB/day of ingest with a 7-day cache is about 700 GB. With multiple query nodes, each node holds its own share of that total. Hardware Sizing has the full model and a calculator.

Ephemeral node storage. The cache is lost when the pod is rescheduled.

values.yaml
query:
  cache:
    enabled: true
    persistent: false
    size: "128Gi"

A local NVMe disk, through hostPath or emptyDir, gives the lowest query latency.

Other Services

The janitor, nursery and ingest services use local disk for working storage: merge scratch space and baby segments. Node storage is fast enough.

All three use emptyDir volumes, with no storage class or provisioning. The nursery's working directory also holds its node identity. The volume belongs to the pod, so a restarted container keeps its identity and cache. Replacing the pod (a deploy, an eviction, a node failure) loses the disk: the nursery mints a new identity, its stream groups fail over in about 30 seconds, and it rebuilds its baby-segment cache from object storage.

values.yaml
janitor:
  cache:
    size: "30Gi" # merge scratch: at least 6x the meta max_segment_size (5 GB default); a hard cap

nursery:
  workingDir:
    size: "50Gi" # baby segment buffer + node identity (emptyDir size limit)

# ingest uses a small emptyDir with no size limit by default

With a local-path storage class, a PVC pins the nursery pod to the node that holds the volume. If that node or volume is lost, the nursery mints a new identity on the empty disk and its stream groups fail over, with no manual step.

Encryption at rest

The local volumes above hold unencrypted copies of your telemetry: the query segment cache, the nursery's baby segments and the janitor's merge scratch. Berserk does not encrypt them; encrypt them below the filesystem:

  • Cloud volumes: use your provider's volume encryption, through an encrypted storageClass for the query PVC and encrypted node disks for emptyDir.
  • Bare metal and hostPath: put the cache directory and the kubelet's storage on a dm-crypt/LUKS device.

Berserk's sparse files and hole punching work on an encrypted filesystem as on any other.

Node Scheduling

nodeSelector, tolerations and affinity choose the nodes Berserk services run on. Each can be set globally or per service; a per-service value wins.

Global defaults

For every service:

values.yaml
global:
  nodeSelector:
    disktype: ssd
  tolerations:
    - key: "dedicated"
      operator: "Equal"
      value: "berserk"
      effect: "NoSchedule"
  affinity: {}

Per-service overrides

For one service:

values.yaml
query:
  nodeSelector:
    kubernetes.io/hostname: my-dedicated-node

Pinning to a specific node

By hostname:

values.yaml
query:
  nodeSelector:
    kubernetes.io/hostname: my-node-name
nursery:
  nodeSelector:
    kubernetes.io/hostname: my-node-name

On this page