현대 시대의 http 연결 유지


92

따라서 http에 대해 한두 가지를 아는 haproxy 작성자에 따르면 :

Keep-alive는 CPU가 100 배 더 느릴 때 서버의 CPU 사용량을 줄이기 위해 고안되었습니다. 그러나 말하지 않은 것은 영구 연결은 많은 메모리를 소비하지만이를 연 클라이언트를 제외하고는 아무도 사용할 수 없다는 것입니다. 오늘날 2009 년에는 CPU가 매우 저렴하고 메모리는 아키텍처 나 가격에 따라 여전히 몇 기가 바이트로 제한됩니다. 사이트에 연결 유지가 필요한 경우 실제 문제가 있습니다. 로드가 많은 사이트는 최대 동시 클라이언트 수를 지원하기 위해 연결 유지를 비활성화하는 경우가 많습니다. 연결 유지 기능이없는 진짜 단점은 개체를 가져 오는 데 약간의 지연 시간이 늘어난다는 것입니다. 이를 보완하기 위해 브라우저는 비 유지 사이트의 동시 연결 수를 두 배로 늘립니다.

( http://haproxy.1wt.eu/에서 )

이것은 다른 사람들의 경험과 일치합니까? 즉, 연결 유지없이-결과가 거의 눈에 띄지 않습니까? (아마도 websockets 등을 사용하면 연결이 유지 상태에 관계없이 "열린"상태로 유지된다는 점에 주목할 가치가 있습니다-매우 반응이 빠른 앱의 경우). 서버에서 멀리 떨어져있는 사람들에게 더 큰 효과가 있습니까? 아니면 페이지를로드 할 때 동일한 호스트에서로드 할 아티팩트가 많은 경우입니까? (CSS, 이미지 및 JS와 같은 것이 점점 캐시 친화적 인 CDN에서 나왔다고 생각합니다.)

생각?

(이것은 serverfault.com 일인지 확실하지 않지만 누군가가 저에게 그것을 옮기라고 말할 때까지 게시물을 교차시키지 않을 것입니다).


1
haproxy에 대한 문서의 다른 곳에서 연결 유지가 더 유리한 용어로 언급되어 있다는 점은 주목할 가치가 있습니다. 사람들의 경험, 특히 대량 호스팅에 대해 듣고 싶습니다.
Michael Neale

"더 나은 디자인의 웹 / 애플리케이션 서버를 얻으십시오"? :-) 연속 (유사) 연결 처리가있는 최신 디자인 (예 : Jetty)은 본질적으로 메모리 / 스레드 문제를 완화합니다. 또한 "몇 GB"는 2008/2009 서버 용어처럼 들립니다 ;-)

3
저에게 흔들리는 것 같습니다. 새로운 소켓을 설정하는 데 관련된 추가 RTT는 인간이 감지 할 수있을만큼 충분히 길고 알려진 물리 법칙 내에서 줄일 수없는 하드 물리적 한계입니다. 반대로 RAM은 저렴하고 저렴하며 유휴 소켓이 몇 kB 이상을 사용할 이유가 없습니다.
Will Dean

2
하지만 흥미로운 것은 이것은 단순한 이론이 아니라 haproxy의 저자입니다. 내가 듣는 다른 모든 것은 이론과 가정입니다.
Michael Neale

답변:


141

이 인용문의 저자이기 때문에 응답하겠습니다 :-)

대규모 사이트에는 동시 연결과 대기 시간이라는 두 가지 큰 문제가 있습니다. 동시 연결은 콘텐츠를 다운로드하는 데 오래 걸리는 느린 클라이언트와 유휴 연결 상태로 인해 발생합니다. 이러한 유휴 연결 상태는 연결을 다시 사용하여 연결 유지 (keep-alive)라고하는 여러 개체를 가져 오기 때문에 발생하며 이는 대기 시간으로 인해 더욱 증가합니다. 클라이언트가 서버와 매우 가까우면 연결을 집중적으로 사용하고 거의 유휴 상태가되지 않도록 할 수 있습니다. 그러나 시퀀스가 ​​종료되면 아무도 채널을 빠르게 닫는 데 신경 쓰지 않으며 연결은 오랫동안 열려 있고 사용되지 않습니다. 이것이 많은 사람들이 매우 낮은 연결 유지 시간 제한을 사용하도록 제안하는 이유입니다. Apache와 같은 일부 서버에서 설정할 수있는 가장 낮은 시간 제한은 1 초이며 높은로드를 유지하기에는 너무 많은 경우가 많습니다. 당신 앞에 20000 개의 클라이언트가 있고 그들이 평균적으로 매초마다 하나의 개체를 가져 오면 20000 개의 연결이 영구적으로 설정됩니다. Apache와 같은 범용 서버에서 20000 개의 동시 연결은 거대하고로드되는 모듈에 따라 32GB에서 64GB 사이의 RAM이 필요하며 RAM을 추가해도 훨씬 더 높이는 것을 기대할 수 없습니다. 실제로 20000 클라이언트의 경우 브라우저가 가져올 개체가 많은 경우 2 ~ 3 개의 연결을 설정하려고하기 때문에 서버에서 40000 ~ 60000 개의 동시 연결을 볼 수도 있습니다. RAM을 추가해도 훨씬 더 높이 올라가고 싶지 않을 것입니다. 실제로 20000 클라이언트의 경우 브라우저가 가져올 개체가 많은 경우 2 ~ 3 개의 연결을 설정하려고하기 때문에 서버에서 40000 ~ 60000 개의 동시 연결을 볼 수도 있습니다. RAM을 추가해도 훨씬 더 높이 올라가고 싶지 않을 것입니다. 실제로 20000 클라이언트의 경우 브라우저가 가져올 개체가 많은 경우 2 ~ 3 개의 연결을 설정하려고하기 때문에 서버에서 40000 ~ 60000 개의 동시 연결을 볼 수도 있습니다.

각 개체 이후에 연결을 닫으면 동시 연결 수가 크게 감소합니다. 실제로는 개체 사이의 시간에 따라 개체를 다운로드하는 데 걸리는 평균 시간에 해당하는 요소만큼 떨어집니다. 개체 (미니어처 사진, 버튼 등)를 다운로드하는 데 50ms가 필요하고 위와 같이 초당 평균 1 개 개체를 다운로드하면 클라이언트 당 0.05 개의 연결 만 가능합니다. 20000 개의 클라이언트에 대한 동시 연결.

이제 새로운 연결을 설정하는 시간이 중요 할 것입니다. 원거리 클라이언트는 불쾌한 대기 시간을 경험하게됩니다. 과거에 브라우저는 연결 유지가 비활성화되었을 때 많은 양의 동시 연결을 사용했습니다. MSIE에서 4, Netscape에서 8의 숫자를 기억합니다. 이것은 실제로 개체 당 평균 대기 시간을 그만큼 나눈 것입니다. 연결 유지가 모든 곳에 존재하므로 원격 서버에 대한 부하가 더욱 증가하고 브라우저가 인터넷 인프라를 보호하기 때문에 더 이상 그 수가 많지 않습니다.

즉, 오늘날의 브라우저에서는 연결 유지 서비스만큼 응답 성이없는 연결 유지 서비스를 얻는 것이 더 어렵습니다. 또한 일부 브라우저 (예 : Opera)는 휴리스틱을 사용하여 파이프 라이닝을 사용합니다. 파이프 라이닝은 응답을 기다리지 않고 여러 요청을 전송하여 대기 시간을 거의 없애기 때문에 연결 유지를 사용하는 효율적인 방법입니다. 100 장의 작은 사진이있는 페이지에서 시도해 보았고 첫 번째 액세스는 연결 유지가없는 것보다 약 2 배 빠르지 만 다음 액세스는 응답이 너무 작아서 지연 시간 만 계산되기 때문에 약 8 배 더 빠릅니다. "304"응답).

이상적으로는 브라우저에 몇 가지 튜너 블을 가져 와서 가져온 개체 간의 연결을 유지하고 페이지가 완료되면 즉시 삭제해야한다고 말하고 싶습니다. 그러나 불행히도 우리는 그것을 보지 못하고 있습니다.

이러한 이유로 Apache와 같은 범용 서버를 전면에 설치해야하고 많은 양의 클라이언트를 지원해야하는 일부 사이트는 일반적으로 연결 유지를 비활성화해야합니다. 또한 브라우저가 연결 수를 늘리도록 강제하기 위해 다운로드를 병렬화 할 수 있도록 여러 도메인 이름을 사용합니다. 한 번의 추가 왕복이 있으므로 연결 설정이 훨씬 더 높기 때문에 SSL을 집중적으로 사용하는 사이트에서 특히 문제가됩니다.

요즘 더 일반적으로 관찰되는 것은 그러한 사이트가 수만에서 수십만 개의 동시 연결을 처리하는 데 문제가없는 haproxy 또는 nginx와 같은 가벼운 프런트 엔드를 설치하는 것을 선호하고 클라이언트 측에서 연결 유지를 활성화하고 아파치 측. 이 측면에서 연결 설정 비용은 CPU 측면에서 거의 null이며 시간 측면에서 전혀 눈에 띄지 않습니다. 이렇게하면 클라이언트 측에서 매우 낮은 시간 초과로 연결 유지로 인한 짧은 대기 시간과 서버 측의 낮은 연결 수가 두 가지 장점을 모두 제공합니다. 모든 사람이 행복하다 :-)

일부 상용 제품은 프론트로드 밸런서와 서버 간의 연결을 재사용하고이를 통해 모든 클라이언트 연결을 멀티플렉싱하여이를 더욱 향상시킵니다. 서버가 LB에 가까울 때 이득은 이전 솔루션보다 그다지 높지 않지만 여러 사용자 간의 예기치 않은 연결 공유로 인해 사용자 간의 세션 교차 위험이 없도록 애플리케이션을 조정해야하는 경우가 많습니다. . 이론적으로 이것은 결코 일어나지 않아야합니다. 현실은 많이 다릅니다 :-)


1
완전하고 포괄적 인 답변에 감사드립니다! Keep-alive에 대한 페이지의 다양한 댓글로 인해 약간 혼란 스러웠지만이 모든 것이 의미가 있습니다.
Michael Neale

흥미롭게도-나는 리눅스에서 크롬이 몇 초 동안 활성 연결을 재사용하는 것을 관찰했다. 즉, 다른 탭을 여는 데 걸린 시간-이 다른 탭은 다른 호스트 이름 이었지만 DNS 와일드 카드를 통해 동일한 서버 (대량 가상 호스팅)-따라서 동일한 연결을 재사용했습니다! (이것은 좋은 종류가 아닌 약간의 놀라움을 불러 일으켰습니다. 분명히 keep alive가 클라이언트 측에서만 가능하다면 괜찮습니다).
Michael Neale

내가 들었던 모든 것은 "아파치 이외의 다른 것을 사용하고 큰 문제가 아닙니다"였습니다. 내가 외삽 한 것은 "mod_php와 승객을 비활성화하면 아파치도 전투 기회를 가질 수있다"는 것입니다.
coolaj86

@ CoolAJ86 : 요점은 절대적으로 Apache를 강타하지 않는 것이며 개인적으로 사용합니다. 요점은 서버가 일반적 일수록 확장해야하는 옵션이 가장 적다는 것입니다. 일부 모듈에는 pre-fork 모델이 필요하므로 엄청난 수의 연결로 확장 할 수 없습니다. 그러나 설명했듯이 haproxy와 같은 다른 무료 구성 요소와 결합 할 수 있으므로 큰 문제는 아닙니다. 왜이 경우 모든 것을 대체할까요? 다른 서버를 사용하여 애플리케이션을 다시 구현하는 번거 로움을 겪는 것보다 haproxy를 설치하는 것이 좋습니다!
Willy Tarreau apr

22

이것이 쓰여진 후 (그리고 여기에 stackoverflow에 게시 됨) 우리는 이제 인기가 높아지고있는 nginx와 같은 서버를 갖게되었습니다.

예를 들어 nginx는 2.5MB (메가 바이트)의 RAM으로 단일 프로세스에서 열린 10,000 개의 연결 유지 연결을 유지할 수 있습니다. 실제로 매우 적은 RAM으로 수천 개의 연결을 열어 놓는 것은 쉽고, 도달 할 수있는 유일한 제한은 열린 파일 핸들 또는 TCP 연결 수와 같은 다른 제한입니다.

Keep-alive는 keep-alive 사양 자체의 문제가 아니라 Apache의 프로세스 기반 확장 모델과 아키텍처가이를 수용하도록 설계되지 않은 서버에 해킹 된 keep-alive 때문에 문제였습니다.

특히 문제는 Apache Prefork + mod_php + keep-alives입니다. 이것은 모든 단일 연결이 PHP 프로세스가 완전히 유휴 상태이고 연결 유지 상태로만 열려 있어도 PHP 프로세스가 차지하는 모든 RAM을 계속 차지하는 모델입니다. 이것은 확장 가능하지 않습니다. 그러나 서버를 이런 방식으로 설계 할 필요는 없습니다. 서버가 별도의 프로세스에서 모든 연결 유지 연결을 유지해야하는 특별한 이유가 없습니다 (특히 모든 프로세스에 완전한 PHP 인터프리터가있는 경우에는 해당되지 않음). PHP-FPM과 nginx와 같은 이벤트 기반 서버 처리 모델은 문제를 우아하게 해결합니다.

2015 업데이트 :

SPDY 및 HTTP / 2는 HTTP의 연결 유지 기능을 훨씬 더 나은 것으로 대체합니다. 연결을 유지하고 여러 요청과 응답을 할 수있을뿐만 아니라 다중화 할 수 있으므로 응답을 어떤 순서로든 보낼 수 있습니다. , 그리고 요청 된 순서대로가 아니라 병렬로. 이렇게하면 느린 응답이 더 빠른 응답을 차단하는 것을 방지하고 브라우저가 단일 서버에 대해 여러 개의 병렬 연결을 열어 두려는 유혹을 제거합니다. 이러한 기술은 mod_php 접근 방식의 부적절 함과 PHP-FPM과 같은 것과 별도로 결합 된 이벤트 기반 (또는 최소한 다중 스레드) 웹 서버와 같은 것의 이점을 더욱 강조합니다.


2

내 이해는 CPU와는 거의 관련이 없지만 세계 반대편에 반복되는 소켓을 열 때 대기 시간이 있다는 것입니다. 대역폭이 무한한 경우에도 연결 지연으로 인해 전체 프로세스가 느려집니다. 페이지에 수십 개의 개체가있는 경우 증폭됩니다. 영구 연결조차도 요청 / 응답 지연 시간이 있지만 평균적으로 2 개의 소켓이 있으면 하나는 스트리밍 데이터 여야하고 다른 하나는 차단 될 수 있습니다. 또한 라우터는 쓰기 전에 소켓이 연결되었다고 가정하지 않습니다. 전체 왕복 핸드 셰이크가 필요합니다. 다시 말하지만, 나는 전문가라고 주장하지 않지만 이것이 내가 항상 그것을 본 방법입니다. 정말 멋진 것은 완전히 ASYNC 프로토콜입니다 (완전히 아픈 프로토콜이 아닙니다).


네-그게 내 가정입니다. 수단 (거리로 인해) 대기 시간이 진짜 문제가있는 지점이 - 어쩌면 그것은 트레이드 오프입니다
마이클 닐

좋아, 그래서 현대 타이포그래피는 (아마도) 가까운 프록시에 연결하게 할 것입니다. 그러나 프록시가 영구 연결을 사용 해야하는지 여부에 대한 질문을 확장합니까?
catchpolenet 2010

@Michael Neale도 TCP 느린 시작과 같은 이유로 인해 실제 지연 시간 패널티는 예상보다 훨씬 더 나쁩니다.
MartinodF

아마도 트레이드 오프는 훨씬 더 짧은 시간 초과 기간입니다. 백업 된 요청이있는 경우 소켓을 종료하고 다시 시작하는 이유는 무엇입니까? 1 초라도 페이지가 전체 지속성으로로드 된 다음 즉시 소켓을 종료 할 수 있습니다.
catchpolenet 2010

2

CloudFront 또는 CloudFlare와 같은 "원본 풀"CDN을 사용하는 경우 매우 긴 연결 유지 기능이 유용 할 수 있습니다. 실제로 완전히 동적 인 콘텐츠를 제공하는 경우에도 CDN이없는 것보다 더 빠를 수 있습니다.

각 PoP가 기본적으로 서버에 영구적으로 연결되도록 오래 지속되는 경우 사용자가 사이트를 처음 방문 할 때 느린 핸드 셰이크 대신 로컬 PoP와 빠른 TCP 핸드 셰이크를 수행 할 수 있습니다. (Light 자체는 광섬유를 통해 전 세계를 반으로 이동하는 데 약 100ms가 걸리며 TCP 연결을 설정하려면 3 개의 패킷이 앞뒤로 전달되어야합니다. SSL에는 3 개의 왕복이 필요합니다 .)


1
나는 +1하고 싶었지만 두 번째 단락에는 전 세계의 절반을 여행하는 데 10ms 밖에 걸리지 않는 잘못된 빛의 발언이 있습니다. 진공에서 10ms의 광속은 3000km이고 광섬유에서 10ms의 광속은 2000km를 훨씬 넘지 않습니다. 지구 반대편 (표면을 따라)은 20,000km입니다. 즉 100 밀리 것이다 그래서에만 섬유 가능성이 바다로 아프리카를 circumnavigating 또는 하와이에 의해 긴 경로를 복용하기보다는 런던에서 시드니까지 직접 가면 --- ...
피라미드

@pyramids 당신 말이 맞아요. 업데이트됩니다.
mjs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.