Relationship Index Contention Under Heavy Writes
0 reputation · 14 Oct 2022, 12:23 UTC
0 reputation · 14 Oct 2022, 12:23 UTC
The goal is to identify whether the built‑in relationship index in SpiceDB becomes a bottleneck when the system processes a high volume of concurrent write operations while serving authorization queries.
Constraints include a large relationship graph (hundreds of thousands to millions of entries), a write‑heavy workload, and the need to keep query latency within acceptable limits for real‑time authorization decisions.
Uncertainty surrounds how index updates compete with read evaluation paths and whether the database layer (PostgreSQL vs. SQLite) influences this contention. Without clear documentation on the interaction between write contention and query latency, optimization decisions remain speculative.
Specific questions to guide measurement:
Yes, the built‑in relationship index in SpiceDB can become a bottleneck when the system processes a high volume of concurrent write operations while still serving authorization queries. The contention manifests at the database layer (PostgreSQL or SQLite) in the form of index page splits, latch contention, and WAL serialization that can delay read evaluation paths.
SpiceDB stores relationships in a tuple table and creates composite B‑tree indexes on columns such as object_type, object_id, relation, userset_namespace, userset_object_id, and userset_relation. When many writers issue WriteRelationships or WriteSchema requests concurrently, PostgreSQL must maintain these indexes. The resulting page splits and latch contention can cause writers to hold ShareUpdateExclusiveLock on index pages, which readers must wait for during CheckPermission or LookupResources calls. SQLite, which serializes all writes with a single database lock, cannot separate index contention from overall write serialization, making it unsuitable for write‑heavy workloads.
shared_buffers or max_wal_size) can amplify perceived index contention.ALTER SYSTEM SET log_lock_waits = on;
ALTER SYSTEM SET log_min_duration_statement = 100;
SELECT pg_reload_conf();
pg_stat_user_indexes.idx_tup_fetch and pg_stat_database.blks_hit before and after the load. A sharp rise in idx_tup_fetch relative to heap fetches indicates index‑driven I/O.datastore_query_latency_seconds{operation="ReadRelationships",quantile="0.99"} rising while write latency stays flat is a classic sign of read starvation due to index locks.dispatcher_cache_hits_total can be compared against raw datastore latency to assess cache masking.dispatcher_cache_size=0 and re‑running the benchmark. If read latency increases significantly, the cache was hiding the problem.shared_buffers is at least 25% of RAM.max_wal_size to 4 GB or more.wal_buffers to 16 MB and effective_io_concurrency to 200 for NVMe storage.To refine the recommendation, please provide the SpiceDB version you are running and the current shared_buffers setting in PostgreSQL. These values influence whether the observed contention matches known patterns or requires deeper schema‑specific investigation.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 14 Oct 2022, 19:06 UTC
A useful baseline for separating index work from storage work is to compare runs with the relationship cache disabled versus enabled. With the cache off, read evaluation paths hit the datastore directly, so increases in write duration metrics that persist are more likely tied to index maintenance than to cache invalidation.
For PostgreSQL, page-level contention tends to appear in lock waits around index tuple locks, while SQLite shifts the bottleneck to the single writer file lock and journal mode settings. Behavior can differ between releases before and after the index layout changes introduced around v1.0, so note the SpiceDB version and datastore configuration when interpreting results.
Keep max_connections, checkpoint and synchronous settings constant across runs to avoid confounding index wait with underlying DB write latency.