TL/DR
It sounds like you need to enable sticky sessions at your load-balancer/router level, so that the users will be sent back to the same server in the cluster that their session originated on.
The long version
In Craft 2.x, every new user gets new PHP session represented by a file on your web server and a cookie in your browser. By default PHP names that cookie PHPSESSID
, but Craft will default set it to CraftSessionId
, although you can configure its name with the phpSessionName config setting.
PHP has a way to use sessions without cookies providing a way to append a unique session ID to the querystring of a URL, but (for many reasons), Craft doesn't support that method.
In addition to the PHP session cookie, Craft will create an identity cookie upon a successful login that has a randomly generated name similar to 4190d8c6874f8615f88325f5b285fc40
. That cookie is how Craft keeps track that you're successfully authenticated.
The problem with load-balanced setups that don't use sticky sessions is that with all of these default settings, when a session is started on server A and then a user is bounced to server B, server B has no knowledge of the session because it was created on server A.
There are ways around it, of course, the easiest being to enable stick sessions at the load balancer level, ensuring that users will get sent back to the server their session was started on for the lifetime of that session.
Alternatively, if sticky sessions aren't your thing, you can configured a shared network storage location and tell each web server to use it for its session.save_path, ensuring they all have access to all server-side session files. If you go this route, you'll also want to set the appId config setting to be identical across all web servers, since it is used in decrypting cookie data (including sessions). By default it it is randomly generated per Craft installation.