source

PHP/MySQL 응용 프로그램에서 멀티코어 CPU를 어떻게 잘 활용합니까?

lovecheck 2023. 9. 14. 23:19
반응형

PHP/MySQL 응용 프로그램에서 멀티코어 CPU를 어떻게 잘 활용합니까?

저는 맞춤형 CMS와 같은 애플리케이션을 유지하고 있습니다.

문서가 제출될 때마다 몇 가지 작업이 수행되며, 이 작업은 대략 다음 범주로 분류될 수 있습니다.

  1. MySQL 쿼리.
  2. HTML 내용 구문 분석.
  3. 인덱스 검색 업데이트 중입니다.

카테고리 1은 문서 내용과 관련된 다양한 MySQL 테이블 업데이트를 포함합니다.

카테고리 2는 MySQL LONGTEXT 필드에 저장된 HTML 컨텐츠를 파싱하여 일부 자동 앵커 태그 변환을 수행하는 것을 포함합니다.저는 이 작업에 많은 계산 시간이 소요된다고 생각합니다.

카테고리 3에는 문서에 해당하는 몇 개의 필드만 사용하는 간단한 MySQL 기반 검색 인덱스 업데이트가 포함됩니다.

문서 제출이 완료된 것으로 간주되기 위해서는 이 모든 작업이 완료되어야 합니다.

이 애플리케이션을 호스팅하는 시스템에는 듀얼 쿼드코어 Xeon 프로세서(총 8개 코어)가 있습니다.그러나 문서가 제출될 때마다 실행되는 모든 PHP 코드는 코어 중 하나에서 실행되는 단일 프로세스로 제한됩니다.

질문:

여러 CPU 코어 간에 PHP/MySQL 웹 애플리케이션 처리 로드를 분할할 때 사용한 계획은 무엇입니까?제 이상적인 솔루션은 기본적으로 몇 개의 프로세스를 생성하여 여러 코어에서 병렬로 실행한 다음 모든 프로세스가 완료될 때까지 차단하는 것입니다.

관련 질문:

당신이 가장 좋아하는 PHP 성능 프로파일링 도구는 무엇입니까?

서론

PHP는 여러 가지 면에서 충분히 활용할 수 있는 완벽한 멀티스레딩 지원 기능을 갖추고 있습니다.다양한 예에서 이러한 멀티스레딩 기능을 입증할 수 있었습니다.

빠른 검색을 통해 추가 리소스를 얻을 수 있습니다.

분류

1: MySQL 쿼리

MySQL은 완전히 멀티 스레드이며 운영 체제가 CPU를 지원할 경우 여러 CPU를 사용하게 되며, 성능을 위해 적절하게 구성된 경우 시스템 리소스를 최대화할 수 있습니다.

의 인 입니다 의 일반적인 입니다.my.ini스레드 성능에 영향을 미치는 요소는 다음과 같습니다.

thread_cache_size = 8

새 연결이 많은 경우 thread_size를 늘려 성능을 향상시킬 수 있습니다.일반적으로 스레드를 잘 구현한 경우에는 성능이 눈에 띄게 향상되지 않습니다.그러나 서버에서 초당 수백 개의 연결이 나타나는 경우 대부분의 새 연결이 캐시된 스레드를 사용하도록 thread_cache_size를 충분히 높게 설정해야 합니다.

Solaris를 사용하는 경우 다음을 사용할 수 있습니다.

thread_concurrency = 8 

thread_currency를 사용하면 응용 프로그램이 동시에 실행해야 하는 스레드 수에 대한 힌트를 스레드 시스템에 제공할 수 있습니다.

이 변수는 MySQL 5.6.1에서 더 이상 사용되지 않으며 MySQL 5.7에서는 제거됩니다.Solaris 8 이전 버전이 아닌 경우에는 MySQL 구성 파일에서 이 파일을 제거해야 합니다.

InnoDB: :

Innodb를 사용하는 경우에는 스레드 동시성을 완전히 지원하므로 스토리지 엔진이 있습니다.

innodb_thread_concurrency //  Recommended 2 * CPUs + number of disks
 

볼 수도 있습니다.innodb_read_io_threads그리고.innodb_write_io_threads입니다.4 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ, 64

기타:

외에도 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ,key_buffer_size,table_open_cache,sort_buffer_size 더 를 내는.

PHP:

순수 PHP에서는 각 쿼리가 개별 PHP 스레드에서 실행되는 MySQL Worker를 만들 수 있습니다.

$sql = new SQLWorker($host, $user, $pass, $db);
$sql->start();

$sql->stack($q1 = new SQLQuery("One long Query")); 
$sql->stack($q2 = new SQLQuery("Another long Query"));

$q1->wait(); 
$q2->wait(); 
             
// Do Something Useful

SQLWorker의 전체 작동 예는 다음과 같습니다.

2: HTML 컨텐츠 파싱

저는 이 작업에 많은 계산 시간이 소요된다고 생각합니다.

문제를 이미 알고 있다면 이벤트 루프, 작업 대기열 또는 스레드 사용을 통해 쉽게 해결할 수 있습니다.

한 번에 하나씩 문서 작업을 하는 것은 매우 느리고 고통스러운 과정일 수 있습니다.@ka는 ajax를 사용하여 여러 요청을 호출하는 방법을 해킹한 적이 있습니다. 일부 크리에이티브 마인드는 pcntl_fork를 사용하여 프로세스를 포크할 것입니다. 하지만 만약 당신이 사용하고 있다면.windows면을할수다은다수feetn할u면은n을f pcntl

와 함께pThreads윈도우와 유닉스 시스템을 모두 지원하기 때문에 제한이 없습니다.아주 쉽습니다.100개의 문서를 파싱해야 한다면요?스레드를 합니다... 100개의 스레드를 합니다.드성개성.드...요.

HTML 검색

// Scan my System
$dir = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$dir = new RecursiveIteratorIterator($dir);

// Allowed Extension
$ext = array(
        "html",
        "htm"
);

// Threads Array
$ts = array();

// Simple Storage
$s = new Sink();

// Start Timer
$time = microtime(true);

$count = 0;
// Parse All HTML
foreach($dir as $html) {
    if ($html->isFile() && in_array($html->getExtension(), $ext)) {
        $count ++;
        $ts[] = new LinkParser("$html", $s);
    }
}

// Wait for all Threads to finish
foreach($ts as $t) {
    $t->join();
}

// Put The Output
printf("Total Files:\t\t%s \n", number_format($count, 0));
printf("Total Links:\t\t%s \n", number_format($t = count($s), 0));
printf("Finished:\t\t%0.4f sec \n", $tm = microtime(true) - $time);
printf("AvgSpeed:\t\t%0.4f sec per file\n", $tm / $t);
printf("File P/S:\t\t%d file per sec\n", $count / $tm);
printf("Link P/S:\t\t%d links per sec\n", $t / $tm);

산출량

Total Files:            8,714
Total Links:            105,109
Finished:               108.3460 sec
AvgSpeed:               0.0010 sec per file
File P/S:               80 file per sec
Link P/S:               907 links per sec

사용된 클래스

Sink

class Sink extends Stackable {
    public function run() {
    }
}

LinkParser

class LinkParser extends Thread {

    public function __construct($file, $sink) {
        $this->file = $file;
        $this->sink = $sink;
        $this->start();
    }

    public function run() {
        $dom = new DOMDocument();
        @$dom->loadHTML(file_get_contents($this->file));
        foreach($dom->getElementsByTagName('a') as $links) {
            $this->sink[] = $links->getAttribute('href');
        }
    }
}

실험.

파싱 중 8,714는들이 있는 파일105,109실이 없는 링크와 시간을 확인할 수 있습니다.

더 나은 건축

실을 너무 많이 뿌리는 것은 생산에서 현명한 일이 아닙니다.Pooling을 사용하는 것이 더 나은 방법일 것입니다.정의된 작업자 풀을 가진 다음 a로 스택합니다.Task

성능향상

좋아요, 위의 예는 여전히 개선될 수 있습니다.시스템이 단일 스레드에서 모든 파일을 검색할 때까지 기다리지 않고 여러 스레드를 사용하여 시스템에서 파일을 검색한 다음 Workers에 데이터를 쌓아 처리할 수 있습니다.

3: 검색 인덱스 업데이트

이것은 첫 번째 답변으로 거의 답을 얻었지만, 성능 향상을 위한 방법은 매우 많습니다.이벤트 기반 접근 방식을 고려해 본 적이 있습니까?

이벤트 소개하기

@rdlowrey 인용문 1:

이런 식으로 생각해보세요.웹 애플리케이션에서 동시에 연결된 10,000개의 클라이언트를 서비스해야 한다고 생각해 보십시오.기존의 요청당 스레드 또는 요청당 프로세스 서버는 스레드가 아무리 가벼워도 한 번에 10,000개의 스레드를 열 수 없기 때문에 선택 사항이 아닙니다.

@rdlowrey 인용문 2:

반면에 모든 소켓을 단일 프로세스에 보관하고 해당 소켓이 읽기 가능하거나 쓰기 가능해지도록 청취하면 전체 서버를 단일 이벤트 루프 안에 넣고 읽기/쓰기 작업이 있을 때만 각 소켓에서 작동할 수 있습니다.

요 요 으로 실험해 보는 것은 event-driven,non-blocking I/O당신의 문제에 접근합니다.PHP는 당신의 어플리케이션을 과금하기 위한 라이브 이벤트를 가지고 있습니다.

이 질문이 전부라는 것을 압니다.Multi-Threading하지만 시간이 있다면 @igorw에 의해 PHP로 쓰여진원자로를 볼 수 있습니다.

마침내.

고려 사항

제 생각에는 당신이 사용하는 것을 고려해야 할 것 같습니다.Cache그리고.Job Queue당신의 몇몇 일들을 위해서요.당신은 쉽게 다음과 같은 메시지를 가질 수 있습니다.

Document uploaded for processing ..... 5% - Done   

그런 다음 모든 시간을 낭비하는 작업을 백그라운드에서 수행합니다.유사한 사례 연구를 위해 대규모 처리 작업을 더 작게 만드는 방법을 검토하십시오.

프로파일링

프로파일링 도구?Xdebug부터 Yslow까지 웹 애플리케이션을 위한 단일 프로파일 도구는 모두 매우 유용합니다.예: Xdebug는 지원되지 않기 때문에 스레드에 관해서는 유용하지 않습니다.

마음에 드는 것이 없습니다.

PHP는 멀티스레딩을 지향하지 않습니다. 이미 알아차렸다시피 각 페이지는 데이터베이스 서버에서 SQL 쿼리가 실행되는 동안 "대기"하는 것을 포함하여 한 번에 한 가지 작업을 수행하는 하나의 PHP 프로세스에 의해 제공됩니다.

유감스럽게도 PHP가 작동하는 방식이기 때문에 대해 당신이 할 수 있는 것은 많지 않습니다.


불구하고 가지 :,.

  • 우선, 서버에 한 번에 한 명 이상의 사용자가 있을 수 있습니다. 즉, 여러 페이지를 동시에 제공하게 되며, 여러 PHP 프로세스와 SQL 쿼리를 동시에 실행할 수 있다는 의미입니다.서버의 여러 코어가 사용됨을 의미합니다.
    • 각 PHP 프로세스는 한 사용자의 요청에 따라 하나의 코어에서 실행되지만 병렬로 실행되는 Apache의 여러 하위 프로세스가 있습니다(구성에 따라 요청마다 하나씩 수십 또는 수백 개까지 가능).
    • MySQL 서버는 다중 스레드이므로, 각 요청을 하나 이상의 코어에서 처리할 수 없더라도 여러 개의 개별 코어를 사용하여 여러 개의 동시 요청에 응답할 수 있습니다.

따라서 실제로 서버의 8개 코어가 사용되게 됩니다 ;-)


생성에 오래 걸린다고 을 두그룹으로 입니다. 즉, Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ

  • 한편, 페이지를 생성하기 위해 해야 할 일들: 그것들에 대해, 당신이 할 수 있는 것은 많지 않습니다.
  • 반면에, 때때로 실행되어야 하는 것들, 그러나 반드시 즉시 실행되어야 하는 것은 아닙니다.
    • 예를 들어, 몇 가지 통계 계산에 대해 생각해 봅니다. 통계 계산이 최신 상태이기를 바라지만, 몇 분 정도 늦어진다면 일반적으로 꽤 괜찮습니다.
    • 전자 메일 전송도 마찬가지입니다. 어쨌든 사용자가 메일을 수신/읽기 전에 몇 분이 경과하므로 즉시 전송할 필요가 없습니다.

제 두 번째 요점은, 그런 일들을 당장 할 필요가 없기 때문에...;-)뭐,장는요 ;-) ;-
큐잉 입니다: 하는 은 과 입니다 가 입니다 가 과 하는 .

  • 웹 응용프로그램은 "작업관리 목록"에 항목을 저장합니다.
  • 그리고 그 "할 일 목록"은 cronjob을 통해 자주 실행되는 배치에 의해 대기열이 해제됩니다.

그리고 다른 조작들에 대해서는 X분마다 한번씩 실행하기를 원할 뿐입니다. 그리고 여기서도 크론잡이 완벽한 도구입니다.

웹 서버를 확장한다고 해서 멀티코어 CPU에 액세스할 때 MySQL이 1인치도 물러서지는 않을 것입니다. 왜 그럴까요?먼저 MySQL의 두 가지 주요 스토리지 엔진을 살펴봅니다.

마이아이샘

이 스토리지 엔진은 여러 코어에 액세스하지 않습니다.그런 적도 없고 앞으로도 없을 것입니다.INSERT, UPDATE, DELETE 각각에 대해 전체 테이블 잠금을 수행합니다.MyISAM을 사용하여 여러 웹 서버에서 쿼리를 전송하면 병목 현상이 발생합니다.

이노DB

MySQL 5.1.38 이전에는 이 스토리지 엔진이 하나의 CPU에만 액세스했습니다. 코어가 MySQL의 다양한 인스턴스를 처리하도록 하려면 하나의 머신에서 MySQL을 여러실행해야 하는 등 이상한 작업을 수행해야 했습니다.그런 다음 여러 인스턴스 간에 웹 서버의 DB 연결 로드 밸런싱을 수행합니다.그것은 오래된 학교(특히 MySQL 5.1.38 이전 버전의 MySQL을 사용하는 경우)입니다.

MySQL 5.1.38부터는 새 InnoDB Plugin을 설치합니다.InnoDB가 여러 CPU에 액세스할 수 있도록 조정해야 하는 기능이 있습니다.DBA Stack Exchange에 이에 대해 적었습니다.

MySQL 5.5/5.6 및 Percona Server에서도 이러한 새로운 기능을 완벽하게 사용할 수 있습니다.

주의 사항

사용자 지정 CMS에서 FULLTEXT 인덱싱/검색을 사용하는 경우 InnoDB에서 FULLTEXT 인덱싱/검색을 지원하므로 MySQL 5.6으로 업그레이드해야 합니다.

MySQL 5.6에 설치한다고 해서 CPU가 자동으로 실행되지는 않습니다.이전 버전의 MySQL이 새 버전보다 먼저 실행되고 더 빨리 실행될 수 있으므로 이를 조정해야 합니다.

이것은 여러분이 찾고 있는 질문에 대한 답이 아닐 수도 있지만, 여러분이 찾고자 하는 해결책은 스레드화를 다룹니다.멀티코어 프로그래밍을 위해서는 쓰레드가 필요하며, PHP에서는 쓰레드가 구현되지 않습니다.

그러나 어떤 의미에서는 운영 체제의 멀티태스킹 능력에 의존하여 PHP의 스레드를 위조할 수도 있습니다.당신이 필요로 하는 것을 달성하기 위한 전략을 개발하기 위해 PHP의 멀티스레딩 전략에 대한 간략한 개요를 제안합니다.

데드 링크:PHP의 멀티스레딩 전략

여러분이 생각할 때 그냥 알려주는 것: "가난한 PHP는 멀티스레딩이 없습니다."

파이썬도 진짜 멀티스레딩이 없어요노드도 그렇지 않습니다.JS는 멀티스레딩을 지원합니다.자바는 일종의 멀티스레딩을 가지고 있지만, 심지어 거기에서도 어떤 코드는 전체 기계를 가짜로 멈추게 합니다.

하지만: 단 하나의 무거운 프로그래밍을 하지 않는 한, 그것은 무관합니다.많은 요청이 페이지를 강타하고 각 요청이 고유한 단일 스레드를 사용하여 자체 프로세스를 생성하므로 모든 코어가 사용됩니다.

언급URL : https://stackoverflow.com/questions/2267345/how-do-you-make-good-use-of-multicore-cpus-in-your-php-mysql-applications

반응형