Archetype 2 — Relation / Edge #
What this archetype is #
A relation row links two entities. The hard part is uniqueness, forward and reverse lookup, and hot reverse edges.
Examples: follow relation, membership, share relation, likes.
We will use user follows user as the running example.
Layer 1: Entities and Postgres table design #
One source-truth entity:
FollowRelationState
-> one edge per (follower, followee)
One primary table:
create table follows (
follower_id bigint not null,
followee_id bigint not null,
status text not null default 'ACTIVE',
created_at timestamptz not null default now(),
primary key (follower_id, followee_id)
);
Forward and reverse indexes:
create index follows_followee_created_idx
on follows (followee_id, created_at desc)
where status = 'ACTIVE';
create index follows_follower_created_idx
on follows (follower_id, created_at desc)
where status = 'ACTIVE';
For celebrity reverse hotspots, add shard_id:
alter table follows add column shard_id int not null default 0;
create index follows_followee_shard_created_idx
on follows (followee_id, shard_id, created_at desc)
where status = 'ACTIVE';
Layer 2: Write path mechanics #
Create edge #
insert into follows (
follower_id, followee_id, status
) values ($1, $2, 'ACTIVE')
on conflict (follower_id, followee_id) do update
set status = 'ACTIVE';
Remove edge #
Soft delete:
update follows
set status = 'REMOVED'
where follower_id = $1
and followee_id = $2
and status = 'ACTIVE';
Forward read #
select followee_id, created_at
from follows
where follower_id = $1
and status = 'ACTIVE'
order by created_at desc
limit 50;
Reverse read #
select follower_id, created_at
from follows
where followee_id = $1
and status = 'ACTIVE'
order by created_at desc
limit 50;
Layer 3: Fault tolerance #
- Duplicate edge creation on retry: prevented by composite PK / unique key
- Add/remove race:
statusupdate ordering matters - Count projection lag: follower counts stored elsewhere may be stale
- Stale relation list cache: reverse edge cache may lag deletes
Layer 4: Scale #
Default hotspots:
- celebrity skew
- hot reverse index range
- hot count key
Common mitigations:
- reverse-edge sharding with
shard_id = hash(follower_id) % N - separate follower count projection table
- cache hot reverse pages