동시성 IO 문제는 최초의 동기 차단 직접 Fork 프로세스부터 작업자 프로세스 풀/스레드 풀, 현재 비동기 IO 및 코루틴에 이르기까지 항상 서버 측 프로그래밍의 기술적인 문제였습니다. PHP 프로그래머는 강력하기 때문에
LAMP 프레임워크는 이러한 기본 측면에 대한 지식이 거의 없습니다. 이 기사의 목적은 동시 IO 프로그래밍에 대한 PHP의 다양한 시도를 자세히 소개하고 마지막으로 동시 IO 문제를 간단하고 이해하기 쉽게 종합적으로 분석하는 Swoole의 사용을 소개하는 것입니다. 자귀.
최초의 서버측 프로그램은 동시성 문제를 해결했습니다IO . 프로세스 모델은 가장 먼저 등장했으며 프로세스 개념은 Unix 시스템이 탄생한 이후부터 존재해 왔습니다. 최초의 서버 측 프로그램은 일반적으로 Accept 각 클라이언트 연결에 대해 프로세스가 생성되고, 하위 프로세스는 루프에 들어가 동기식 및 차단 방식으로 클라이언트 연결과 상호 작용하여 데이터를 보내고 받습니다. 데이터 처리.
멀티 스레딩 모드는 나중에 등장했습니다. 스레드는 프로세스보다 가볍고 스레드 간에 메모리 스택을 공유하므로 서로 다른 스레드 간의 상호 작용을 구현하기가 매우 쉽습니다. 예를 들어, 채팅방과 같은 프로그램에서 클라이언트 연결은 서로 상호 작용할 수 있으며 채팅방의 플레이어는 다른 사람에게 메시지를 보낼 수 있습니다. 다중 스레드 모드에서 구현하는 것은 매우 간단하며 스레드의 클라이언트 연결에 직접 데이터를 보낼 수 있습니다. 다중 프로세스 모드에서는 프로세스 간 통신(IPC)이라고 통칭되는 파이프라인, 메시지 큐, 공유 메모리와 같은 복잡한 기술을 사용해야 합니다.
코드 예:
Multi-process/스레드 모델의 프로세스는
socket을 만들고, 서버 포트를 바인딩하고(bind), 포트에서 수신합니다(listen). PHP 중국어에서는 stream_socket_server하나의 함수로 위의 3 단계를 완료할 수 있습니다. 물론 하위 수준의 소켓 확장을 사용하여 별도로 구현할 수도 있습니다.
while 루프에 들어가 accept 작업을 차단하고 클라이언트 연결이 들어올 때까지 기다립니다. 이때 프로그램은 새 클라이언트가 서버에 대한 connect을 시작할 때까지 절전 상태에 들어가고 운영 체제는 이 프로세스를 깨울 것입니다. accept 함수는 클라이언트에 연결된 socket
fork( PHP: pcntl_fork) 하위 프로세스를 생성하려면 pthread_create(php: new Thread)는 하위 스레드를 생성합니다. 아래에 별도로 명시하지 않는 한 프로세스는 프로세스/스레드를 나타내는 데에도 사용됩니다.
하위 프로세스가 성공적으로 생성된 후 while 루프에 들어가 recv(php: fread) 호출을 통해 클라이언트가 서버로 데이터를 보내기를 기다립니다. 데이터를 받은 후 서버 프로그램은 이를 처리한 다음 send(php: fwrite)가 클라이언트에 응답을 보냅니다. 긴 연결 서비스는 클라이언트와 계속 상호 작용하는 반면, 짧은 연결 서비스는 일반적으로 응답을 받은 후 닫힙니다. 클라이언트 연결이 닫히면 하위 프로세스가 종료되고 모든 리소스가 삭제됩니다. 기본 프로세스는 이 하위 프로세스를 재활용합니다.
이 모델의 가장 큰 문제는
스레드 생성 및 삭제 프로세스가 매우 비싸다는 것입니다. 따라서 위 모델은 사용량이 많은 서버 프로그램에는 적용할 수 없습니다. 해당 개선된 버전은 이 문제를 해결합니다. 이것은 고전적인 리더-팔로워 모델입니다. 코드 예:
프로그램이 시작된 후
N
프로세스를 생성하는 것이 특징입니다. 각 하위 프로세스는 Accept에 진입하고 새로운 연결이 들어올 때까지 기다립니다. 클라이언트가 서버에 연결되면 하위 프로세스 중 하나가 활성화되어 클라이언트 요청 처리를 시작하고 더 이상 새로운 TCP 연결을 허용하지 않습니다. 이 연결이 닫히면 하위 프로세스가 해제되고 Accept 에 다시 들어가 새 연결 처리에 참여합니다. 이 모델의 장점은 추가 소비 없이 프로세스를 완전히 재사용할 수 있고 성능이 매우 좋다는 것입니다. Apache , PHP-FPM과 같은 많은 일반 서버 프로그램이 이 모델을 기반으로 합니다. 다중 프로세스 모델에도 몇 가지 단점이 있습니다. 이 모델은 동시성 문제를 해결하기 위해 프로세스 수에 크게 의존합니다. 하나의 클라이언트 연결에는 하나의 프로세스가 필요합니다. 동시 처리 기능에 따라 달라집니다. 운영 체제는 생성할 수 있는 프로세스 수에 제한이 있습니다. 많은 수의 프로세스를 시작하면 추가적인 프로세스 스케줄링 소비가 발생합니다. 수백 개의 프로세스가 있는 경우 프로세스 컨텍스트 전환 스케줄링 소비는 CPU의 1% 미만을 차지할 수 있으며 수천 또는 수만 개의 프로세스가 시작되면 무시할 수 있습니다. 소비가 급증할 것이다. 예약 소비는 CPU 또는 심지어 100%의 수십 퍼센트를 차지할 수 있습니다. IM)과 같이 서버가 수만 또는 심지어 수십만 또는 수백만을 유지해야 하는 다중 프로세스 모델로 해결할 수 없는 일부 시나리오도 있습니다. 동시에 연결 수가 많은 경우(클래식 C10K 문제) 다중 프로세스 모델로는 충분하지 않습니다. 다중 프로세스 모델의 약점이기도 한 또 다른 시나리오가 있습니다. 일반적으로 하나의 요청이 100ms, 100 프로세스를 소비하는 경우 Web서버가 100 프로세스를 시작합니다. 1000qps을 제공할 수 있습니다. 처리 능력의 종류는 여전히 좋습니다. 그러나 요청이 외부 네트워크 Http 인터페이스를 호출해야 하는 경우(예: QQ, Weibo 로그인)에는 시간이 오래 걸리며 한 요청에 10초이 소요됩니다. . 그 하나의 프로세스는 1초 안에 0.1 요청을 처리할 수 있고, 100 프로세스는 10qps만 처리할 수 있습니다. 이렇게 처리능력은 너무 나쁘다. 모든 동시성IO을 하나의 프로세스로 처리할 수 있는 기술이 있나요? 대답은 '예'입니다. 이것이 IO 다중화 기술입니다. 사실은IO 재사용의 역사는 여러 Linux는 오랫동안 프로세스 내에서 1024 연결을 유지할 수 있는 select 시스템 호출을 제공해 왔습니다. 나중에 poll 시스템 호출이 추가되었습니다. poll은 몇 가지 개선 사항을 적용하고 1024 제한 문제를 해결했으며 원하는 수의 연결을 유지할 수 있습니다. 하지만 select/poll의 또 다른 문제는 연결에 이벤트가 있는지 감지하기 위해 루프가 필요하다는 것입니다. 문제가 발생합니다. 서버에 100개의 연결이 있고 단 하나의 연결만 특정 시간에 서버에 데이터를 전송하는 경우 select/poll은 루프를 수행해야 합니다 100 만 번 중 1회만 히트했고 나머지 9910,0009999회은 모두 무효였습니다. 그리고 CPU를 낭비했어요 자원. linux 2.6까지 커널은 무제한의 연결을 유지할 수 있는 새로운 EPOLL 시스템 호출을 제공하며 문의할 필요가 없습니다. 요즘에는 epoll을 기반으로 다양한 동시성 비동기 IO 서버 프로그램이 구현됩니다. 예를 들어 Nginx, 、 얼랭, 고랭. Node.js 와 같은 단일 프로세스 및 단일 스레드 프로그램은 모두 epoll 덕분에 1millionTCP 연결을 유지할 수 있습니다. 기술 . IO클래식 Reactor 모델인 Reactor을 사용하여 비동기 비차단 프로그램을 재사용합니다. 그 자체. 보내고 받은 데이터. socket 핸들의 이벤트 변경 사항을 모니터링할 수 있습니다. Reactor에는 addaddsocket reactor을 들어보세요. 들어보세요
소켓使는 클라이언트를 Socket으로 만들 수도 있고 파이프라인, Eventfd, 신호 등의 수정된 이벤트 모니터링 유형일 수도 있습니다. 읽기 및 쓰기 가능과 같은 유형입니다. 듣기 위해 읽기 쉽고 이해하기 쉽습니다.
Socket accept이 필요함을 의미합니다. 데이터를 수신하기 위한 클라이언트 연결에는 recv이 필요합니다. 쓰기 가능한 이벤트는 이해하기가 조금 더 어렵습니다. SOCKET에는 캐시 영역이 있습니다. 2M 데이터를 클라이언트 연결로 전송하려는 경우 운영 체제는 기본적으로 TCP로 전송될 수 없습니다. 캐싱 영역에는 256K만 있습니다. 한 번에 256K만 보낼 수 있습니다. 캐시가 가득 차면 send는 EAGAIN 오류를 반환합니다. 이때 쓰기 가능한 이벤트를 모니터링해야 합니다. 순수 비동기 프로그래밍에서는 send 작업이 완전히 차단되지 않는지 확인하기 위해 쓰기 가능한 이벤트를 모니터링해야 합니다. del이 reactor callback은 이벤트 발생 후 해당 처리 로직으로, 일반적으로 add/set일 때 공식화됩니다. C 언어는 함수 포인터로 구현되고, JS는 익명 함수를 사용할 수 있고, PHP은 익명 함수, 객체 메서드 배열 및 문자열 함수 이름을 사용할 수 있습니다. Reactor는 실제로 socket 핸들을 작동하는 이벤트 생성기입니다(예: connect/accept) 、보내기/ Recv , close은 callback에서 완료됩니다. 구체적인 코딩은 아래 의사 코드를 참조하세요. Reactor이 모델은 다중 프로세스 및 다중 스레드와 결합하여 비동기 비차단을 달성할 수도 있습니다. IO 멀티코어를 활용하세요. 현재 널리 사용되는 비동기 서버 프로그램은 모두 다음과 같습니다. 예: Nginx: 다중 프로세스 Reactor Nginx+Lua : 멀티- process Reactor+Coroutine Golang: 단일 스레드Reactor+다중 스레드 코루틴 Swoole: 멀티스레드Reactor+Multi-processWorker 코루틴은 실제로 기본 기술의 관점에서 비동기식입니다. IO Reactor 모델에서는 애플리케이션 계층이 자체적으로 작업 스케줄링을 구현하고 Reactor를 사용하여 현재 실행 중인 각 사용자 모드 스레드를 전환하지만 사용자 코드에서는 Reactor의 존재가 전혀 보이지 않습니다. Stream: PHP 커널 socket패키지 제공 Sockets: 기본 Socket용
API 캡슐화 Libevent: libevent 라이브러리 캡슐화 이벤트 : Libevent업데이트됨 고급 기반 캡슐화, 객체 지향 인터페이스, 타이머 및 신호 처리에 대한 지원 제공 pcntl/posix : 여러 프로세스, 신호 및 프로세스 관리 지원 : 멀티스레딩, 스레드 관리 및 잠금 지원 PHP공유 메모리, 세마포어 및 메시지 대기열에 대한 관련 확장도 있습니다 PECL: PHP 확장 라이브러리, 시스템 하위 계층, 데이터 분석, 알고리즘, 드라이버, 과학 컴퓨팅, 그래픽 등 포함 PHP 표준 라이브러리에 없으면 PECL에서 원하는 기능을 찾을 수 있습니다. PHP의 장점: 첫 번째 하나는 간단합니다. PHP 기타 언어는 간단해야 합니다. PHP을 시작하고 싶다면 일주일 안에 시작할 수 있습니다. C++"21Days of Deep LearningC++"이라는 책이 있습니다. 사실 21에서는 학습이 불가능합니다. , 또는 C++이라고 말해보세요. 3-5년 없이는 깊이 익히는 것이 불가능합니다. 하지만 PHP은 확실히 7부터 시작할 수 있습니다. 그래서 PHP PHP는 PHP의 공식 표준 라이브러리와 확장 라이브러리에서 서버 프로그래밍에 사용할 수 있는 99%을 제공하기 때문에 매우 강력합니다. PHP의 PECL 확장 라이브러리에는 원하는 모든 기능이 있습니다. ㅋㅋㅋ PHP의 단점: 성능은 상대적으로 좋지 않습니다. 왜냐하면 결국 동적 스크립트이고 집중적인 작업에 적합하지 않기 때문입니다. PHP 프로그램입니다. 사용됩니다
C/C ++로 작성된 PHP 버전은 그보다 100배 더 나쁩니다. 함수 명명 규칙이 좋지 않다는 것은 누구나 알고 있습니다. PHP은 실용성에 더 중점을 두고 있으며 일부 사양이 없습니다. 일부 함수의 이름은 매우 혼란스럽기 때문에 매번 PHP 매뉴얼을 참조해야 합니다. 제공되는 데이터 구조와 함수의 인터페이스 세분성은 상대적으로 거칠습니다. PHP에는 단 하나의 Array 데이터 구조가 있으며 기본 레이어는 HashTable을 기반으로 합니다. PHP의 Array은 Map, Set, 을 설정합니다. Vector, Queue, Stack, Heap 및 기타 데이터 구조 함수. 또한 PHP에는 다른 데이터 구조의 클래스 캡슐화를 제공하는 SPL이 있습니다. 그래서 PHP PHP은 실용적인 응용 프로그램 수준 프로그램, 비즈니스 개발 및 빠른 구현 도구에 더 적합합니다. PHP 다음에는 적합하지 않습니다. 저수준 개발 소프트웨어 는 C/C++, JAVA, Golang 및 기타 정적 컴파일 언어를 PHP에 대한 보완으로 사용합니다. , 결합 정적 및 동적 도움말 포함 IDE자동 완성 및 문법 프롬프트용 도구 Swoole 확장은 순수 PHP을 사용하여 비동기 네트워크 서버 및 클라이언트 프로그램을 완벽하게 구현할 수 있습니다. 하지만 다중 IO과 유사한 스레드를 구현하려면 연결 관리 방법, 데이터 송수신의 원자성을 보장하는 방법, 네트워크를 포함하여 여전히 해야 할 지루한 프로그래밍 작업이 많이 있습니다. 프로토콜 처리. 게다가 프로토콜 처리 부분에서 PHP코드의 성능이 상대적으로 좋지 않아 C 언어와 를 사용하여 새로운 오픈소스 프로젝트Swoole을 시작했습니다. PHP 작업을 완료하기 위해 결합되었습니다. 유연하고 변경 가능한 비즈니스 모듈은 PHP를 사용하여 높은 개발 효율성을 달성합니다. 기본 기본 및 프로토콜 처리 부분은 C 언어로 구현되어 고성능을 보장합니다. 확장된 방식으로 PHP에 로드되어 완전한 네트워크 통신 프레임워크를 제공한 다음 PHP 코드를 사용하여 일부 비즈니스를 작성할 수 있습니다. 해당 모델은 멀티 스레딩Reactor+multi-processWorker을 기반으로 하며 전체 비동기, 반 비동기 및 반 동기를 모두 지원합니다. Accept스레드, 해결 Accept성능 병목 현상 및 엄청난 문제 다중IO스레드, 예 멀티 코어 활용도 향상 완전 비동기식, 반동기식, 반비동기식 2 모드 제공 비동기 모드로 높은 동시성 처리 IO 부분 복잡한 비즈니스 로직 부분적으로 동기화 모드 사용 하단 레이어는 모든 연결 탐색, 서로 데이터 전송, 데이터 패킷 자동 병합 및 분할, 원자 단위로 데이터 전송을 지원합니다. https://github.com/swoole/swoole-src 홈페이지에서 볼 수 있습니다. AsynchronousTCP서버: 여기new swoole_server 객체, 그런 다음 매개변수가 청취에 전달됩니다. HOST 및 PORT을 설정한 다음 새 연결이 올 때 onConnect인 3 콜백 기능을 설정합니다. 에, onReceive 특정 클라이언트로부터 데이터를 받았습니다. onClose특정 클라이언트가 연결을 종료했습니다. 마지막으로 start를 호출하여 서버 프로그램을 시작합니다. swoole하단 레이어는 CPU 수에 따라 Reactor스레드 및 Worker 수를 시작합니다. 프로세스. . 비동기 클라이언트: 클라이언트는 4콜백 이벤트, onConnect이 성공적으로 연결되었다는 점을 제외하면 서버와 유사합니다. 서버. 알았어. 서버에 데이터를 보내려고 합니다. onError서버에 연결하지 못했습니다. onReceive서버가 클라이언트 연결로 데이터를 보냈습니다. onClose연결이 종료되었습니다. 이벤트 콜백을 설정한 후 서버에 대한 connect을 시작합니다. 매개변수는 서버의 IP, PORT 및 시간 초과입니다. 동기화 클라이언트: 동기화 클라이언트는 이벤트 콜백을 설정할 필요가 없으며 Reactor 모니터링이 없으며 직렬을 차단합니다. 다음 단계로 진행하기 전에 IO이 완료될 때까지 기다리세요. 비동기 작업: 비동기 작업 기능은 순수 비동기 Server 프로그램에서 시간이 많이 걸리거나 차단 기능을 실행하는 데 사용됩니다. 기본 구현은 프로세스 풀을 사용합니다. 작업이 완료된 후 onFinish가 실행되고 작업 처리 결과를 프로그램에서 얻을 수 있습니다. 예를 들어 IM을 브로드캐스트해야 하는 경우 비동기 코드로 직접 브로드캐스트하면 다른 이벤트 처리에 영향을 미칠 수 있습니다. 또한 Reactor를 사용하여 socket처럼 파일 핸들을 모니터링할 수 없기 때문에 파일 읽기 및 쓰기는 비동기 작업을 사용하여 구현할 수도 있습니다. 파일 핸들은 항상 읽을 수 있으므로 파일을 직접 읽으면 서버 프로그램이 차단될 수 있습니다. 비동기 작업을 사용하는 것은 매우 좋은 선택입니다. 비동기 밀리초 타이머 이 2인터페이스는 JS과 같은 것을 구현합니다. setInterval, setTimeout 함수 함수는 n 밀리초 간격으로 함수를 구현하거나 n 밀리초 후에 함수를 실행하도록 설정할 수 있습니다. 비동기MySQLClient swoole은 최대 MySQL 연결 수를 설정할 수 있는 MySQL비동기 클라이언트용 내장 연결 풀도 제공합니다. 동시 SQL 요청은 이러한 연결을 반복적으로 생성하는 대신 이러한 연결을 재사용할 수 있으므로 연결 리소스가 고갈되지 않도록 MySQL을 보호합니다. AsyncRedis클라이언트 비동기 WebProgram 논리 프로그램의 핵심은 Redis에서 데이터를 읽은 다음 HTML 페이지를 표시하는 것입니다. ab를 사용하면 스트레스 테스트 성능은 다음과 같습니다. php-fpm에서 동일한 논리로 성능 테스트 결과는 다음과 같습니다. WebSocket Program swoole에는 websocket 서버가 내장되어 있으며, 이를 사용하여 Web 페이지 활성 푸시 기능(예: WebIM)을 구현하는 데 사용할 수 있습니다. . 참고로 사용할 수 있는 오픈 소스 프로젝트가 있습니다. https://github.com/matyhtf/php-webim 비동기 프로그래밍에서는 일반적으로 매우 복잡한 로직을 사용하는 경우 중첩된 콜백 함수를 사용할 수 있습니다. 레이어별로. 코루틴은 이 문제를 해결할 수 있습니다. 코드는 순차적으로 작성될 수 있지만 런타임은 비동기적이고 비차단입니다. Swoole 확장 및 PHP5.5의 Yield/Generator 구문 구현을 기반으로 하는 Tencent 엔지니어는 Golang과 유사합니다. 코루틴, 프로젝트 이름 TSF(Tencent입니다.
Server Framework), 오픈 소스 프로젝트 주소: https://github.com/tencent-php/tsf. 현재 Tencent의 기업 QQ, QQ 공식 계정 프로젝트와 휠 무시 교통 위반 점검 프로젝트에 대규모로 적용되어 있습니다.
. TSF는 사용하기도 매우 간단합니다. 다음 호출은 완전히 직렬입니다. 그러나 실제로는 비동기식 및 비차단 방식으로 실행됩니다. TSF기본 스케줄러가 프로그램 실행을 인계받고 해당 IO이 완료된 후에도 실행을 계속합니다.
IO재사용/이벤트 루프/비동기 비차단
코루틴이란 무엇인가요?
PHP 동시 IO 프로그래밍 실습
PHP관련 확장
PHP 언어의 장점과 단점
위 확장을 기반으로 하는
PHP
의
Swoole의 일부 기능:
Swoole 프로세스 / 스레드 모델:
Swoole프로그램 실행 흐름:
PHP+Swoole 사용 확장 구현 비동기 통신 프로그래밍의
예제 코드는 TCP서버 및 클라이언트
PHP+SwooleCoroutine
위 내용은 PHP 동시 IO 프로그래밍에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!