> 백엔드 개발 > PHP 튜토리얼 > 일괄 처리 홈 PHP에서 일괄 처리 구현

일괄 처리 홈 PHP에서 일괄 처리 구현

WBOY
풀어 주다: 2016-07-29 08:37:03
원래의
943명이 탐색했습니다.

웹 애플리케이션의 기능을 완료하는 데 1~2초 이상 걸리는 경우 어떻게 해야 합니까? 일종의 오프라인 처리 솔루션이 필요합니다. PHP 애플리케이션에서 장기 실행 작업을 오프라인으로 제공하는 여러 가지 방법을 알아보세요.
대형 체인점에는 큰 문제가 있습니다. 매일 모든 매장에서 수천 건의 거래가 발생합니다. 회사 경영진은 이 데이터를 마이닝하고 싶어합니다. 어떤 제품이 잘 팔리나요? 무엇이 나쁜가요? 유기농 제품은 어디에서 잘 팔리나요? 아이스크림 판매는 어떻게 진행되고 있나요?
이 데이터를 캡처하려면 조직은 회사에서 요구하는 보고서 유형을 생성하는 데 더 적합한 데이터 모델에 모든 거래 데이터를 로드해야 합니다. 그러나 이는 시간이 걸리고 체인이 성장함에 따라 하루 분량의 데이터를 처리하는 데 하루 이상이 걸릴 수 있습니다. 그래서 이것은 큰 문제입니다.
이제 웹 애플리케이션에서는 이렇게 많은 데이터를 처리할 필요가 없지만 모든 사이트에서는 고객이 기꺼이 기다리는 것보다 처리하는 데 더 오랜 시간이 걸릴 가능성이 있습니다. 일반적으로 고객이 기꺼이 기다리는 시간은 200밀리초입니다. 이 시간을 초과하면 고객은 프로세스가 "느리다"고 느낄 것입니다.이 수치는 데스크탑 애플리케이션을 기반으로 한 반면, 웹은 우리를 더 인내심 있게 만듭니다. 하지만 무슨 일이 있어도 고객을 몇 초 이상 기다리게 해서는 안 됩니다. 따라서 PHP에서 일괄 작업을 처리하려면 몇 가지 전략을 채택해야 합니다.
cron을 사용한 분산 접근 방식
UNIX® 시스템에서 일괄 처리를 실행하는 핵심 프로그램은 cron 데몬입니다. 데몬은 실행할 명령줄과 실행 빈도를 알려주는 구성 파일을 읽습니다. 그런 다음 데몬은 구성된 대로 이를 실행합니다. 오류가 발생하면 문제 디버깅을 돕기 위해 지정된 이메일 주소로 오류 출력을 보낼 수도 있습니다.
저는 스레딩 기술 사용을 강력히 옹호하는 엔지니어를 알고 있습니다. "스레드! 스레드는 백그라운드 처리를 수행하는 실제 방법입니다. cron 데몬은 오래되었습니다.
그렇게 생각하지 않습니다."
저는 두 가지 방법을 모두 사용해 보았는데, cron에는 "Keep It Simple, Stupid(KISS, simple is beautiful)" 원칙이 있다는 장점이 있다고 생각합니다. 백그라운드 처리를 단순하게 유지합니다. cron은 항상 실행되는 멀티스레드 작업 처리 애플리케이션을 작성하는 대신(메모리 누수가 없음) 간단한 배치 스크립트를 시작합니다. 처리할 작업이 있는지 확인하고 해당 작업을 실행한 후 종료하는 스크립트입니다. 메모리 누수에 대해 걱정할 필요가 없습니다. 스레드가 멈추거나 무한 루프에 걸리는 것에 대해 걱정할 필요도 없습니다.
그럼 크론은 어떻게 작동하나요? 이는 시스템 환경에 따라 다릅니다. 나는 cron의 오래된 간단한 UNIX 명령줄 버전에 대해서만 논의할 것입니다. 시스템 관리자에게 자신의 웹 애플리케이션에서 이를 구현하는 방법을 문의할 수 있습니다.
다음은 매일 밤 11시에 PHP 스크립트를 실행하는 간단한 cron 구성입니다.
0 23 * * * jack /usr/bin/php /users/home/jack/myscript.php
처음 5 필드는 스크립트가 시작되어야 하는 시기를 정의합니다. 그런 다음 이 스크립트를 실행하는 데 사용해야 하는 사용자 이름입니다. 나머지 명령은 실행할 명령줄입니다. 시간 필드는 분, 시간, 일, 월 및 요일입니다. 다음은 몇 가지 예입니다.
명령:
15 * * * * jack /usr/bin/php /users/home/jack/myscript.php
매시간 15분에 스크립트를 실행합니다.
명령:
15,45 * * * * jack /usr/bin/php /users/home/jack/myscript.php
매시간 15분과 45분에 스크립트를 실행합니다.
명령:
*/1 3-23 * * * jack /usr/bin/php /users/home/jack/myscript.php
오전 3시부터 오후 11시까지 매분마다 스크립트를 실행합니다.
명령
30 23 * * 6 jack /usr/bin/php /users/home/jack/myscript.php
매주 토요일 오후 11시 30분(토요일은 6으로 지정)에 스크립트를 실행합니다.
보시다시피 조합 수는 무제한입니다. 필요에 따라 스크립트가 실행되는 시기를 제어할 수 있습니다. 실행할 스크립트를 여러 개 지정하여 일부 스크립트는 1분마다 실행하고 다른 스크립트(예: 백업 스크립트)는 하루에 한 번만 실행할 수 있도록 할 수도 있습니다.
보고된 오류를 보낼 이메일 주소를 지정하려면 다음과 같이 MAILTO 지시문을 사용할 수 있습니다.
MAILTO=jherr@pobox.com
참고: Microsoft® Windows® 사용자의 경우 다음이 있습니다. 효율적인 예약 작업 시스템을 사용하여 명령줄 프로세스(예: PHP 스크립트)를 정기적으로 시작할 수 있습니다.
맨 위로
일괄 처리 아키텍처의 기본
일괄 처리는 매우 간단합니다. 대부분의 경우 두 가지 워크플로 중 하나가 사용됩니다. 첫 번째 워크플로는 보고를 위한 것입니다. 스크립트는 하루에 한 번 실행되고 보고서를 생성하여 사용자 그룹에 보냅니다. 두 번째 워크플로는 일종의 요청에 대한 응답으로 생성된 일괄 작업입니다. 예를 들어 웹 애플리케이션에 로그인하여 시스템에 등록된 모든 사용자에게 새로운 기능에 대해 알려주는 메시지를 보내도록 요청했습니다. 시스템에 10,000명의 사용자가 있으므로 이 작업은 일괄 처리되어야 합니다. PHP는 이러한 작업을 완료하는 데 시간이 걸리므로 브라우저 외부의 작업으로 수행해야 합니다.
두 번째 워크플로에서 웹 애플리케이션은 단순히 정보를 어딘가에 저장하고 배치 애플리케이션이 이를 공유하도록 합니다. 이러한 메시지는 작업의 성격을 지정합니다(예: "시스템의 모든 사람에게 이 전자 메일 보내기").) 일괄 프로그램은 작업을 실행한 다음 작업을 삭제합니다. 또는 처리기가 작업을 완료된 것으로 표시합니다. 어떤 방법을 사용하더라도 작업이 완료된 것으로 인식되어 다시 실행되지 않도록 해야 합니다.
이 기사의 나머지 부분에서는 웹 애플리케이션 프런트엔드와 배치 백엔드 간에 데이터를 공유하는 다양한 방법을 보여줍니다.
맨 위로 가기
메일 대기열
첫 번째 방법은 전용 메일 대기열 시스템을 사용하는 것입니다. 이 모델에서 데이터베이스의 테이블에는 다양한 사용자에게 보내야 하는 이메일 메시지가 포함되어 있습니다. 웹 인터페이스는 mailouts 클래스를 사용하여 이메일을 대기열에 추가합니다. 이메일 처리기는 mailouts 클래스를 사용하여 처리되지 않은 이메일을 검색한 다음 이를 다시 사용하여 대기열에서 처리되지 않은 이메일을 제거합니다.
이 모델에는 먼저 MySQL 스키마가 필요합니다.
목록 1. mailout.sql
DROP TABLE IF EXISTS 메일아웃;CREATE TABLE 메일아웃( id MEDIUMINT NOT NULL AUTO_INCREMENT, from_address TEXT NOT NULL, to_address TEXT NOT NULL, 제목 TEXT NOT NULL, 내용 TEXT NOT NULL, PRIMARY KEY ( id ));
이 모드는 매우 간단합니다. 각 줄에는 보낸 사람과 받는 사람 주소는 물론 이메일 제목과 내용도 포함됩니다.
데이터베이스의 메일아웃 테이블을 처리하는 PHP 메일아웃 클래스입니다.
목록 2. mailouts.php
getMessage()) } public static function delete( $id ) { $db = Mailouts::get_db(); $sth = $db->prepare( 'ID=?'에서 메일아웃 삭제) $db->execute( $sth, $id ) ; true 반환 } 공개 정적 함수 add( $from, $to, $subject, $content ) { $db = Mailouts::get_db() $sth = $db->prepare( 'INSERT INTO 메일아웃 VALUES; ,?,?,?,?)' ); $db->execute( $sth, array( $from, $to, $subject, $content ) } public static function get_all() { $ db = Mailouts::get_db(); $res = $db->query( "SELECT * FROM mailouts" ) $rows = array(); while( $res->fetchInto( $row ) ) { $rows []= $row; } return $rows; }}?>
이 스크립트에는 Pear::DB 데이터베이스 액세스 클래스가 포함되어 있습니다. 그런 다음 add, delete 및 get_all이라는 세 가지 주요 정적 함수가 포함된 mailouts 클래스를 정의합니다. add() 메소드는 이메일을 대기열에 추가합니다. 이 메소드는 프런트엔드에서 사용됩니다. get_all() 메서드는 테이블의 모든 데이터를 반환합니다. delete() 메소드는 이메일을 삭제합니다.
왜 스크립트 끝부분에서 delete_all() 메서드를 호출하지 않는지 궁금하실 수도 있습니다. 이렇게 하지 않는 데는 두 가지 이유가 있습니다. 메시지를 보낸 후 각 메시지를 삭제하면 문제가 발생한 후 스크립트를 다시 실행하더라도 시작 사이에 새 메시지가 추가될 수 있으므로 메시지가 두 번 전송될 가능성은 없습니다. 일괄 작업 정보가 완료됩니다.
다음 단계는 대기열에 항목을 추가하는 간단한 테스트 스크립트를 작성하는 것입니다.
목록 3. mailout_test_add.php

이 예에서는 메일 발송을 추가합니다. 이 메시지는 "테스트 제목"이라는 제목과 이메일을 포함하여 회사의 Molly에게 전송됩니다. 몸 . 명령줄에서 php mailout_test_add.php 스크립트를 실행할 수 있습니다.
이메일을 보내려면 다른 스크립트가 필요하며 이 스크립트는 작업 핸들러 역할을 합니다.
목록 4. mailout_send.php

이 스크립트는 get_all() 메소드를 사용하여 모든 이메일 메시지를 검색한 다음 PHP의 mail() 메소드를 사용하여 메시지를 하나씩 보냅니다. . 성공적인 이메일이 전송될 때마다 delete() 메서드가 호출되어 대기열에서 해당 레코드를 삭제합니다.
cron 데몬을 사용하여 이 스크립트를 주기적으로 실행하세요. 이 스크립트를 실행하는 빈도는 애플리케이션의 요구 사항에 따라 다릅니다.
참고: PEAR(PHP Extension and Application Repository) 저장소에는 무료로 다운로드할 수 있는 우수한 메일 ​​대기열 시스템 구현이 포함되어 있습니다.
맨 위로
더 일반적인 접근 방식
이메일 전송을 위한 솔루션은 훌륭하지만 더 일반적인 접근 방식이 있습니까? 처리가 완료될 때까지 브라우저에서 기다리지 않고도 이메일을 보내고, 보고서를 생성하고, 기타 시간이 많이 소요되는 처리를 수행할 수 있어야 합니다.
이를 위해 PHP가 해석된 언어라는 점을 활용할 수 있습니다. PHP 코드는 데이터베이스의 대기열에 저장되고 나중에 실행될 수 있습니다. 이를 위해서는 두 개의 테이블이 필요합니다(목록 5 참조).
목록 5. generic.sql
DROP TABLE IF EXISTSprocessing_items;CREATE TABLEprocessing_items(ID MEDIUMINT NOT NULL AUTO_INCREMENT, 함수 TEXT NOT NULL, PRIMARY KEY(id));DROP TABLE IF EXIST Sprocessing_args;CREATE TABLEprocessing_args ( id MEDIUMINT NOT NULL AUTO_INCREMENT, item_id MEDIUMINT NOT NULL, key_name TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (id))
첫 번째 테이블processing_items에는 작업 핸들러가 호출하는 함수가 포함되어 있습니다. 두 번째 테이블인processing_args에는 키/값 쌍의 해시 테이블 형식으로 함수에 보낼 인수가 포함되어 있습니다.
메일아웃 테이블과 마찬가지로 이 두 테이블도 ProcessItems라는 PHP 클래스로 래핑됩니다.
清单 6. generic.php
    prepare('processing_args에서 항목 ID=?' );    $db->실행( $sth, $id );    $sth = $db->prepare('processing_items WHERE id=?' )에서 삭제하세요.    $db->실행( $sth, $id );    true를 반환합니다.  }  공개 정적 함수 추가( $function, $args )  {    $db = ProcessingItems::get_db();    $sth = $db->prepare( 'processing_items VALUES에 삽입(null,?)' );    $db->execute( $sth, array( $function ) );    $res = $db->query( "SELECT last_insert_id()" );    $id = null;    while( $res->fetchInto( $row ) ) { $id = $row[0]; }    foreach( $args as $key => $value )    {       $sth = $db->prepare( 'INSERT INTO processing_args  VALUES (null,?,?,?)' );        $db->execute( $sth, array( $id, $key, $value ) );    }    return true;  }  공개 정적 함수 get_all()  {    $db = ProcessingItems::get_db();    $res = $db->query( "SELECT * FROM processing_items" );    $행 = 배열();    while( $res->fetchInto( $row ) )    {        $item = array();        $item['id'] = $row[0];        $item['function'] = $row[1];        $item['args'] = 배열();        $ares = $db->query( "SELECT key_name, 값 FROM   processing_args WHERE item_id=?", $item['id'] );        while( $ares->fetchInto( $arow ) )            $item['args'][ $arow[0] ] = $arow[1];        $행 []= $item;    }    $행을 반환합니다.  }}?> : add () 、 get_all () 和 delete () 。与 mailouts 系统一样 系统一样, 前端使用 add (), 处理引擎使用 get_all () 和 delete ()。
清单7 所示的测试脚本将一个条目添加到处理队列中。
清单 7. generic_test_add.php
      'foo' ) )?>
지금 这个示例中,添加了一个对 printvalue 函数的调用,并将 value 参数设置为 foo。我使用 PHP 命令行解释器运行这个脚本,并将这个方法调用放进队列中。然后使用以下处리脚本运行这个방법。
清单 8. generic_process.php
    
这个脚本不常简单。它获得 get_all() 返回的处理条目,然后使用 call_user_func_array (一个 PHP 内part 函数) 给定的参数动态地这个示例中,调用本地的 printvalue 函数。
이 기능을 시연하기 위해 명령줄에서 어떤 일이 일어나는지 살펴보겠습니다.
% php generic_test_add.php % php generic_process.php 인쇄: foo%
출력은 많지 않지만 Points를 통해 알 수 있습니다. . 이 메커니즘을 통해 모든 PHP 함수의 처리를 연기할 수 있습니다.
이제, PHP 함수 이름과 매개변수를 데이터베이스에 입력하는 것을 좋아하지 않는 경우, 또 다른 접근 방식은 데이터베이스의 "처리 작업 유형" 이름과 실제 PHP 처리 함수 사이에 PHP 코드에 매핑을 설정하는 것입니다. . 이렇게 하면 나중에 PHP 백엔드를 수정하기로 결정한 경우 "처리 작업 유형" 문자열이 일치하는 한 시스템이 계속 작동합니다.
맨 위로
데이터베이스 제거
마지막으로 데이터베이스를 사용하는 대신 디렉터리의 파일을 사용하여 배치 작업을 저장하는 약간 다른 솔루션을 보여줍니다. 여기에 제시된 아이디어는 "데이터베이스를 사용하는 대신 이 방법을 채택하라"고 제안하는 것이 아니라 단지 대체 방법일 뿐이며 채택 여부를 결정하는 것은 귀하의 몫입니다.
분명히 이 솔루션에는 데이터베이스를 사용하지 않으므로 스키마가 없습니다. 따라서 먼저 이전 예제와 유사한 add(), get_all() 및 delete() 메서드를 포함하는 클래스를 작성하세요.
清单 9. batch_by_file.php
     $v )    {       fprintf( $fh, $k.":".$v."n" );    }    fclose( $fh );    true를 반환합니다.  }  공용 정적 함수 get_all()  {    $rows = array();    if (is_dir(BATCH_DIRECTORY)) {        if ($dh = opendir(BATCH_DIRECTORY)) {            while (($file = readdir($dh)) !== false) {              $path = BATCH_DIRECTORY.$file;                if ( is_dir( $path ) == false )               {                  $item = array();                    $item['id'] = $path;                    $fh = fopen( $path, 'r' );                    if ( $fh )                   {                       $item['function'] = trim(fgets( $fh ));                        $item['args'] = 배열();                        while(( $line = fgets( $fh ) ) != null )                      {                       $args = split(':', trim($line) );                            $item['args'][$args[0]] = $args[1];                        }                       $행 []= $item;                        fclose($fh);                    }                }            }Closedir ($ dh);}} $ 행 반환;} & Gt
BatchFiles 클래스에는 add(), get_all() 및 delete()의 세 가지 주요 메서드가 있습니다. 이 클래스는 데이터베이스에 액세스하지 않지만 배치_items 디렉터리의 파일을 읽고 씁니다.
새 배치 항목을 추가하려면 다음 테스트 코드를 사용하세요.
목록 10. Batch_by_file_test_add.php
'foo' ) );?> >한 가지 주의할 점: 클래스 이름(BatchFiles) 외에는 작업이 어떻게 저장되는지에 대한 표시가 실제로 없습니다. 따라서 향후 인터페이스 수정 없이 데이터베이스 형태의 스토리지로 변경이 용이하다.
마지막으로 핸들러 코드입니다.
목록 11. Batch_by_file_processor.php
이 코드는 파일 이름과 클래스 이름이 수정된 것을 제외하면 데이터베이스 버전과 거의 동일합니다.
위로
결론
앞서 언급했듯이 서버는 스레드에 대한 많은 지원을 제공하며 백그라운드 일괄 처리를 수행할 수 있습니다. 어떤 경우에는 작업자 스레드를 사용하여 소규모 작업을 처리하는 것이 확실히 더 쉽습니다. 그러나 배치 작업은 구현, 배포 및 유지 관리가 쉬운 기존 도구(cron, MySQL, 표준 객체 지향 PHP 및 Pear::DB)를 사용하여 PHP 애플리케이션에서 생성할 수도 있습니다.
참고자료
학습
developerWorks 글로벌 사이트에서 이 글의 영문 원문을 참고하실 수 있습니다.
IBM DeveloperWorks PHP 프로젝트 리소스 센터를 읽고 PHP에 대해 자세히 알아보세요.
PHP.net은 PHP 개발자를 위한 훌륭한 리소스입니다.
PEAR Mail_Queue 패키지는 데이터베이스 백엔드를 포함하는 강력한 메일 대기열 구현입니다.
crontab 매뉴얼에는 cron 구성에 대한 자세한 내용이 나와 있지만 이해하기 쉽지 않습니다.
PHP 매뉴얼의 명령줄에서 PHP 사용 섹션은 cron에서 스크립트를 실행하는 방법을 이해하는 데 도움이 될 수 있습니다.
developerWorks 기술 이벤트와 웹캐스트를 계속 지켜봐 주시기 바랍니다.
IBM 오픈 소스 개발자가 최신 기술 개발에 대해 배울 수 있는 전 세계의 다가오는 컨퍼런스, 전시회, 웹캐스트 및 기타 이벤트에 대해 알아보세요.
developerWorks 오픈 소스 기술 존을 방문하여 오픈 소스 기술로 개발하고 이를 IBM 제품과 함께 사용하는 데 도움이 되는 광범위한 방법 정보, 도구, 프로젝트 업데이트를 확인하세요.
developerWorks 팟캐스트에는 소프트웨어 개발자를 위한 흥미로운 인터뷰와 토론이 많이 포함되어 있습니다.
제품 및 기술 얻기
PEAR::DB가 포함된 PHP 확장 및 애플리케이션 저장소인 PEAR를 확인하세요.
다운로드 또는 DVD로 제공되는 IBM 평가판 소프트웨어를 사용하여 다음 오픈 소스 개발 프로젝트를 개선하세요.
토론
developerWorks PHP 개발자 포럼은 모든 PHP 개발자가 기술적인 문제를 논의할 수 있는 장소를 제공합니다. PHP 스크립트, 함수, 구문, 변수, 디버깅 및 기타 주제에 대해 질문이 있는 경우 여기에서 질문할 수 있습니다.
developerWorks 블로그에 참여하여 개발자Works 커뮤니티에 참여하세요.
저자 소개
Jack D. Herrington은 20년 이상의 업무 경험을 보유한 수석 소프트웨어 엔지니어입니다. 그는 Code Generation in Action, Podcasting Hacks, PHP Hacks 등 세 권의 책과 30개 이상의 기사를 집필했습니다.

위 내용은 Batch Process House의 내용을 포함하여 Batch Process House PHP에서의 일괄 처리 구현을 소개한 내용입니다. PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿