>시스템 튜토리얼 >리눅스 >웹 서버 성능 개선 방법

웹 서버 성능 개선 방법

WBOY
WBOY앞으로
2024-01-07 18:10:321211검색
소개 인터넷의 지속적인 발전으로 인해 음식, 의복, 주택, 교통, 금융교육, 주머니부터 신원에 이르기까지 일상생활에서 점점 더 많은 요구가 인터넷을 통해 실현되고 있으며, 사람들은 항상 인터넷에 의존하고 있습니다. 점점 더 많은 사람들이 자신의 필요를 충족하기 위해 인터넷을 사용하고 있습니다.

고객의 요청을 직접적으로 직면하는 웹 서버로서, 동시에 더 많은 요청을 견뎌야 하고 사용자에게 더 나은 경험을 제공해야 한다는 것은 의심의 여지가 없습니다. 이때, 웹측의 성능이 비즈니스 발전에 병목 현상이 되는 경우가 많아 성능 개선이 시급합니다. 이 기사의 저자는 개발 과정에서 웹 서버의 성능을 향상시킨 몇 가지 경험을 요약하고 이를 모든 사람과 공유했습니다.

문제 분석

웹 서버의 성능을 위해 먼저 관련 지표를 분석합니다. 사용자의 관점에서 볼 때, 사용자가 웹 서비스를 호출할 때 요청 반환 시간이 짧을수록 사용자 경험은 더 좋아집니다. 서버 관점에서 보면 동시에 처리할 수 있는 사용자 요청 수가 많을수록 서버 성능은 더욱 강력해집니다. 두 가지 측면을 결합하여 성능 최적화의 두 가지 방향을 요약합니다.

1. 서버가 지원할 수 있는 최대 동시 요청 수를 늘립니다.

2. 각 요청의 처리 속도를 향상시킵니다.

최적화 방향이 명확해졌습니다. 먼저 서버 측의 일반적인 아키텍처 패턴을 소개합니다. 즉, 브라우저나 앱의 웹 요청이 서버 측에서 여러 계층의 구조를 통해 처리되고 반환됩니다.

아키텍처 모드: IP 부하 분산->캐시 서버->역방향 프록시->응용 프로그램 서버->데이터베이스

그림 1과 같이 설명의 편의를 위해 실제적인 예를 들어보겠습니다: LVS(Keepalived)->Squid->nginx->Go->MySQL

웹 서버 성능 개선 방법그림 1: 서버 측 아키텍처

우리는 각 계층에서 요청을 분산하므로 하위 수준 구조의 여러 분기가 동시에 작동하여 전체 최대 동시성 수를 늘릴 수 있습니다.

아키텍처와 결합하여 일반적으로 성능을 방해하는 문제가 무엇인지 분석하고 그에 따른 해결 방법을 찾아보겠습니다.

일반적인 상황에서 IP 로드 밸런싱, 캐시 서버 및 nginx 프록시 계층은 주로 클러스터 안정성 문제입니다. 성능 병목 현상이 발생하기 쉬운 곳은 주로 애플리케이션 서버 계층과 데이터베이스 계층입니다. 아래에 몇 가지 예를 나열해 보겠습니다.

1. 방해의 영향

(1) 질문: 대부분의 웹 요청은 요청이 처리되면 요청이 완료될 때까지 프로세스가 일시 중지됩니다(CPU 점유). 대부분의 경우 웹 요청은 이 문제가 문제가 되지 않을 만큼 빠르게 완료됩니다. 그러나 완료하는 데 오랜 시간이 걸리는 요청(예: 대량의 데이터 또는 외부 API를 반환하는 요청)의 경우 이는 처리가 끝날 때까지 애플리케이션이 잠겨 있음을 의미하며, 이 기간 동안 다른 요청은 처리되지 않습니다. 그리고 이것이 유효하지 않다는 것은 명백합니다. 대기 시간이 낭비되고 시스템 리소스가 점유되어 우리가 감당할 수 있는 동시 요청 수에 심각한 영향을 미칩니다.

(2) 해결책:

웹 서버가 이전 요청이 처리되기를 기다리는 동안 I/O 루프를 열어 처리가 완료될 때까지 다른 애플리케이션 요청을 처리하고, 요청을 기다리는 동안 정지하는 대신 요청을 시작하고 피드백을 제공할 수 있습니다. 완료하려면 프로세스를 시작하세요. 이러한 방식으로 불필요한 대기 시간을 절약하고 이 시간을 더 많은 요청을 처리하는 데 사용할 수 있으므로 요청 처리량을 크게 늘릴 수 있습니다. 즉, 처리할 수 있는 동시 요청 수를 거시적으로 늘릴 수 있습니다.
(3) 예시

여기에서는 Python 웹 프레임워크인 Tornado를 사용하여 동시성 성능을 향상시키기 위해 차단 방법을 변경하는 방법을 구체적으로 설명합니다.

시나리오: HTTP 요청을 원격 엔드(매우 안정적인 웹사이트)로 보내는 간단한 웹 애플리케이션을 구축합니다. 이 기간 동안 네트워크 전송은 안정적이며 네트워크의 영향을 고려하지 않습니다.

이 예에서는 Siege(스트레스 테스트 소프트웨어)를 사용하여 서버에서 10초 안에 약 10개의 동시 요청을 수행합니다.

그림 2에서 볼 수 있듯이 여기서 문제는 각 요청 자체가 얼마나 빨리 반환되더라도 프로세스가 기다리지 않기 때문에 원격 엔드에 대한 서버의 왕복 액세스 요청이 충분히 큰 지연을 생성한다는 것입니다. 요청이 완료되어 데이터가 처리될 때까지 처리하기 전에는 항상 강제 정지 상태입니다. 요청이 한두 개일 경우에는 아직 문제가 되지 않지만, 사용자가 100명(또는 심지어 10명)에 도달하면 전반적인 속도가 느려지는 것을 의미합니다. 그림에서 볼 수 있듯이 10초 이내에 유사 사용자 10명의 평균 응답 시간은 1.99초로 총 29회에 이르렀습니다. 이 예에서는 매우 간단한 논리만 보여줍니다. 다른 비즈니스 로직이나 데이터베이스 호출을 추가하면 결과는 더욱 나빠집니다. 더 많은 사용자 요청이 추가되면 동시에 처리할 수 있는 요청 수가 천천히 늘어나고 일부 요청은 시간 초과되거나 실패할 수도 있습니다.

그림 2: 차단 응답웹 서버 성능 개선 방법

아래에서는 Tornado를 사용하여 비차단 HTTP 요청을 수행합니다.

그림 3에 표시된 것처럼 초당 3.20개 트랜잭션에서 12.59개로 증가하여 동일한 시간에 총 118개의 요청을 처리했습니다. 이것은 정말 큰 개선입니다! 상상할 수 있듯이 사용자 요청이 증가하고 테스트 시간이 증가함에 따라 위 버전으로 인해 발생하는 속도 저하 없이 더 많은 연결을 제공할 수 있습니다. 이로 인해 로드할 수 있는 동시 요청 수가 꾸준히 늘어납니다.
웹서버 성능개선 실습

웹 서버 성능 개선 방법

그림 3: 비차단 응답

2. 컴퓨팅 효율성이 응답 시간 및 동시 횟수에 미치는 영향

먼저 기본 지식을 소개하겠습니다. 애플리케이션은 머신에서 실행되는 프로세스이고, 프로세스는 자체 메모리 주소 공간에서 실행되는 독립적인 실행 본체입니다. 프로세스는 하나 이상의 운영 체제 스레드로 구성됩니다. 이러한 스레드는 실제로 함께 작동하고 동일한 메모리 주소 공간을 공유하는 실행 본체입니다.
(1) 질문

기존 컴퓨팅 방식은 단일 스레드에서 실행되므로 효율성이 낮고 컴퓨팅 성능도 약합니다.
(2) 솔루션

한 가지 해결책은 스레드 사용을 완전히 피하는 것입니다. 예를 들어 여러 프로세스를 사용하여 운영 체제에 대한 부담을 덜어줄 수 있습니다. 그러나 단점은 모든 프로세스 간 통신을 처리해야 한다는 점이며, 이는 일반적으로 공유 메모리 동시성 모델보다 오버헤드가 더 많습니다.

또 다른 방법은 멀티스레딩을 사용하여 작업하는 것입니다. 그러나 멀티스레딩을 사용하는 응용 프로그램은 정확성이 어렵고, 서로 다른 스레드를 동기화하고, 데이터를 잠그므로 하나의 스레드만 동시에 데이터를 변경할 수 있다는 것이 인식되어 있습니다. 시간. 그러나 과거의 소프트웨어 개발 경험에 따르면 이로 인해 복잡성이 높아지고 코드 오류가 발생하기 쉬우며 성능이 저하될 것입니다.

주요 문제는 메모리 내 데이터 공유로, 이는 여러 스레드에 의해 예측할 수 없는 방식으로 작동되어 재현 불가능하거나 무작위 결과("경합 조건"이라고 함)로 이어집니다. 따라서 이 고전적인 접근 방식은 더 이상 최신 멀티 코어/멀티 프로세서 프로그래밍에 적합하지 않습니다. 연결당 스레드 모델은 충분히 효율적이지 않습니다. 많은 적합한 패러다임 중에는 Communicating Sequential Processes(C. Hoare가 발명한 CSP)라는 패러다임과 메시지 전달 모델(Erlang과 같은 다른 언어에서 이미 사용됨)이라는 패러다임이 있습니다.

여기서 사용하는 방법은 병렬 아키텍처를 사용하여 작업을 처리하는 것입니다. 동시 프로그램은 여러 스레드를 사용하여 프로세서 또는 코어에서 작업을 수행할 수 있지만 특정 지점에서는 동일한 프로그램만 여러 코어 또는 다중 프로세서에서 실행될 수 있습니다. 실제 병렬성은 프로세서에 있습니다.

병렬성은 여러 프로세서를 사용하여 속도를 높이는 기능입니다. 따라서 동시 프로그램은 병렬일 수도 있고 아닐 수도 있습니다.

병렬 모드는 멀티 스레드, 멀티 코어, 멀티 프로세서 및 심지어 여러 컴퓨터를 동시에 사용할 수 있습니다. 이는 의심할 여지 없이 더 많은 리소스를 동원하여 응답 시간을 단축하고 컴퓨팅 효율성을 향상하며 서버 성능을 크게 향상시킬 수 있습니다. .
(3) 예시

Go 언어에서 고루틴을 사용하는 자세한 설명은 다음과 같습니다.

Go 언어에서는 애플리케이션의 동시 처리 부분을 고루틴(코루틴)이라고 부르는데, 이는 보다 효율적인 동시 작업을 수행할 수 있습니다. 코루틴과 운영 체제 스레드 사이에는 일대일 관계가 없습니다. 코루틴은 가용성에 따라 하나 이상의 스레드에 매핑(다중화, 실행)됩니다. 코루틴 스케줄러는 이 작업을 매우 잘 수행합니다. 코루틴은 스레드보다 가볍고 가볍습니다. 매우 눈에 띄지 않으며 소량의 메모리와 리소스를 사용합니다. 4K의 스택 메모리만 사용하여 힙에 생성할 수 있습니다. 만드는 비용이 매우 저렴하기 때문에 필요한 경우 많은 수의 코루틴(동일한 주소 공간에 연속된 100,000개의 코루틴)을 쉽게 만들고 실행할 수 있습니다. 그리고 스택을 나누어 메모리 사용량을 동적으로 늘리거나 줄입니다. 스택 관리는 자동이지만 가비지 수집기에 의해 관리되지는 않지만 코루틴이 종료된 후 자동으로 해제됩니다. 코루틴은 여러 운영 체제 스레드 간에 또는 스레드 내에서 실행될 수 있으므로 작은 메모리 공간으로 많은 작업을 처리할 수 있습니다. 운영 체제 스레드의 코루틴 시간 분할 덕분에 적은 수의 운영 체제 스레드를 사용하여 원하는 만큼 많은 제공 코루틴을 가질 수 있으며 Go 런타임은 어떤 코루틴이 차단되었는지 지능적으로 파악하여 보류하고 다른 작업을 처리할 수 있습니다. 코루틴. 프로그램조차도 서로 다른 프로세서와 컴퓨터에서 서로 다른 코드 세그먼트를 동시에 실행할 수 있습니다.

우리는 일반적으로 긴 계산 과정을 여러 부분으로 나누고 각 고루틴이 한 작업을 담당하게 하여 단일 요청에 대한 응답 시간을 두 배로 늘리려고 합니다.

예를 들어 3단계로 나누어진 작업이 있는데, 단계 a는 데이터베이스 a로 가서 데이터를 가져오고, 단계 b는 데이터베이스 b로 가서 데이터를 가져오고, 단계 c는 데이터를 병합하여 반환합니다. 고루틴을 시작한 후 단계 a와 b를 함께 수행할 수 있으므로 응답 시간이 크게 단축됩니다.

직접적으로 말하면, 계산 프로세스의 일부가 직렬에서 병렬로 변환됩니다. 작업은 관련 없는 다른 작업의 실행이 완료될 때까지 기다릴 필요가 없으며 실제 계산에서는 프로그램의 병렬 실행이 더 유용합니다.

여기에서는 지원 데이터 중 이 부분에 대해 너무 자세히 설명하지 않겠습니다. 관심 있는 학생들은 이 정보를 직접 확인할 수 있습니다. 예를 들어, 웹 서버가 Ruby에서 Go로 전환되었을 때 성능이 15배 향상되었다는 옛날 이야기(Ruby는 녹색 스레드를 사용합니다. 즉, 하나의 CPU만 사용합니다). 이 이야기는 다소 과장되었을 수 있지만 병렬 처리로 인해 성능이 향상된다는 점에는 의심의 여지가 없습니다. (Ruby가 Go로 전환: http://www.vaikan.com/how-we-went-from-30-servers-to-2-go/).

3. 디스크 I/O가 성능에 미치는 영향

(1) 질문

디스크에서 데이터를 읽는 것은 기계적 움직임에 따라 달라집니다. 데이터를 읽을 때마다 소요되는 시간은 탐색 시간, 회전 지연, 전송 시간의 세 부분으로 나눌 수 있습니다. 탐색 시간은 자기 팔이 이동하는 데 필요한 시간을 나타냅니다. 시간, 메인스트림 디스크는 일반적으로 5ms 미만입니다. 회전 지연은 우리가 자주 듣는 디스크 속도입니다. 예를 들어, 7200rpm의 디스크는 분당 7200회 회전할 수 있음을 의미합니다. 회전 지연은 1/120/2 = 4.17ms입니다. 전송 시간은 디스크에서 읽거나 디스크에 데이터를 쓰는 데 걸리는 시간을 의미하며 일반적으로 10분의 1초로 처음 두 번에 비해 무시할 수 있습니다. 그러면 디스크에 액세스하는 시간, 즉 디스크 I/O에 액세스하는 시간은 약 9ms(5ms+4.17ms)인데 꽤 괜찮은 것 같지만 500-MIPS 머신이 5억 개의 항목을 실행할 수 있다는 것을 알아야 합니다. 즉, 하나의 I/O를 실행하는 데 400,000개의 명령이 필요하기 때문입니다. 데이터베이스에는 종종 수십만, 수백만 또는 수천만 개의 데이터가 포함되며, 매번 실행될 때마다 9밀리초가 걸리면 이는 분명히 재앙입니다.
(2) 솔루션

디스크를 버리고 다른 것으로 교체하지 않는 한, 디스크 I/O가 서버 성능에 미치는 영향에 대한 근본적인 해결책은 없습니다. 다양한 저장 매체의 응답 속도와 가격을 온라인으로 검색할 수 있습니다. 돈이 있으면 저장 매체를 마음대로 변경할 수 있습니다.

저장 매체를 변경하지 않고도 캐시 설정 등 애플리케이션의 디스크 액세스 횟수를 줄일 수 있으며, 큐 및 스택을 사용하여 데이터를 처리하는 등 일부 디스크 I/O를 요청 주기 외부에 배치할 수도 있습니다. /O 등.

4. 데이터베이스 쿼리 최적화

비즈니스 개발 모델이 변경되면서 점점 더 많은 팀이 애자일 개발을 채택하고 있으며 주기가 점점 짧아지고 있습니다. 많은 데이터베이스 쿼리 문이 비즈니스 로직에 따라 작성되면서 SQL 쿼리 형식이 무시되는 경우가 많습니다. . 문제로 인해 데이터베이스에 대한 부담이 증가하고 데이터베이스 쿼리에 대한 응답 속도가 느려집니다. 다음은 MySQL 데이터베이스에서 무시했던 몇 가지 일반적인 문제와 최적화 방법에 대한 간략한 소개입니다.

가장 왼쪽 접두사 일치 원칙은 매우 중요한 원칙입니다. MySQL은 범위 쿼리(>, 3이고 d = 4 (a, b, c, d) 순서로 인덱스를 생성하면 d는 (a, b, d, c)에 인덱스를 생성하면 해당 인덱스를 사용하지 않습니다. , a와 b를 모두 사용할 수 있으며 d의 순서는 임의로 조정할 수 있습니다.
구별도가 높은 열을 인덱스로 선택하세요. 구별 공식은 반복되지 않는 필드의 비율을 나타내는 count(distinct col)/count(*)입니다. 고유 키의 수는 1입니다. 일부 상태 및 성별 필드는 빅 데이터 앞에서 0으로 구분될 수 있습니다. 그러면 누군가 이 비율이 실증적인 가치가 있는지 물을 수 있습니다. 다양한 사용 시나리오로 인해 이 값을 결정하기가 어렵습니다. 일반적으로 조인해야 하는 필드는 0.1 이상이어야 합니다. 즉, 하나당 평균 10개의 레코드가 검색됩니다.
숫자 필드를 사용해 보십시오. 필드에 숫자 정보만 포함되어 있으면 문자 필드로 디자인하지 마십시오. 그러면 쿼리 및 연결 성능이 저하되고 저장 공간 오버헤드가 늘어납니다. 엔진은 쿼리 및 연결 처리 시 문자열의 각 문자를 하나씩 비교하는데, 숫자 유형의 경우 한 번의 비교만으로 충분하기 때문입니다.
인덱스 열은 계산에 참여할 수 없습니다. 예를 들어 from_unixtime(create_time) = '2014-05-29'인 경우 b+ 트리가 필드 값을 저장하는 이유는 매우 간단합니다. ​​​데이터 테이블에 있지만, 검색할 때 비교할 모든 요소에 함수를 적용해야 하는데 이는 비용이 너무 많이 듭니다. 따라서 명령문은 다음과 같이 작성해야 합니다.
다음과 같이 인덱스를 사용하여 전체 테이블 스캔을 수행합니다.

num이 null인 t에서 ID를 선택하세요

num에 기본값 0을 설정하고 테이블의 num 열에 null 값이 없는지 확인한 후 다음과 같이 쿼리할 수 있습니다.

num=0
인 t에서 ID를 선택하세요. 조건을 연결하기 위해 where 절에 또는 를 사용하지 마십시오. 그렇지 않으면 엔진이 인덱스 사용을 포기하고 다음과 같이 전체 테이블 스캔을 수행합니다.
num=10 또는 num=20
인 t에서 ID를 선택하세요. 다음과 같이 쿼리할 수 있습니다.

num=10인 t에서 ID 선택 모두 num=20인 t에서 ID 선택
다음 쿼리는 전체 테이블 스캔(선행 백분율 기호 없음)을 발생시킵니다.
이름이 '%abc%'와 같은 t에서 ID를 선택하세요
효율성을 높이려면 전체 텍스트 검색을 고려하세요.
In과 Not in도 주의해서 사용해야 합니다. 그렇지 않으면 다음과 같이 전체 테이블 스캔이 발생합니다.
숫자가 (1,2,3)인 t에서 ID를 선택하세요
연속 값의 경우 다음 사이에 사용할 수 있으면 in을 사용하지 마세요.
1에서 3 사이의 숫자가 있는 t에서 ID를 선택하세요

위 내용은 웹 서버 성능 개선 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 linuxprobe.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제