No description
Find a file
jedarden 690cefe04e P4.2 Node addition: dual-write + paginated shard migration
Implement plan §2 "Adding a node to an existing group":

1. Admin API endpoints now use Rebalancer methods:
   - POST /_miroir/nodes → Rebalancer.add_node()
   - POST /_miroir/nodes/{id}/drain → Rebalancer.drain_node()
   - DELETE /_miroir/nodes/{id} → Rebalancer.remove_node()

2. Node addition flow:
   - Mark node as `joining`
   - Recompute assignments → affected_shards where new node enters top-RF
   - Dual-write: writes go to both old owner and new node
   - Background migration via _miroir_shard filter (paginated)
   - Mark `active`; stop dual-write
   - Delete migrated shard from old node

3. Integration tests (p42_node_addition.rs):
   - 3→4 node migration with 10K docs
   - Chaos: writes during migration caught by dual-write
   - Performance: ≤ total_docs/(Ng+1) × 1.1 docs moved
   - Log inspection: old node not queried after migration
   - Pagination verification with limit/offset
   - Dual-write verification

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:15:35 -04:00
.beads Phase 3: Final verification and completion note 2026-05-05 07:40:12 -04:00
.cargo Multi-stage Dockerfile with musl cross-compilation and .dockerignore 2026-04-19 13:47:45 -04:00
.github P8.6: Release mechanics — bump script, release-ready check, PR template, Argo CIs 2026-04-19 09:54:26 -04:00
benches P12.OP4: Implement dfs_query_then_fetch for cross-shard comparability 2026-04-19 03:43:10 -04:00
charts/miroir P3: Add Helm schema validation - Redis requires replicas > 1 2026-05-02 18:01:32 -04:00
crates P4.2 Node addition: dual-write + paginated shard migration 2026-05-08 15:15:35 -04:00
dashboards P7.3: Add §13.1 resharding row to Grafana dashboard, fix y-coordinate overlaps 2026-04-19 13:18:13 -04:00
docs P3: Complete Phase 3 — Task Registry + Persistence (SQLite + Redis) 2026-05-02 16:52:25 -04:00
k8s P12: close Phase 12 epic — all 6 open problems triaged and documented 2026-04-24 19:14:23 -04:00
notes Add Phase 4.1 verification summary (miroir-mkk.1) 2026-05-05 10:54:18 -04:00
scripts P8.6: Release mechanics — bump script, release-ready check, PR template, Argo CIs 2026-04-19 09:54:26 -04:00
tests/benches/score-comparability P2.2: Implement write path with primary key validation, shard injection, and two-rule quorum 2026-04-19 06:48:30 -04:00
.dockerignore Multi-stage Dockerfile with musl cross-compilation and .dockerignore 2026-04-19 13:47:45 -04:00
.editorconfig Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00
.gitignore P8: Add optional OpenTelemetry tracing deps, fix subscriber init, clean up .gitignore 2026-04-19 13:24:24 -04:00
.needle-predispatch-sha Phase 3: Final verification and completion note 2026-05-05 07:40:12 -04:00
1 P7.5.a: Request ID middleware + X-Request-Id response header 2026-04-21 08:01:30 -04:00
Cargo.lock Phase 3: Task Registry + Persistence (SQLite schema, Redis mirror) 2026-05-03 20:39:58 -04:00
Cargo.toml P12.OP4: Implement dfs_query_then_fetch for cross-shard comparability 2026-04-19 03:43:10 -04:00
CHANGELOG.md P8: Finalize CI/CD templates, prod ArgoCD app, and CHANGELOG for v0.1.0 2026-04-19 15:09:14 -04:00
clippy.toml Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00
Dockerfile Multi-stage Dockerfile with musl cross-compilation and .dockerignore 2026-04-19 13:47:45 -04:00
LICENSE Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00
miroir.yaml P3.3.d: Fix compilation - add missing local_search_ui_rate_limiter field 2026-04-26 19:30:10 -04:00
README.md Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00
rust-toolchain.toml Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00
rustfmt.toml Add repo hygiene: LICENSE, CHANGELOG, .gitignore 2026-04-18 20:47:36 -04:00

Miroir

Multi-node Index Replication Orchestrator, Integrated Rebalancing

Miroir is a RAID-like orchestration layer for Meilisearch. It stripes a large index across a fleet of small-RAM Meilisearch nodes with a configurable replication factor, fans out search queries across all shards, and rebalances shard assignments when nodes are added or removed — all using the Meilisearch Community Edition.

The Problem

Meilisearch loads its entire index into memory-mapped LMDB files. A large index that exceeds a single server's available RAM cannot run on that server. The Enterprise Edition's native sharding is gated behind a commercial license. Miroir solves this without it.

How It Works

Client
  │
  ▼
Miroir Orchestrator
  ├── Write path: hash(doc_id) → assign to shard → write to R replicas
  ├── Read path:  scatter query to all shards → gather → merge ranked results
  └── Rebalance: on node add/remove → recompute assignments → migrate minimum shards

Meilisearch Nodes (N instances, each holding a subset of shards)
  node-0   node-1   node-2   ...   node-N

Replication Factor

Analogous to software RAID — configurable per deployment:

RF Redundancy Node failures tolerated Capacity
1 None (stripe only) 0 100% of fleet
2 One replica 1 per shard group 50% of fleet
3 Two replicas 2 per shard group 33% of fleet

Key Components

  • Orchestrator — proxy that handles shard routing, scatter-gather, result merging, and topology management
  • Shard router — consistent hash function (Rendezvous/HRW) mapping document IDs to node assignments; minimal reshuffling on topology change
  • Rebalancer — on node add/remove, recomputes assignments and migrates only the shards that changed owners; surviving replicas serve reads during rebuild
  • Result merger — normalizes and merges ranked result sets from multiple shards into a single coherent response

Status

Design phase. See docs/ for architecture detail.