Для начала хотелось бы отметить, что, на мой взгляд, логичным представляется
разделять понятия балансировки (load balancing) и разделения (load sharing) нагрузки. Вкратце, балансировка нагрузки подразумевает некую обратную связь (чем меньше нагрузка сервера, к примеру, тем больше вероятность, что следующий запрос будет обработан именно им), в отличие от разделения нагрузки.
Рассмотрим поверхностно, как происходит взаимодействие клиента с web-сервисом. Клиент обращается по некому URL, происходит разрешение доменного имени в IP-адрес (момент 1). Далее, необходимо установить TCP-сессию с хостом, представленным этим адресом (момент 2). Для этого IP-пакеты, содержащие TCP-сегменты, должны добраться до этого хоста (момент 3). После установления TCP-сессии в ней идет обмен HTTP-сообщениями (момент 4).
В точке (1) возможно как разделение (DNS round-robin), так и балансировка нагрузки (специфичные DNS-решения, отслеживающие метрики производительности серверов). В точке (2) возможны балансировка/разделение нагрузки при помощи NAT или TCP-проксирования. В точке (3) возможно разделение нагрузки при помощи BGP anycast, equal-cost multipath или CARP/VRRP (в порядке уменьшения уровня абстракции архитектуры, если можно так выразиться). В точке (4) возможны балансировка/разделение нагрузки при помощи reverse proxy.
Эта же модель частично применима и при взаимодействии, скажем, веб-сервера с сервером баз данных и прочая.
Примерно таким образом можно распределить нагрузку на большое количество серверов. Но необходимо понимать, что при этом, в зависимости от сферы применения, встает ряд других задач, как, в частности, консистентность состояния серверов.