dskit
A modular Go toolkit of production-hardened building blocks for distributed systems, extracted from Grafana Labs' own database projects.
Repository Health
Technical Analysis
dskit is a collection of Go packages that Grafana Labs pulled out of its own distributed systems — Mimir, Loki, Tempo, and Pyroscope — so that the plumbing every horizontally-scaled service needs didn’t have to be rewritten four times over. Instead of a single opinionated framework, it is a grab-bag of narrowly-scoped packages: a consistent-hashing ring for sharding work across nodes, a common key-value abstraction with Consul, Etcd, and Memberlist backends, a Guava-style service lifecycle model for coordinating startup and shutdown across components, gRPC client/server middleware for metrics and logging, exponential backoff, request hedging, and tenant/multi-tenancy helpers.
Because every package originated as internal infrastructure for real, high-throughput systems rather than a green-field API design exercise, the abstractions are shaped by what actually broke in production — retry storms, split-brain ring state, noisy gRPC logging — rather than by what looked clean on a whiteboard. Teams building their own sharded, multi-tenant, or highly-available Go services can pull in just the ring, just the KV client, or just the service manager without adopting a whole framework.
The project is maintained as living infrastructure: it ships from the same commit history that powers Grafana’s production databases, uses conventional-commit PR titles instead of a hand-written changelog, and tracks the two latest Go minor releases for compatibility.
What You Get
- Consistent-hashing ring (
ring/) — a distributed hash ring implementation for sharding ownership of keys/tokens across a fleet of nodes, with heartbeat-based membership and configurable replication factor. - Pluggable KV store client (
kv/) — a singleClientinterface with Consul, Etcd, and Memberlist implementations plus amultiwrapper for migrating between backends without changing call sites. - Service lifecycle model (
services/) — a Guava-inspiredServiceinterface (New → Starting → Running → Stopping → Terminated/Failed) plus aManagerfor coordinating groups of dependent services. - gRPC client/server middleware (
grpcclient/,grpcutil/,middleware/) — reusable interceptors for metrics, structured logging, tracing propagation, and HTTP-over-gRPC error mapping (httpgrpc/). - Resilience primitives (
backoff/,hedging/,limiter/,gate/) — exponential backoff for retries, request hedging to cut tail latency, and concurrency/rate limiting helpers. - Multi-tenancy helpers (
tenant/,user/) — extracting and propagating tenant/org IDs through request contexts and gRPC metadata, the same mechanism Mimir and Loki use for tenant isolation.
Common Use Cases
- Building a sharded microservice — use
ring/to distribute ownership of partitions, shards, or tenants across a fleet of stateless workers with automatic rebalancing on scale-up/down. - Coordinating service startup order — use
services/to model a component (a cache warmer, a background compactor) as aServiceand let aManagersequence dependent starts/stops instead of hand-rolling goroutine coordination. - Swapping coordination backends — use
kv/to write ring or config-watching code once against theClientinterface, then choose Consul, Etcd, or gossip-based Memberlist at deploy time via config. - Instrumenting gRPC services — drop in
grpcclient/middlewareinterceptors to get consistent Prometheus metrics and structured logs across every gRPC call without writing interceptor boilerplate per service. - Multi-tenant SaaS backends — use
tenant/to extract a tenant ID from inbound requests and propagate it through internal RPCs, mirroring how Grafana Cloud isolates tenant data in Mimir/Loki.
Under The Hood
Architecture
The repository is organized as roughly forty independent, single-purpose packages (ring/, kv/, services/, grpcclient/, tenant/, etc.) rather than a layered framework — there is no central entry point or app object; a consumer imports only the packages it needs. The one cross-cutting abstraction is the services.Service state machine (services/basic_service.go), which several other packages (the ring, KV clients) build on to expose consistent start/stop/health semantics. The kv/client.go Config/StoreConfig pair follows a composition pattern: a single Client interface is backed by swappable consul, etcd, or memberlist implementations selected at runtime via a store config string, so call sites never branch on backend. Because packages are deliberately decoupled, changing one (e.g. the ring’s token-generation strategy) has a narrow, auditable blast radius rather than rippling through a shared core.
Tech Stack
Pure Go (99% of the codebase, go.mod requires Go 1.25+ with a 1.27 toolchain), with no runtime beyond the standard library and its dependencies: go-kit/log for structured logging, prometheus/client_golang for metrics, hashicorp/consul, go.etcd.io/etcd/client, and hashicorp/memberlist for the three KV backends, gogo/protobuf and google.golang.org/grpc for RPC, and OpenTelemetry/Jaeger packages for tracing. Build and release automation runs through a Makefile and GitHub Actions (test-build.yml), with Renovate configured for automated dependency updates.
Code Quality
Test coverage is extensive — roughly one test file per implementation file across the tree (over 150 _test.go files), using the standard library testing package alongside stretchr/testify for assertions and mocks. Core packages like services/ include both unit tests and runnable examples (services/example_test.go). Linting is enforced via golangci-lint (.golangci.yml) with revive, misspell, and loggercheck enabled alongside gofmt/goimports formatters and a scoped errcheck exclusion list, and CI runs on every push and pull request via test-build.yml, with a dedicated flaky-test-detection workflow that reruns the suite twenty times on demand. Error handling favors explicit returned errors over panics, consistent with idiomatic Go and the codebase’s origin as production infrastructure.
API Design
The public surface favors small, composable interfaces over large all-in-one structs — kv.Client, services.Service, and ring.ReadRing are each narrow enough to mock or reimplement independently. Constructors follow a consistent New* + Config + RegisterFlagsWithPrefix pattern throughout (seen in kv/client.go and mirrored in the ring and gRPC packages), so configuring any subsystem from a CLI flag set feels the same regardless of which package it comes from. Documentation is comment-driven (package-level doc comments plus per-function GoDoc) rather than a separate docs site, which keeps API reference accurate but raises the initial learning curve for newcomers who need to read source alongside the README to understand how packages compose.
Used by 2 apps in this directory
Grafana
Monitoring · Analytics
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.
Pyroscope
Monitoring · Devops · Developer Tools
An open-source, horizontally scalable continuous profiling platform that pinpoints CPU, memory, and I/O bottlenecks down to the exact line of code, built by Grafana Labs alongside Loki, Tempo, and Mimir.