skip to content

Three unrelated applications share one in-memory store instance with no per-team budget - what are they actually sharing?

level: juniorimportance: should knowfreq 52%

answer

  1. nothing sits between the tenants
  2. one ceiling, not three budgets
  3. growth is subtracted from neighbours
  4. blast radius is the whole instance

basics

~20 s

One memory ceiling, one keyspace, one set of connection slots and one server's capacity to run operations, with nothing in between. What one application consumes is unavailable to the others, and what one does to the instance happens to all three.

solid answer

~50 s

A shared instance pools four things nobody carved up: the memory ceiling the server enforces on itself, the single keyspace all three write into, the server's limit on concurrent connections, and the capacity to execute operations. A fifth is easy to miss - the operating posture, because the ceiling, what the server does when it reaches it, and when the instance restarts are single-valued settings applied to everyone at once. There is no per-team budget unless someone built one; most stores of this class ship with no per-owner accounting, so the instance will not tell you that one owner holds most of the stored-data size and will not stop them. The consequence runs both ways: one team's growth pushes the instance toward a ceiling everyone lives under, and one team's expensive operation occupies capacity every other caller is waiting on.

go deeper

for a junior

Be able to name what one instance pools: the memory ceiling, the keyspace, the connection slots and the capacity to run operations. No per-team budget exists unless someone built one.

for a middle

Explain the mechanism in both directions - growth consumes a ceiling the neighbours share, and an expensive operation consumes capacity the neighbours are queued behind - and say which of the two a given symptom points at.

for a senior

Price an action before taking it. Raising the ceiling, removing a prefix or restarting is a decision about every occupant, so name the co-tenants and what they hold before touching a shared instance.

for a principal

Decide what is allowed to share an instance at all, and make the sharing contract explicit: who changes settings, what one tenant's worst case may cost the others, and which occupants must be separated because their worst cases are not comparable.

## What 'shared' actually means An in-memory store instance is one process holding one keyspace. When several unrelated applications are pointed at it, nothing sits between them: there is no tenant registry, no per-owner allocation, and in most stores of this class no per-owner accounting either. **Multi-tenant here usually means only that several teams were given the same address** and asked to keep their key names apart. That leaves four resources pooled, none of them divided: - **The memory ceiling.** The upper bound the server enforces on itself is a property of the instance, not of an owner. Every entry any tenant stores is charged against it. - **The keyspace.** One flat namespace that all tenants write into, and that any of them can read from or remove out of. - **Connection slots.** The server's limit on concurrent connections is instance-wide; a tenant whose pool grows takes slots the others may need. - **Execution capacity.** The instance's ability to run operations is finite and undivided, and work submitted by one tenant occupies it. A fifth is pooled and easy to miss: **the operating posture**. The ceiling, what the server does when it reaches it, whether anything is written to disk, and when the instance is restarted or upgraded are single-valued settings that apply to every occupant at once. There is no per-tenant version of any of them. ## Growth: one tenant's entries are another tenant's missing room Because the ceiling is instance-wide, a tenant that doubles what it stores does not run out of its own room - it moves the whole instance closer to the ceiling. What happens there is a property of the instance too. A store configured to make room by removing entries removes whatever its configured ordering rule ranks first among the candidates it is allowed to touch, and those candidates come from the whole keyspace; the tenant that caused the pressure is not preferentially charged for it. A store configured to refuse instead begins failing writes for whoever writes next, which is just as likely to be a neighbour. Either way, the cost does not land where the growth did. ## Capacity and connections: one tenant's call is another tenant's latency Work queues at the instance, not per owner. On a store whose server executes one operation at a time, a single expensive operation stops every other caller for as long as it runs. On a store that serves requests on many threads the effect is softer - callers touching other entries can proceed - but capacity is still finite and still shared, and enough concurrent work from one tenant saturates it. Connections behave the same way: the limit is reached by the sum of all tenants' pools, so the tenant refused a new connection is often not the tenant that filled them. ## Damage: one tenant's mistake is everyone's incident Actions that are routine on a single-owner instance are not routine here. Raising the ceiling, removing a large group of entries, restarting to clear bad state, changing the persistence posture - each is a decision about every occupant, taken by one of them. A bulk removal issued with a pattern one character too broad reaches a neighbour's keys, because the only thing between them was a string convention. | Shared resource | What one tenant's excess does to the others | What the instance usually shows you | |---|---|---| | Memory ceiling | Entries removed, or writes refused, for tenants who did not grow | Instance totals only: stored-data size and resident footprint | | Execution capacity | Latency for every waiting caller, and timeouts on the tightest ones | Instance-wide operation rates and server-side execution times | | Connection slots | New connections refused to whoever asks next | A count of current connections, not a count per owner | | Operating posture | Settings, restarts and upgrades applied to all at once | One configuration, with nothing scoped to a tenant | ## What varies between stores Do not assume the whole family behaves the same way here: - Some stores remove entries to make room; others refuse the write, and some refuse by default. The symptom of a full instance differs accordingly. - Some serve on a single execution thread; others are multi-threaded and reach per-operation atomicity by locking the entry instead. One long operation does not have the same blast radius on both. - A few stores, and several managed offerings, do provide a per-tenant container or quota. Where one exists, check whether it bounds memory and capacity or only partitions names - the two are routinely confused. ## What to establish before joining a shared instance 1. Who else is on it, and whether what they hold is a replaceable copy or state that exists nowhere else. 2. What the instance does at its ceiling, since that decides whether your symptom will be missing entries or failed writes. 3. Who may change the ceiling, the posture and the restart schedule, and how the others hear about it. 4. How usage is attributed today - and, where it is not attributed at all, that your key names at least make attribution possible later.

  • Stored-data size is climbing and no team admits to a change - how do you find the owner when the instance keeps no per-team accounting?
    Attribute by key prefix. Walk the keyspace incrementally in bounded batches, or run a sampling pass over entries away from the serving path, and roll approximate sizes up per prefix. That gives an estimate, not a bill, and it only works where prefixes map to owners; keys nobody prefixed land in an 'unknown' bucket that is often the largest one.
  • Is sharing safer if every tenant stores only replaceable copies of data that exists elsewhere?
    It lowers the cost of losing entries, not the cost of sharing. An instance holding only replaceable data can be emptied without losing anything, though whatever backs it must then absorb the traffic. The effects on latency, connections and capacity are unchanged. Sharing turns dangerous fastest when one occupant holds state that exists nowhere else.

saying these in an interview costs you the question

  • Assumes each application is allocated its own slice of the instance's memory
  • Thinks a busy tenant only degrades itself
  • Believes the instance reports memory usage per owning team by default
  • Says the instance always refuses writes rather than ever removing a neighbour's entry
  • Counts memory as the only shared resource and forgets connections and execution capacity