http keep-alive в современную эпоху

92

Итак, по словам автора haproxy, кто кое-что знает о http:

Keep-alive был изобретен для уменьшения использования ЦП на серверах, когда ЦП были в 100 раз медленнее. Но что не сказано, так это то, что постоянные соединения потребляют много памяти и не могут использоваться никем, кроме клиента, который их открыл. Сегодня, в 2009 году, процессоры очень дешевы, а объем памяти по-прежнему ограничен несколькими гигабайтами из-за архитектуры или цены. Если сайту нужен keep-alive, возникает реальная проблема. Высоконагруженные сайты часто отключают поддержку активности для поддержки максимального количества одновременных клиентов. Реальный недостаток отсутствия keep-alive - это немного увеличенная задержка для выборки объектов. Чтобы компенсировать это, браузеры удваивают количество одновременных подключений к сайтам без поддержки активности.

http://haproxy.1wt.eu/ )

Соответствует ли это опыту других людей? т.е. без keep-alive - сейчас результат еле заметен? (вероятно, стоит отметить, что с веб-сокетами и т. д. - соединение остается «открытым» независимо от статуса keep-alive - для очень отзывчивых приложений). Будет ли эффект больше для людей, удаленных от сервера, или если при загрузке страницы нужно загрузить много артефактов с одного и того же хоста? (Я думаю, что такие вещи, как CSS, изображения и JS, все чаще поступают из CDN, дружественных к кешу).

Мысли?

(не уверен, что это связано с serverfault.com, но я не буду перекладывать сообщения, пока кто-нибудь не скажет мне переместить его туда).

Майкл Нил
источник
1
Стоит отметить, что в другом месте документации для haproxy этот keep-alive упоминается в других, более благоприятных условиях. Я хотел бы услышать об опыте людей, особенно о массовом хостинге.
Майкл Нил
"Получить лучше спроектированный веб-сервер / сервер приложений"? :-) Новые разработки (такие как Jetty) с обработкой продолжения (-подобных) соединений существенно уменьшают проблемы с памятью / потоками. Кроме того, "несколько ГБ" звучит как термин сервера 2008/2009 ;-)
3
Для меня это звучит как треп. Дополнительный RTT, связанный с установкой нового сокета, является жестким физическим пределом, который часто бывает достаточно длинным, чтобы его мог обнаружить человек, и не может быть уменьшен в рамках известных законов физики. И наоборот, оперативная память дешевая, становится все дешевле, и нет причин для неиспользуемого сокета использовать более нескольких килобайт.
Уилл Дин,
2
но что интересно, это не просто теория - это автор haproxy. Все остальное, что я слышу, - это теории и предположения.
Майкл Нил,

Ответы:

141

Привет, раз уж я автор этой цитаты, отвечу :-)

На больших сайтах есть две большие проблемы: одновременные подключения и задержка. Одновременное подключение вызывается медленными клиентами, которым требуется много времени для загрузки содержимого, а также состояниями незанятого подключения. Эти состояния незанятого соединения вызваны повторным использованием соединения для выборки нескольких объектов, известным как keep-alive, что дополнительно увеличивается из-за задержки. Когда клиент находится очень близко к серверу, он может интенсивно использовать соединение и гарантировать, что он почти никогда не простаивает. Однако, когда последовательность заканчивается, никто не заботится о быстром закрытии канала, и соединение остается открытым и не используется в течение длительного времени. Это причина, по которой многие люди предлагают использовать очень низкий тайм-аут проверки активности. На некоторых серверах, таких как Apache, самый низкий тайм-аут, который вы можете установить, составляет одну секунду, и часто его слишком много для выдерживания высоких нагрузок: Если перед вами 20000 клиентов, и они загружают в среднем один объект каждую секунду, у вас будут постоянно установлены эти 20000 соединений. 20000 одновременных подключений на сервере общего назначения, таком как Apache, огромны, потребуют от 32 до 64 ГБ ОЗУ в зависимости от того, какие модули загружены, и вы, вероятно, не можете надеяться подняться намного выше, даже добавив ОЗУ. На практике для 20000 клиентов вы можете даже увидеть от 40000 до 60000 одновременных соединений на сервере, потому что браузеры будут пытаться установить от 2 до 3 соединений, если у них есть много объектов для выборки. и вы, вероятно, не можете надеяться подняться намного выше, даже добавив RAM. На практике для 20000 клиентов вы можете даже увидеть от 40000 до 60000 одновременных соединений на сервере, потому что браузеры будут пытаться установить от 2 до 3 соединений, если у них есть много объектов для выборки. и вы, вероятно, не можете надеяться подняться намного выше, даже добавив RAM. На практике для 20000 клиентов вы можете даже увидеть от 40000 до 60000 одновременных соединений на сервере, потому что браузеры будут пытаться установить от 2 до 3 соединений, если у них есть много объектов для выборки.

Если вы закроете соединение после каждого объекта, количество одновременных соединений резко упадет. В самом деле, оно снизится на коэффициент, соответствующий среднему времени загрузки объекта по времени между объектами. Если вам нужно 50 мс для загрузки объекта (миниатюрная фотография, кнопка и т. Д.), И вы загружаете в среднем 1 объект в секунду, как указано выше, тогда у вас будет только 0,05 соединения на одного клиента, что составляет всего 1000 одновременных подключений для 20000 клиентов.

Теперь пришло время установить новые связи. У удаленных клиентов возникнет неприятная задержка. Раньше браузеры использовали большое количество одновременных подключений, когда функция keep-alive была отключена. Я помню цифры 4 на MSIE и 8 на Netscape. Это действительно разделило бы среднюю задержку для каждого объекта на столько же. Теперь, когда keep-alive присутствует повсюду, мы больше не видим таких высоких цифр, потому что это еще больше увеличивает нагрузку на удаленные серверы, а браузеры заботятся о защите инфраструктуры Интернета.

Это означает, что с современными браузерами труднее добиться того, чтобы сервисы, не поддерживающие активность, так же быстро реагировали, как и сервисы поддержки активности. Кроме того, некоторые браузеры (например, Opera) используют эвристику, чтобы попытаться использовать конвейерную обработку. Конвейерная обработка - это эффективный способ использования проверки активности, поскольку он почти устраняет задержку, отправляя несколько запросов, не дожидаясь ответа. Я пробовал это на странице со 100 маленькими фотографиями, и первый доступ примерно в два раза быстрее, чем без сохранения активности, но следующий доступ примерно в 8 раз быстрее, потому что ответы настолько малы, что учитывается только задержка (только «304» отклика).

Я бы сказал, что в идеале у нас должны быть некоторые настройки в браузерах, чтобы они поддерживали связь между извлеченными объектами и немедленно отбрасывали их, когда страница была завершена. Но, к сожалению, мы этого не видим.

По этой причине некоторые сайты, которым необходимо установить серверы общего назначения, такие как Apache, на передней стороне и которые должны поддерживать большое количество клиентов, обычно должны отключать поддержку активности. И чтобы заставить браузеры увеличивать количество подключений, они используют несколько доменных имен, чтобы загрузки можно было распараллеливать. Это особенно проблематично на сайтах, интенсивно использующих SSL, потому что настройка соединения еще выше, так как есть еще один дополнительный круговой обход.

В настоящее время чаще всего наблюдается то, что такие сайты предпочитают устанавливать легкие внешние интерфейсы, такие как haproxy или nginx, которые без проблем обрабатывают от десятков до сотен тысяч одновременных подключений, они включают поддержку активности на стороне клиента и отключают его на стороне клиента. Сторона Apache. С этой стороны, стоимость установления соединения практически равна нулю с точки зрения ЦП и совсем не заметна с точки зрения времени. Таким образом, это обеспечивает лучшее из обоих миров: низкую задержку из-за поддержания активности с очень маленькими таймаутами на стороне клиента и небольшое количество подключений на стороне сервера. Все счастливы :-)

Некоторые коммерческие продукты еще больше улучшают это, повторно используя соединения между передним балансировщиком нагрузки и сервером и мультиплексируя все клиентские соединения через них. Когда серверы расположены близко к LB, выигрыш не намного выше, чем у предыдущего решения, но часто требуется адаптация приложения, чтобы гарантировать отсутствие риска пересечения сеанса между пользователями из-за неожиданного разделения соединения между несколькими пользователями. . Теоретически этого не должно происходить. Реальность сильно отличается :-)

Вилли Тарро
источник
1
Спасибо за исчерпывающий и исчерпывающий ответ! Меня немного смущали различные комментарии на странице о keep-alive - но все это имеет смысл.
Майкл Нил
Интересно, что я наблюдал, как Chrome в Linux повторно использовал поддерживаемое соединение в течение нескольких секунд, то есть время, которое потребовалось для открытия другой вкладки - эта другая вкладка относилась к другому имени хоста, но разрешалась через подстановочный знак DNS на тот же сервер (масса виртуальный хостинг) - и таким образом повторно использовали одно и то же соединение! (это вызвало у меня некоторое удивление, не очень хорошее - очевидно, если keep alive только на стороне клиента, это нормально).
Майкл Нил,
Все, что я слышал, было «используйте что-нибудь кроме apache, и это не имеет большого значения». Я экстраполировал, что «отключите mod_php и пассажира, и тогда даже у apache может появиться шанс на борьбу».
coolaj86
@ CoolAJ86: суть не в том, чтобы разбивать Apache, и я лично использую его. Дело в том, что чем более универсален сервер, тем меньше возможностей для масштабирования. Некоторым модулям требуется предварительная модель, поэтому вы не можете масштабироваться до огромного количества подключений. Но, как уже объяснялось, это не имеет большого значения, поскольку вы можете комбинировать его с другим бесплатным компонентом, таким как haproxy. Зачем кому-то заменять все в этом случае? Лучше установить haproxy, чем заново реализовывать свое приложение на другом сервере!
Вилли Тарро
22

За годы, прошедшие с тех пор, как это было написано (и размещено здесь, в stackoverflow), у нас теперь есть серверы, такие как nginx, популярность которых растет.

Например, nginx может поддерживать 10 000 активных соединений в одном процессе, имея всего 2,5 МБ (мегабайта) ОЗУ. На самом деле легко держать открытыми несколько тысяч соединений с очень небольшим объемом оперативной памяти, и единственными ограничениями, которые вы столкнетесь, будут другие ограничения, такие как количество дескрипторов открытых файлов или TCP-соединений.

Сохранение активности было проблемой не из-за каких-либо проблем со спецификацией keep-alive, а из-за модели масштабирования Apache, основанной на процессах, и из-за того, что keep-alive были взломаны на сервере, архитектура которого не была разработана для этого.

Особенно проблематичен Apache Prefork + mod_php + keep-alives. Это модель, в которой каждое отдельное соединение будет продолжать занимать всю оперативную память, которую занимает процесс PHP, даже если он полностью простаивает и остается открытым только для поддержания активности. Это не масштабируется. Но серверы не обязательно должны быть спроектированы таким образом - нет особой причины, по которой серверу нужно поддерживать каждое поддерживающее соединение в отдельном процессе (особенно, когда каждый такой процесс имеет полный интерпретатор PHP). PHP-FPM и модель обработки сервера на основе событий, такая как в nginx, элегантно решают проблему.

Обновление 2015:

SPDY и HTTP / 2 заменяют функцию поддержки активности HTTP чем-то еще лучшим: возможностью не только поддерживать соединение и делать несколько запросов и ответов по нему, но и мультиплексировать их, чтобы ответы можно было отправлять в любом порядке , и параллельно, а не только в том порядке, в котором они были запрошены. Это предотвращает блокировку медленных ответов более быстрых и устраняет соблазн браузеров поддерживать несколько параллельных подключений к одному серверу. Эти технологии дополнительно подчеркивают недостатки подхода mod_php и преимущества чего-то вроде событийного (или, по крайней мере, многопоточного) веб-сервера, соединенного отдельно с чем-то вроде PHP-FPM.

Thomasrutter
источник
2

Насколько я понимаю, это мало связано с процессором, а связано с задержкой при открытии повторяющихся сокетов на другой конец света. даже если у вас бесконечная пропускная способность, задержка подключения замедлит весь процесс. усиливается, если на вашей странице десятки объектов. даже постоянное соединение имеет задержку запроса / ответа, но она уменьшается, когда у вас есть 2 сокета, так как в среднем один должен передавать данные, а другой может блокировать. Кроме того, маршрутизатор никогда не предполагает, что сокет подключается, прежде чем разрешить вам писать в него. Требуется полное рукопожатие туда и обратно. опять же, я не претендую на звание эксперта, но я всегда так видел. что было бы действительно круто, так это протокол полностью ASYNC (нет, не полностью больной протокол).

ловушка
источник
да - это было бы моим предположением. возможно, это компромисс - есть момент, когда задержка (из-за расстояния) означает, что это настоящая проблема
Майкл Нил
хорошо, современная типографика заставит вас подключиться к прокси, который находится поблизости (возможно). но тогда вы расширяете вопрос, должны ли прокси использовать постоянные соединения?
catchpolenet
@Michael Neale также из-за таких вещей, как медленный запуск TCP, фактический штраф за задержку намного хуже, чем вы могли ожидать.
MartinodF
возможно, компромисс - это гораздо более короткий период ожидания. если у вас есть резервные копии запросов, зачем отключать сокет и начинать заново? даже 1 секунда позволит странице загрузиться с полным постоянством, а затем сразу же выключить сокеты.
catchpolenet
2

Очень длительные проверки активности могут быть полезны, если вы используете CDN с «исходным запросом», например CloudFront или CloudFlare. Фактически, это может сработать быстрее, чем отсутствие CDN, даже если вы обслуживаете полностью динамический контент.

Если вы долго поддерживаете активность, так что каждый PoP в основном имеет постоянное соединение с вашим сервером, то при первом посещении вашего сайта пользователи могут выполнить быстрое установление связи TCP со своим локальным PoP вместо медленного рукопожатия с вами. (Самому свету требуется около 100 мс, чтобы пройти половину земного шара по оптоволокну, а для установления TCP-соединения требуется передача трех пакетов туда и обратно. SSL требует трех циклов приема -передачи .)

mjs
источник
1
У меня возникло искушение поставить +1, но во втором абзаце есть это неправильное замечание: свет занимает всего 10 мс, чтобы облететь половину света. 10 мс скорости света в вакууме - это 3000 км, а скорость света 10 мс в волокне не намного больше, чем 2000 км; на полпути (по поверхности) 20 000 км. Таким образом, это будет 100 мс - если только ваш оптоволокно идет прямо из Лондона в Сидней, а не облетит Африку морем или проделает длинный путь по Гавайям ...
пирамиды
@pyramids Вы правы, либо я опечатал это, либо просто дурачился. Буду обновлять.
mjs