HTTP forgets you between requests
HTTP is stateless: it keeps no memory between requests. Every request has to carry everything the server needs, because the server has already forgotten the last one. That looks like a defect. It is the load-bearing wall of web scaling. If no request depends on what one particular machine remembers, any machine can serve any request, and you can add or remove servers freely.
Users still expect to log in once, so state gets layered on top. The usual mechanism is a session cookie. On login the server creates a record, stores it somewhere, and hands the browser an opaque identifier, which the browser then attaches to every request after that without being asked.
Where the state actually goes
Where that record lives matters, because it is the real design choice. Keep it in one server's own memory and you have created sticky sessions. The balancer must now send each user back to the same machine every time, and when that machine dies, everyone on it is logged out. Deploys hurt for the same reason.
A shared store fixes it, one every server can reach. Each server does one fast lookup per request, roughly a millisecond, and your machines go back to being interchangeable.
Or remove the lookup altogether. A signed token packs the user identifier and an expiry into the credential itself, so a server checks the signature and trusts the contents without asking anything. The catch is taking it back. A session in a shared store dies the moment you delete it. A signed token stays valid until it expires, whatever you would prefer, so a stolen one keeps working. Short expiries and refresh tokens are the usual compromise, and teams that need instant logout drift back to server-side state.
Worked example
Sofia's startup runs its Rails app on two servers with in-memory sessions and cookie-pinned routing. During a Tuesday deploy, server 1 restarts and every user pinned to it is logged out mid-action; support gets 43 tickets in an hour, several from users whose half-filled forms vanished. The fix costs a day: sessions move to a Redis instance shared by both servers, and the load balancer drops its pinning rule. Each request now spends about 1 ms fetching the session, which is invisible next to the 80 ms the requests already took. The next deploy rolls servers one at a time and nobody notices. Later, when traffic triples, she scales from two app servers to six without touching the session code at all.