All projects

Infrastructure · 2025

Agora

A fault-tolerant, sharded edge-network information retrieval engine built from scratch in Go — custom BM25 ranking, no Elasticsearch or Lucene.

GogRPCProtocol BuffersDockerBM25

Problem

Distributed search has to return useful ranked results even when individual shards are slow, unavailable, or recovering.

Why I built it

I built Agora to learn the mechanics hidden behind mature search systems: indexing, ranking, fan-out, partial failure, and top-k merging.

Architecture

  • Each edge worker holds an in-memory inverted index with posting lists; queries are tokenized and scored locally with configurable BM25 k1/b parameters.
  • The coordinator fans out SearchRequests concurrently (goroutines + WaitGroup) with a strict deadline, then merges partial top-K slices via a bounded min-heap.
  • Push heartbeats and TTL-based eviction keep the worker pool fresh; restarted nodes re-register automatically without manual config reload.

Implementation

  • Workers maintain custom in-memory inverted indexes and compute BM25 scores locally.
  • A Go coordinator issues bounded concurrent gRPC requests and merges shard results with a min-heap.
  • Heartbeat registration and TTL eviction let the cluster degrade and recover without a manual topology file.

Experiments

  • Worker processes can be killed during queries to observe partial-result semantics and registry eviction.
  • Race-detector and table-driven tests cover concurrent index reads and exact scoring behavior.

What I learned

  • Deadlines are part of a distributed system's product behavior, not just defensive plumbing.
  • Returning partial results can be more useful than turning every shard failure into a global error.

Next questions

  • How should shards be rebalanced as corpus size and query patterns change?
  • What ranking quality is lost when deadlines cut off slow shards?