php5 + MySQL을 초당 200 회 이상 요청하는 방법은 무엇입니까?


16

나는 홈페이지를 성능 조정을 위해 조정하고 있으며, 현재 3.14.by에서 약 200 개의 요청을 처리하여 6 개의 SQL 쿼리를 사용하고 3.14.by/forum에서 20 req / second를 phpBB 포럼입니다.

이상하게도 일부 VPS 및 전용 Atom 330 서버에서 숫자는 거의 같습니다.

서버 소프트웨어는 다음과 같습니다 : Apache2 + mod_php prefork 4 개의 자식 (여기서 다른 숫자를 시도), php5, APC, nginx, PHP 세션 저장을위한 memcached.

MySQL은 사용 가능한 RAM의 약 30 %를 소비하도록 구성됩니다 (VPS에서 ~ 150Mb, 전용 서버에서 700Mb)

이것은 어딘가에 병목 현상이있는 것 같습니다. 어떤 제안도 있습니까? (즉, 6 개 미만의 SQL을 수행하면 더 빠를 수 있지만 sqld는 캐시 된 쿼리로 인해 최상위 %를 몇 % 이상 먹지 않으므로 제한 요소처럼 보이지 않습니다)

누구든지 preforked apache2를 차고 nginx + php를 떠나는 것이 훨씬 빠르다는 것을 테스트 했습니까?

더 많은 벤치 마크

Small 40-byte static file: 1484 r/s via nginx+apache2, 2452 if we talk to apache2 directly. 
Small "Hello world" php script: 458 r/s via ngin+apache2.

업데이트 : 병목 현상은 캐시 된 데이터의 MySQL 성능으로 나타납니다. 단일 SQL이 포함 된 페이지는 354req / sec를 표시하고 6 개의 SQL은-180 req / sec입니다. 내가 여기서 조정할 수 있다고 생각하십니까? (MySQL의 경우 100-200Mb를 포크 아웃 할 수 있음)

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
default-character-set=cp1251
collation-server=cp1251_general_cs

skip-character-set-client-handshake

user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
skip-external-locking

bind-address        = 127.0.0.1

key_buffer      = 16M
max_allowed_packet  = 8M
thread_stack        = 64K
thread_cache_size   = 16
sort_buffer_size    = 8M
read_buffer_size    = 1M

myisam-recover      = BACKUP
max_connections        = 650
table_cache            = 256
thread_concurrency     = 10

query_cache_limit       = 1M
query_cache_size        = 16M

expire_logs_days    = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet  = 8M

[mysql]
[isamchk]
key_buffer      = 8M

!includedir /etc/mysql/conf.d/

왜 Apache와 nginx를 모두 사용하고 있습니까?
jamieb

이는 일반적인 구성, Apache2에서 PHP 및 아파치 인프라를 필요로하는 다양한 앱,로드시 아파치 2 메모리 풋 프린트를 줄이기위한 nginx입니다.
BarsMonster

사실, 나는 당신의 문제를 이해하지 못합니다. 귀하의 사이트가 현재 느린가요? 그렇다면 얼마나 느립니까? 그리고 속도를 얼마나 높이고 싶습니까? 병목 현상의 위치를 ​​파악하기 위해 사이트의 일부를 프로파일 링하려고 했습니까?
jamieb

설명에 있습니다 : 이제 180-200 요청 / 초입니다. 이것이 홈페이지에는 충분하지만 동일한 코드베이스로 작성된 다른 사이트가 더 빨리 작동하도록이 설정을 조정하고 싶습니다. 이상적으로 동적 페이지로 100Mbit 연결을 포화시키고 싶습니다 :-)
BarsMonster

2
"초당 요청 수"는이 맥락에서 실제로 의미있는 지표가 아닙니다. 내 넷북은 "초당 200 개의 요청"을 처리 할 수 ​​있습니다. 이러한 연결 속도에서 원하는 응답 시간을 알려주십시오.
jamieb

답변:


29

분명히, 당신이 시도 할 수있는 많은 것이 있습니다. 최선의 방법은 인덱스를 사용하지 않는 쿼리 (그에 대한 로그 사용) 및 최적화되지 않은 다른 쿼리에 대한 로그를 추적하는 것입니다. 나는 수년간 성능 관련 옵션의 거대한 목록을 작성 했으므로 귀하의 정보에 대한 작은 하위 집합을 여기에 포함 시켰습니다. 시도해 볼 수있는 일반적인 참고 사항은 다음과 같습니다 (아직하지 않은 경우).

MySQL

  • query_cache_type = 1-캐시 SQL 쿼리가 켜져 있습니다. 2로 설정하면 SQL_CACHE 힌트가 전달 된 경우에만 쿼리가 캐시됩니다. 유형 1과 마찬가지로 SQL_NO_CACHE 힌트를 사용하여 특정 쿼리에 대해 캐시를 비활성화 할 수 있습니다
  • key_buffer_size = 128M (기본값 : 8M)-MyISAM 테이블 인덱스를위한 메모리 버퍼. 전용 서버에서 key_buffer_size를 서버의 총 메모리 양의 1/4 이상으로 절반 이하로 설정하십시오.
  • query_cache_size = 64M (기본값 : 0)-쿼리 캐시 크기
  • back_log = 100 (기본값 : 50, 최대 : 65535)-미해결 연결 요청 대기열. 단시간에 많은 연결이있을 때만 중요
  • join_buffer_size = 1M (기본값 : 131072)-전체 테이블 스캔 (인덱스 없음)이있을 때 사용되는 버퍼
  • table_cache = 2048 (기본값 : 256)-max_user_connections에 가장 큰 SQL 쿼리에 포함 된 최대 JOIN 수를 곱해야합니다. 피크 시간에는 "open_tables"변수를 지침으로 사용하십시오. 또한 "opened_tables"변수를보십시오- "open_tables"에 가까워 야합니다
  • query_prealloc_size = 32K (기본값 : 8K)-구문 분석 및 실행을위한 영구 메모리. 복잡한 쿼리가있는 경우 증가
  • sort_buffer_size = 16M (기본값 : 2M)-정렬을 도와줍니다 (ORDER BY 및 GROUP BY 작업)
  • read_buffer_size = 2M (기본값 : 128K)-순차적 스캔에 도움이됩니다. 순차적 스캔이 많은 경우 늘리십시오.
  • read_rnd_buffer_size = 4M-정렬 후 MyISAM 테이블의 읽기 속도 향상
  • max_length_for_sort_data-정렬 파일에서 행 포인터 대신 저장할 행 크기 임의의 테이블 읽기를 피할 수 있습니다
  • key_cache_age_threshold = 3000 (기본값 : 300)-키 캐시를 핫존에 보관하는 시간 (가열하기 전에)
  • key_cache_division_limit = 50 (기본값 : 100)-보다 정교한 캐시 제거 메커니즘을 활성화합니다 (2 단계). 최저 수준으로 유지할 비율을 나타냅니다. delay_key_write = ALL-모든 인덱스 업데이트에서 테이블에 대해 키 버퍼가 플러시되지 않고 테이블이 닫힐 때만 해당됩니다. 이렇게하면 키 쓰기 속도가 크게 향상되지만이 기능을 사용하는 경우 --myisam-recover = BACKUP, FORCE 옵션으로 서버를 시작하여 모든 MyISAM 테이블의 자동 검사를 추가해야합니다.
  • memlock = 1-메모리에서 프로세스 잠금 (스왑 인 / 아웃 감소)

아파치

  • 스폰 방법 변경 (예 : mpm)
  • 가능하면 로그 비활성화
  • AllowOverride 없음-가능할 때마다 .htaccess를 비활성화합니다. 사용하지 않으면 .htaccess 파일을 찾기 위해 아파치를 중지하므로 파일 조회 요청을 저장합니다.
  • SendBufferSize-OS 기본값으로 설정합니다. 혼잡 한 네트워크에서는이 매개 변수를 일반적으로 다운로드 한 가장 큰 파일의 크기에 가깝게 설정해야합니다
  • KeepAlive Off (기본값 On)-네트워크 연결을 올바르게 닫고 더 빠른 속도로 lingerd를 설치하십시오.
  • DirectoryIndex index.php-파일 목록을 가능한 짧고 절대적으로 유지하십시오.
  • 옵션 FollowSymLinks-Apache에서 파일 액세스 프로세스를 단순화
  • mod_rewrite 또는 최소한 복잡한 정규식 사용을 피하십시오
  • ServerToken = 제품

PHP

  • variables_order = "GPCS"(환경 변수가 필요하지 않은 경우)
  • register_globals = 끄기-보안 위험이 아니라 성능에 영향을 미칩니다
  • include_path를 가능한 최소한으로 유지하십시오 (추가 파일 시스템 조회는 피하십시오)
  • display_errors = 끄기-오류 표시를 비활성화합니다. 모든 프로덕션 서버에 강력히 권장됩니다 (문제 발생시 추악한 오류 메시지가 표시되지 않음).
  • magic_quotes_gpc = 해제
  • magic_quotes _ * = 끄기
  • output_buffering = 켜기
  • 가능하면 로깅 비활성화
  • expose_php = 끄기
  • register_argc_argv = 해제
  • always_populate_raw_post_data = 끄기
  • php.ini 파일을 php가 먼저 찾을 위치에 배치하십시오.
  • session.gc_divisor = 1000 또는 10000
  • session.save_path = "N; / path"-대규모 사이트의 경우 사용을 고려하십시오. 세션 파일을 하위 디렉토리로 분할

OS 비틀기

  • 사용 된 하드 디스크를 -o noatime 옵션 (액세스 시간 없음)으로 마운트하십시오. 또한이 옵션을 / etc / fstab 파일에 추가하십시오.
  • / proc / sys / vm / swappiness (0에서 100까지)를 조정하여 최상의 결과가 무엇인지 확인하십시오.
  • RAM 디스크 사용-mount --bind -ttmpfs / tmp / tmp

그것은 좋은 목록입니다, 나는 이미 이것들의 대다수를 가졌으며, 나머지 것들을 추가했을 때 성능은 향상되지 않았습니다. 병목 현상은 PHP와 MySQL 사이에서 쿼리 캐시에서 초당 800 개 이상의 요청을 처리 할 수없는 것처럼 보입니다.
BarsMonster

좋아, 어떻게 데이터베이스에 연결합니까 (mysql_connect () 대신 mysql_pconnect ())? 영구 연결을 사용합니까? 두 가지 방법 모두 시도 ...
Ivan Peevski

나는 이미 pconnect에 있고 연결 풀링은 php.ini에서 활성화되어 있습니다 ... : -S
BarsMonster

완전 함을 위해 연결을 시도합니다. 나는 그것이 더 잘 수행되는 경우 (특히로드 테스트에서)를 보았습니다.
Ivan Peevski

1

병목 현상이 CPU가 아닌 경우 IO는 네트워크 또는 디스크입니다. 그래서 .. 당신은 얼마나 많은 IO가 진행되고 있는지 볼 필요가 있습니다. 나는 네트워크를 생각하지 않았을 것입니다 (10mbps 반이중 링크를 사용하지 않는 한 자동 감지가 제대로 작동하지 않는 경우 스위치를 확인하는 것이 좋습니다).

디스크 IO가 남게되는데 이는 특히 VPS에서 큰 요소가 될 수 있습니다. sar 또는 iostat를 사용하여 디스크를 살펴본 다음 디스크를 많이 사용하는 경우 자세한 정보를 찾는 방법을 Google에 찾으십시오.


예, 네트워크에는 문제가 없습니다. 로컬 서버에서 ab를 실행할 때 성능은 동일합니다. iowait 시간을 확인했습니다-0.01 % 미만입니다. 기본적으로 모든 것이 디스크 캐시에 있으며 요청 처리와 관련된 디스크 쓰기가 없습니다 (모든 로그가 비활성화되어 있음).
BarsMonster

1

Nginx ( memcached ) 또는 Varnish 를 사용하여 캐싱을 조사합니다 .

최소한 SaveTheRbtz와 같이 Nginx를 사용하여 정적 파일을 서버에 저장해야합니다.


이들은 동적 페이지이므로 캐시하지 않는 것이 좋습니다.
BarsMonster

1
memcached는 전통적인 캐싱 앱이 아니며 동적 페이지에서 놀라운 일을 할 수 있습니다. DB와 앱 사이에 있습니다. 앱은 먼저 객체에 대해 memcached를 쿼리합니다. 객체가 없으면 DB에서로드됩니다. 결과적으로 DB에서 훨씬 느린 영구 스토리지가 아닌 RAM을 사용하여 DB 요청을 처리하는 것입니다.
jamieb

Memcache는 알려진 기능인 nginx와 함께 사용할 수 있습니다. 느린 영구 저장소는 사용되지 않으며 MySQL의 쿼리 캐시에 모두 있습니다.
BarsMonster

Memcached와 MySQL의 쿼리 캐시는 실제로 비교할 수 없습니다. 그들은 똑같은 일조차하지 않습니다. 여기에 게시 된 모든 제안을 이해하기 위해 귀찮게하지 않고 꽤 빨리 처리 할 수 ​​있습니다. 좀 더 열린 마음을 갖는 것이 좋습니다.
jamieb

memcached와 MySQL 쿼리 캐시의 차이점을 분명히 이해합니다. 그러나 모든 것이 100 % 적중률로 쿼리 캐시에 있다는 사실 때문에 "느린 영구 저장 장치"라고 부르지 않습니다. 어제의 원래 대답은 전체 페이지를 캐시하는 일반적인 시나리오 인 NginX + Memcached를 사용하는 것에 관한 것입니다. 개별 객체 캐싱은 완전히 다른 시나리오입니다. MySQL 앞에서 memcached를 사용하는 것이 표에 있지만 지금은 많은 코드 변경이 필요하기 때문에 더 많은 주스를 얻는 것에 대해 생각하고 있습니다.
BarsMonster 5

1

서버에 문제가없는 것 같으므로로드 생성기가 문제 일 수 있습니다. 여러 컴퓨터에서 실행하십시오.


서버 자체에서 실행해도 성능은 같습니다. manu 동시 연결 방식 (10 또는 50)에 관계없이로드 테스트는 ab -c 10 -t 10을 통해 수행됩니다.
BarsMonster

1

Apache가 허용하는 최대 연결 수에 도달 한 것 같습니다. Apache 구성을 살펴보십시오. 서버 제한 및 최대 클라이언트를 늘리면 I / O 또는 메모리와 같은 다른 제한에 아직 구속되지 않은 경우 도움이됩니다. mpm_prefork_module 또는 mpm_worker_module의 값을보고 필요에 맞게 적절히 조정하십시오.

서버 제한 512
MaxClients 512

아파치 2 앞에 nginx가 있다면 이것을 정말로 필요로하므로 물리적 코어 * 2 아파치 2 프로세스보다 더 많은 것은 없다고 생각합니다 ....
BarsMonster

이것을 확인했습니다. Apache2 프로세스 수를 4에서 16으로 늘려도 성능이 전혀 향상되지는 않았습니다 (0.5 % 감소). nginx 작업자 수를 2 또는 4로 늘려도 아무런 개선이 없었습니다.
BarsMonster

1
데이터가 상당히 정적 인 경우 (즉, 다른 모든 페이지로드를 업데이트하지 않는 경우) query_cache를 늘릴 수 있습니다. MySQL은 그런 식으로 결과 집합을 잡고 메모리에서 가져옵니다. 그러나 캐시되는 테이블이 해당 시간 동안 쓰기를 수신하면 데이터에 영향을 미치지 않더라도 캐시를 무효화하여 메모리를 낭비합니다.
Erik Giberti

지금은 100 % 쿼리 캐시 적중률을보고, MySQL은 ... 느린 여전히 느낌
BarsMonster

1
MySQL 구성 파일에 skip-name-resolve를 추가하십시오. 그러면 서버에 대한 모든 연결에서 DNS 조회가 저장됩니다. 여기서 단점은 모든 연결을 IP로 잠 가야한다는 것입니다 ( '%'를 사용하지 않는 경우). SQL이 동일한 서버에 있고 localhost 이외의 다른 곳에 액세스 할 필요가없는 경우 skip-networking을 추가하여 전체 TCP / IP 스택을 종료 할 수도 있습니다. 그러나 병목 현상은 Apache라고 생각합니다.
Erik Giberti

0

이 하중은 공구 또는 실제 하중에 의해 생성됩니까?

memcached를 확인하고 싶을 수도 있습니다. 높은 연결 속도에서 문제가 발생하여 응용 프로그램에서 대기 시간이 발생했습니다.

로드 생성기를 사용하는 경우 작은 정적 페이지를 칠 때 얻는 결과는 무엇입니까?

로드하는 동안 TIME_WAIT 조건에 대한 네트워크 스택을 점검 할 수 있습니다. 아마도 연결 대기열을 채우고있을 것입니다.

당신이 볼 수있는 약 100 가지 이유와 항목이 있지만 더 많은 정보가 없다면, 나는이 시점에서 추측을 던지고 있습니다.


서버 자체에서 벤치마킹하는 ab-c 10 -t 10 URL을 통해 테스트되었으므로 네트워크에 문제가 없어야합니다. 귀하의 요청에 따라 더 많은 벤치 마크를 게시했습니다.
BarsMonster

나는 ab로 튜닝하는 데 너무 많은 노력을 기울이지 않을 것입니다. 실제 성능으로 제대로 변환되지 않을 수도 있습니다. 당신이하고 싶은 일은 앱을 분석하고 각 구성 요소를 테스트하는 것입니다. 예를 들어 아주 작은 정적 페이지만으로 아파치 서버를 직접 누르십시오. 백엔드에서 최대 요청 / 초에 대한 정보를 얻을 수 있습니다. nginx를 앞에두고 동일한 백엔드 파일을 호출하여 다시 테스트하십시오. 그런 다음 간단한 "hello world"유형의 PHP 페이지로 테스트하십시오. 때로는 모든 레이어가 간단한 것을 숨길 수 있습니다. 또한 테스트 중에 연결을 확인하십시오. 네트워크 스택이 가득 차지 않았는지 확인하십시오.
jeffatrackaid

어제 이러한 벤치 마크를 수행했으며 업데이트 된 원래 질문 설명에 있습니다. 또한 로컬 호스트에서 테스트를 수행하므로 네트워크에 문제가 없습니다.
BarsMonster

로컬 호스트에서 수행하더라도 네트워크가 문제가 될 수 있습니다. 귀하의 경우는 아니지만 문제가 발생할 수 있습니다. 적어도 현재 PHP 설정에서 ~ 450 req / sec의 상한선이 없습니다. 다음 단계는 데이터베이스 호출을 삭제하고 변경 내용을 확인하는 것입니다. 높은 수준의 튜닝을 수행 할 때이 문제를 해결하는 것이 가장 문제가되는 레이어를 정확히 찾아내는 데 도움이 될 수 있습니다.
jeffatrackaid

-1

이와 같은 시간 문제의 99 %%가 데이터베이스로 추적됩니다. 타격 지수를 먼저 확인하십시오. 그래도 작동하지 않으면 가능한 모든 것을 캐싱하기 시작하십시오.


모든 인덱스이며 제가 말한 것처럼 100 % 사례에서 MySQL 쿼리 캐시에 도달합니다
BarsMonster

-1

가능한 경우 연결 풀러를 사용하여 데이터베이스를 웹 응용 프로그램에 연결 한 상태로 유지하십시오 (각 요청에서 다시 연결하지 않아도 됨). 그것은 속도의 큰 차이를 만들 수 있습니다.

또한 EXPLAIN을 사용하여 모든 쿼리를 분석하십시오 (또한 SHOW PROFILE?


모든 쿼리는 인덱스를 사용합니다. MySQL 연결 풀이 사용됩니다.
BarsMonster
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.