source

PHP에서 스레드 세이프 또는 비스레드 세이프란 무엇입니까?

goodcode 2022. 9. 18. 21:33
반응형

PHP에서 스레드 세이프 또는 비스레드 세이프란 무엇입니까?

비스레드나 스레드 세이프 같은 PHP용 바이너리가 다른 것을 보았습니다.

이것은 무엇을 의미합니까?

이 패키지의 차이점은 무엇입니까?

동시성 접근에 대한 필요한 배경:

Web 서버 마다, 착신 HTTP 요구를 병렬로 처리하는 방법이 다릅니다.매우 일반적인 방법은 스레드를 사용하는 것입니다. 즉, 웹 서버는 수신 요청마다 하나의 스레드를 작성/전용합니다.Apache HTTP 웹 서버는 요청을 처리하기 위해 여러 모델을 지원하며, 그 중 하나(워커 MPM이라고 함)는 스레드를 사용합니다.그러나 프로세스를 사용하는 프리포크 MPM이라는 다른 동시성 모델을 지원합니다.즉, 웹 서버는 각 요청에 대해 단일 프로세스를 작성/전용합니다.

또한 완전히 다른 동시성 모델(비동기 소켓과 I/O 사용)도 있습니다.또, 2개 또는 3개의 모델을 혼재시키는 모델도 있습니다.이 질문에 답변하기 위해 위의 두 가지 모델과 Apache HTTP 서버를 예로 들어 보겠습니다.

PHP가 웹 서버와 "통합"하는 방법에 대한 필요한 배경:

PHP 자체는 실제 HTTP 요청에 응답하지 않습니다. 이것은 웹 서버의 작업입니다.따라서 처리를 위해 요청을 PHP로 전송하도록 웹 서버를 구성하고 결과를 받아 사용자에게 보냅니다.웹 서버와 PHP를 연결하는 방법은 여러 가지가 있습니다.Apache HTTP 서버의 경우 가장 많이 사용되는 것은 "mod_php"입니다.이 모듈은 실제로는 PHP 자체이지만 웹 서버용 모듈로 컴파일되어 있기 때문에 그 안에 바로 로드됩니다.

PHP를 Apache 및 기타 웹 서버와 연결하는 다른 방법이 있지만 mod_php가 가장 인기 있는 방법이며 질문에 대한 답변에도 도움이 됩니다.

호스팅 회사와 GNU/Linux Distros는 우리를 위해 준비된 모든 것을 제공하기 때문에 이전에는 이러한 세부 사항을 이해할 필요가 없었을 것입니다.

자, 이제 질문합시다!

mod_php를 사용하면 PHP가 Apache에 바로 로드되기 때문에 Apache가 Worker MPM(즉 스레드 사용)을 사용하여 동시 처리를 하려면 PHP가 동일한 멀티 스레드 환경에서 동작할 수 있어야 합니다.즉, PHP가 Apache와 올바르게 공놀이를 하기 위해서는 스레드 안전해야 합니다.

이 시점에서, 「OK, 멀티 스레드 Web 서버를 사용하고 있고, 거기에 PHP를 직접 짜넣으려면, 스레드 세이프 버전의 PHP를 사용할 필요가 있다」라고 생각할 필요가 있습니다.그리고 이것이 올바른 생각일 것이다.그러나 실제로 PHP의 스레드 안전성에 대해서는 매우 논란이 되고 있습니다.정말 무슨 일을 하는지 아는 곳이야

최종 노트

혹시 모르니까, 만약 선택사항이 있다면 멀티 스레드 환경에서는 PHP를 사용하지 않는 이 좋을 것 같습니다.

Unix 기반 환경만 언급하면 다행스럽게도 PHP를 Apache 웹 서버와 함께 사용하는 경우만 생각하면 됩니다.이 경우 Apache의 프리포크 MPM(스레드를 사용하지 않기 때문에 PHP 스레드 안전은 중요하지 않습니다)과 모든 GNU/Linux 배포에 대해 알고 있습니다.이 결정은 Apache + PHP를 패키지 시스템을 통해 설치할 때 선택할 필요가 없습니다.만약 당신이 nginx나 lighttpd와 같은 다른 웹 서버를 사용한다면, 당신은 어쨌든 PHP를 거기에 포함시킬 수 있는 옵션은 없을 것입니다.Fast CGI 또는 이와 동등한 것을 사용하는 것을 검토하게 될 것입니다.이것은, PHP가 Web 서버 외부에 있는 경우, 예를 들면, 복수의 PHP 프로세스를 사용해 요구에 응답하는 경우에 사용됩니다.패스트 CGI그런 경우에는 나사산 안전도 문제가 되지 않습니다.웹 사이트가 어떤 버전을 사용하고 있는지 확인하려면 다음을 포함하는 파일을 넣으십시오.<?php phpinfo(); ?>를 검색해 주세요.Server API응모하는 것 같아요. 이건 마치CGI/FastCGI또는Apache 2.0 Handler.

PHP의 명령줄 버전도 살펴보면 스레드의 안전성은 중요하지 않습니다.

마지막으로 스레드 세이프가 중요하지 않은 경우 스레드 세이프와 비스레드 세이프 중 어느 버전을 사용해야 합니까?솔직히, 나는 과학적인 답을 가지고 있지 않아!하지만 스레드 세이프가 아닌 버전이 더 빠르거나 버그가 적거나 그렇지 않으면 스레드 세이프 버전만 제공하고 선택권은 주지 않았을 것입니다.

는 항상 nginx를 사용하거나 명령줄에서 PHP를 실행하기 때문에 항상 스레드 이외의 세이프 버전을 선택합니다.

CGI 바이너리, 명령줄 인터페이스 또는 단일 스레드만 사용되는 기타 환경으로 PHP를 설치하는 경우 스레드 이외의 세이프 버전을 사용해야 합니다.

스레드 세이프 버전은 작업자 MPM(멀티 프로세싱 모델) 또는 여러 PHP 스레드가 동시에 실행되는 다른 환경에서 PHP를 Apache 모듈로 설치하는 경우 사용해야 합니다.간단히 말해서 PHP의 CGI/Fast CGI 빌드는 스레드 세이프가 필요하지 않습니다.

modphp를 갖춘 Apache MPM 프리포크를 사용하는 이유는 구성 및 설치가 용이하기 때문입니다.성능 면에서는 상당히 비효율적입니다.Fast CGI/PHP-FPM을 사용하는 것이 좋습니다.그러면 훨씬 더 빠른 MPM Worker를 사용할 수 있습니다.전체 PHP는 스레드되지 않은 상태로 유지되지만 Apache는 스레드화된 상태로 제공됩니다(필요한 대로).

그래서 기본적으로 아래에서 위로

리눅스

Apache + MPM 워커 + ModFast CGI (FCGI 아님)| (또는)| Cherokee | (또는)| Nginx

PHP-FPM + APC

ModFCGI는 PHP-FPM 또는 외부 FastCGI 응용 프로그램을 올바르게 지원하지 않습니다.비프로세스 관리 Fast CGI 스크립트만 지원합니다.PHP-FPM은 PHP Fast CGI 프로세스 매니저입니다.

PHP 설명서에 따르면

PHP를 다운로드할 때 스레드 안전이란 무엇입니까?

스레드 안전은 Windows의 Apache 2와 같은 멀티스레드 웹 서버 컨텍스트에서 바이너리가 작동할 수 있음을 의미합니다.스레드 안전은 데이터가 다른 스레드와 충돌하지 않도록 각 스레드에 로컬 저장소 복사본을 만드는 방식으로 작동합니다.

그럼 뭘 골라야 하죠?CGI 바이너리로 PHP를 실행하도록 선택할 경우, 요청 시 바이너리가 호출되기 때문에 스레드 안전이 필요하지 않습니다.IIS5 및 IIS6과 같은 멀티스레드 웹 서버의 경우 PHP 스레드 버전을 사용해야 합니다.

다음 라이브러리는 스레드 세이프가 아닙니다.멀티 스레드 환경에서는 사용하지 않는 것이 좋습니다.

  • SNMP(유닉스)
  • mSQL(유닉스)
  • IMAP(윈/유닉스)
  • Sybase-CT(Linux, libc5)

다른 답변은 SAPI 구현을 다루며, 이는 관련이 있지만 스레드 세이프 배포와 스레드 세이프 배포의 차이를 묻는 질문입니다.

먼저 PHP는 *NIX의 경우 libphp.so, Windows의 경우 php.http와 같이 임베디드 가능한 라이브러리로 컴파일됩니다.이 라이브러리는 모든 C/CPP 응용 프로그램에 내장할 수 있지만 주로 웹 서버에서 사용됩니다.핵심 PHP는 모듈 초기화 단계와 요청 초기화 단계 두 가지 주요 단계로 시작됩니다.모듈은 PHP 코어 및 모든 확장을 초기화합니다. 여기서 요청은 PHP 사용자 공간을 초기화합니다. 기본 사용자 공간 기능뿐만 아니라 PHP 코드 자체도 마찬가지입니다.

PHP 라이브러리는 모듈 단계를 한 번만 호출하면 되지만 요청 단계는 각 HTTP 요청에 대해 다시 초기화해야 합니다.CLI는 mod_php ext와 같은 라이브러리에 링크하지만 HTTP 요구 처리에서는 사용할 수 없는 경우에도 내부적으로 이러한 단계를 거쳐야 합니다.또한 PHP는 말 그대로 HTTP 요청을 처리하기 위해 설계된 것이 아니라 CGI 이벤트를 처리하기 위해 설계되었습니다.이것은 php-cgi뿐만 아니라 php-fpm, mod_php, CLI, 심지어 매우 희귀한 PHP 데스크톱 애플리케이션을 포함한 모든 SAPI/애플리케이션입니다.

libphp에 링크하는 웹 서버(또는 일반적으로 SAPI)는 다음 4가지 패턴 중 하나를 따르는 경향이 있습니다.

  • 요청별로 완전히 새로운 PHP 인스턴스를 만듭니다(이전 CGI 패턴, 일반적이지 않으며 권장되지 않음).
  • 하나의 PHP 인스턴스를 생성하지만 별도의 분기된 하위 프로세스에서 두 초기화 단계(함께)를 거칩니다.
  • 하나의 PHP 인스턴스를 만들고 부모 프로세스 사전 포크로 모듈 초기화를 한 번 수행한 후 HTTP 요청별로 개별 요청 단계 사후 포크를 수행합니다.

예 2 및 3에서는 일반적으로 각 요청 후에 자식 프로세스가 종료됩니다.예 2에서는 각 요청의 마지막에 자식 프로세스를 종료해야 합니다.

네 번째 예는 스레드 구현에 관한 것입니다.

  • module init은 메인 스레드에서 한 번 호출한 후 다른 스레드 내에서 request init을 호출합니다.

스레드화된 경우, 요구 처리 스레드는 루프 내에서 실행되는 스레드 풀을 사용하는 경향이 있으며, 각 스레드는 처음에 요구 단계를 초기화하고 마지막에 요구 단계를 파괴하는 것보다 더 적합합니다.

스레드 구현이 libphp를 어떻게 사용하는지에 관계없이 모듈 단계가 하나의 스레드로 초기화되고 요청 단계가 다른 스레드(PHP가 설계된 경우)로 호출되면 PHP 코어 내에서뿐만 아니라 모든 네이티브 PHP 확장 내에서 간단한 동기화가 필요합니다.이 시점에서 이것은 단순히 "요청"의 문제가 아니라 PHP 사용자 공간으로 다른 스레드에 존재하는 PHP 코어(또는 PHP 확장) 내의 모든 리소스 형식에 의존하는 PHP OPCODE에 따라 호출되는 동기화입니다.

This places a huge demand on synchronization within thread-safe PHP distributions, which is why PHP tends to follow a "share nothing" rule which helps minimize the impact, but there is no such thing as truly "sharing nothing" in this pattern, unless each thread contains a completely separate PHP context, where the module phase and request phase is all done within the same thread per request which is not suggested or supported. If the context built within the module init phase is in a separate thread as the request init phase there will most definitely be sharing between threads. So the best attempt is made to minimize context within the module init phase that must be shared between threads, but this is not easy and in some cases not possible.

This is especially true in more complicated extensions which have their own requirements of how a their own context must be shared between threads, with openssl being a major culprit of of this example which effectually extends outward to any extension that uses it, whether internal such as PHP stream handlers or external such as sockets, curl, database extensions, etc.

If not obvious at this point, thread-safe vs non thread-safe is not just a matter of how PHP works internally as a “request handler” within an SAPI implementation, but a matter of how PHP works internally as an embedded virtual machine for a programming language.

This is all made possible by the TSRM, or the thread safe resource manager, which is well made and handles a very large amount of synchronization with little perceived overhead, but the overhead is definitely there and will grow not just based on how many requests per second that the server must handle (the deciding factor on how may threads the SAPI requires), but also by how much PHP code is used per request (or per execution). In other words, large bloated frameworks can make a real difference when it comes specifically to TSRM overhead. This isn't to speak of overall PHP performance and resource requirements within thread-safe PHP, but just the additional overhead of TSRM itself within thread-safe PHP.

As such, pre compiled PHP is distributed in two flavors, one built where TSRM is active in libphp (thread-safe) and one where libphp does not use any TSRM features (non thread-safe) and thus does not have the overhead of TSRM.

Also note that the flag used to compile PHP with TSRM (--enable-maintainer-zts or --with-zts in later PHP versions) causes phpize to extend this outward into the compilation of extensions and how they initialize their own libraries (libssl, libzip, libcurl, etc) which will often have their own way of compiling for thread-safe vs non thread-safe implementations, i.e their own synchronization mechanisms outside of TSRM and PHP as a whole. While this not exactly PHP related, in the end will still have effect on PHP performance outside of TSRM (meaning on top of TSRM). As such, PHP extensions (and their dependents, as well as external libraries PHP or extensions link to or otherwise depend on) will often have different attributes in thead-safe PHP distributions.

ReferenceURL : https://stackoverflow.com/questions/1623914/what-is-thread-safe-or-non-thread-safe-in-php

반응형