일괄 처리 시 사용된 잠긴 파일을 사용하는 PHP의 배타 처리 정보

18102 단어 PHP
비망록 대신 앞으로의 자신을 향해.
사용하는 버전은 PHP7이지만 5.6 이하도 괜찮을 것 같습니다.아마

STEP1: 파일을 잠그고 배타적으로 제어하는 방법


PHP에서는 일괄 처리를 이용해 데이터 유지보수, 업데이트 등 일차와 월차 처리를 하는 업무가 많지만, 그때는 어떻게 배타적으로 다른 일괄 처리와 자체 일괄 처리의 다중 시작과 인위적인 방문 등을 해야 할지 생각한다.가장 정통적인 방법은 다음과 같은 파일을 잠그는 방법입니까?
  • 일괄 처리 시작 시 잠긴 파일이 있는지 확인
  • 가 없으면 잠금 파일을 만들어 일괄 처리에 들어갑니다
  • 배치 실행 종료 시 잠긴 파일 삭제
  • 인코딩을 하고 싶으면 다음과 같은 느낌이 들 거예요.간단해.제작, 삭제, 확인만 가능합니다.
    
    class exclusiveControl {
    
        /**
         * ロックファイルを作成する
         * @param unknown $bid
         */
        public function make_lock_file($bid) {
            $dir = __DIR__;
            $fpath = $dir.'/tmp/'.$bid.'.lock';
            touch($fpath);
        }
    
    
        /**
         * ロックファイルを削除する。
         * @param unknown $bid
         */
        public function delete_lock_file($bid) {
            $dir = __DIR__;
            unlink($dir.'/tmp/'.$bid.'.lock');
        }
    
    
        /**
         * ロックファイルの存在確認
         * @param unknown $bid
         * @return true = 処理続行、false = エラーを出して中断
         */
        public function check_lock_file($bid) {
            $dir = __DIR__;
            //ファイルパス指定
            $fpath = $dir.'/tmp/'.$bid.'.lock';
    
            //ファイルチェック
            if (file_exists($fpath)) {
                return false;
            }
            return true;
        }
    }
    
    만약 대량만 있다면 록 파일도 적당한 이름을 사용할 수 있다.그러나 여러 개의 로트가 동시에 이동하는 경우 어떤 로트가 작성된 잠금 파일인지 구분해야 한다.
    한 번은 "한 번만 움직여도 다른 건 가짜야!"그렇다면 간단하지만 횟수마다 배타적인 상황을 대비해 파일을 중복 잠그지 말아야 한다.
    따라서 차례별 고유 ID(이번에는 이것을 $bid라고 부른다)와 명칭 등이 잠긴 파일의 이름에 붙는다.이렇게 하면 어느 쪽이 작동하는지 자원 관리자와 컨트롤러에서 확인하면 알 수 있다.

    STEP2: 시스템 및 프로세스의 예기치 않은 종료에 대응


    잠금 파일을 사용하여 배타 제어를 할 때 문제가 발생할 수 있는 곳이 바로 이것이다.일괄 처리는 어떤 이유(잠금 파일 삭제 방법의 문법적 오류, 기계의 시스템 자체의 끝 등...) 때문에 강제로 종료된 경우 잠금 파일만 남았고, 다음 부팅 때는 "정확하게 시작하려고 했는데 배열에 의해 영향을 받았다!"이런 구상.폴더를 하나하나 참조하여 파일을 삭제···사용자가 끝까지 하도록 하는 것은 너무 무책임한 짓이다.
    나는 방법이 여러 가지가 있다고 생각한다. 이번에 채택한 것은
    배치 작업 시 프로세스 ID의 일관성 확인
    이런 방법.
    강제 종료 후 남은 잠금 파일은 스팸 파일일 뿐이므로 삭제해야 합니다.쓰레기인지 아닌지를 식별하기 위해 일괄 처리를 시작할 때의 PHP.exe의 프로세스 ID가 잠긴 파일을 만들 때의 프로세스 ID와 일치하는지 확인합니다.
    쉽게 프로세스 ID는 프로세스가 시작된 후 종료되기 전까지 변경되지 않으므로 강제 종료에 대해 상당히 높은 정밀도로 대응할 수 있습니다.
    위의 잠금 파일 시리즈에 다음 단계를 추가합니다.
  • 배치 시작 시 잠긴 파일 확인
  • 잠긴 파일이 있으면 잠긴 파일의 처리 ID, PHP를 읽습니다.exe의 프로세스 ID와 일치하는지 확인하십시오.없으면 일괄 처리
  • 정합성이 보장되는 경우 현재 이동한 일괄이므로 실행하지 않고 오류
  • 를 반환합니다.
  • 일치하지 않으면 이 잠금 파일은 이상하게 끝난 잔해이기 때문에 삭제하고 대량 처리에 들어갑니다
  • 잠금 파일 생성 및 대량 처리
  • 이때 PHP.exe 쓰기 프로세스 ID
  • 배치 실행 종료 시 잠긴 파일 삭제
  • 흐름도를 만들면 다음과 같은 느낌이 든다.

    이 안건에서는 다양한 정황으로 처리과정 ID를 확인해야 할 다른 부분이 있어 다른 학급에만 해당 처리를 제안했다.
    
    class exclusiveControl {
    
        /**
         * ロックファイルの作成とプロセスIDの書き込み。バッチ実行開始時
         * @param unknown $bid
         */
        public function make_lock_file($bid) {
            $dir = __DIR__;
            $fpath = $dir.'/../tmp/'.$bid.'.lock';
            touch($fpath);
    
            //プロセスIDを取得し、ファイルに書き込む
            $pid = getmypid();
            file_put_contents($fpath, $pid);
        }
    
    
        /**
         * ロックファイルの削除。バッチ終了時
         * @param unknown $bid
         */
        public function delete_lock_file($bid) {
            $dir = __DIR__;
            unlink($dir.'/../tmp/'.$bid.'.lock');
        }
    
    
        /**
         * ロックファイルの存在確認、およびプロセスIDに基づく確認
         * @param unknown $bid
         * @return true = 処理続行、false = エラーを出して中断
         */
        public function check_lock_file($bid) {
            $dir = __DIR__;
            //ファイルパス指定
            $fpath = $dir.'/../tmp/'.$bid.'.lock';
    
            //ファイルチェック→プロセスIDチェック
            if (file_exists($fpath)) {
                $pid = file_get_contents($fpath);
                //引数のプロセスIDがphpプロセスのIDと一致するか確認
                if (!Process::check_pid($pid)){
                    //不一致だったら削除して処理続行
                    self::delete_lock_file($bid);
                    return true;
                } else {
                    //一致してたら排他する
                    return false;
                }
            }
            return true;
        }
    }
    
    
    class Process{
    
    
        /**
         * 引数のプロセスIDがphp.exeによるものかどうかチェックする。
         * @param unknown $pid
         * @return 引数と現実行分のプロセスIDが一致 = false
         */
        public function check_pid ($pid) {
            if ($pid === '') {
                return true;
            }
    
            $imagename = "php.exe";
            $tasklist = `tasklist /nh`;
    
            if (preg_match_all('/(.*?)\s+(\d+).*[^\n]?/', $tasklist, $match)) {
                //preg_matchの結果からphpのプロセスを検索し、
                //見つかったらそのプロセスIDを引数のプロセスIDと比較
                foreach ($match[1] as $key => $value) {
                    if($value == $imagename){
                        $active_pid = $match[2][$key];
                        if($active_pid == $pid){
                            return false;
                        }
                    } else {
                        continue;
                    }
                }
                return true;
            }
            return true;
        }
    }
    
    
    getmypid()는 php의 현재 프로세스 ID를 얻는 함수입니다.이 잠금 파일을 작성한 쓰기를 통해 시작할 때 PHP의 프로세스 ID는 일괄 처리가 끝날 때까지 데이터로 저장됩니다.
    "간단하게 말하면 php의 프로세스 ID를 본다면, 어디에서 볼까요?"그러면 그때는tasklist를 사용합니다.
    (참조 → http://wa3.i-3-i.info/word12514.html
    이것을 사용하면 현재 사용 중인 작업 목록을 얻을 수 있습니다.
    상기 조건으로tasklist를 검색하면 저장된 $match가 배열되어 다음과 같은 느낌으로 들어갑니다.사실 실행 중인 프로그램은 더 많이 표시되지만, 여기서는 생략됩니다.
    
    $match[0] //タスク一覧的な
    Array
    (
        [0] => System Idle Process              0 Services                   0     24 K
        [1] => System                           4 Services                   0     15,680 K
        [2] => smss.exe                       356 Services                   0     1,416 K
        [3] => csrss.exe                      504 Services                   0     7,016 K
    )
    
    $match[1] //プロセスの名前
    Array
    (
        [0] => System Idle Process
        [1] => System
        [2] => smss.exe
        [3] => csrss.exe 
      ・
      ・
      ・
      [10] => php.exe
    )
    
    $match[2] //プロセスID(数値はあくまでも例です)
    Array
    (
        [0] => 0
        [1] => 4
        [2] => 356
        [3] => 504
      ・
      ・
      ・
      [10] => 1840 //ほしいやつ
    )
    
    $match[1]$match[2] 번호가 연관
    예를 들어 위에서 말한 바와 같이 php.exe$match[1][10]에 들어가면 php의 처리 ID는 $match[2][10]의 값이다.
    이것이야말로 이번에 검사해야 할 과정 ID다.
    그리고 그것을 잠금 파일에 적힌 처리 ID와 비교하면 그 횟수가 움직이는지 알 수 있다.결과에 따라 배타성 여부를 결정하면 된다.

    끝말


    PHP의 배타적 제어 기법으로 이번 파일 잠금뿐만 아니라 공식적으로 준비한 flock 함수,semafor 등 다양한 방법도 있지만, 각자 길고 짧은 것 같아서 주류는 없다(자신만 모를 수도 있다).
    문서의 배타성을 잠그는 방법을 사용하면 위와 같이 강제 종료 등 과정에서 취약한 부분은 경원되기 쉬우나 이번처럼 참조 처리를 추가하면 배타적 처리의 정밀도가 현저히 높아진다처리 속도에 변화가 거의 없어 장점이라고 할 수 있다.어느 정도 이유만 있으면 간단히 쓸 수 있기 때문에 PHP를 처음 만났는데도 잘 모르는 사람도 쉽게 쓸 수 있다고 느낄 수 있다.
    그러나 이것은 어떤 방법을 써도 말할 수 있다
    대부분의 경우 일괄 처리는 뒷면에서 실행되기 때문에 일괄 처리 실행 과정에서 화면에서도 일괄 처리로 실행되는submit 단추를 누르지 않거나 시작 중인 일괄 처리를 검사할 수 없거나 UI에서 이러한 방법이 없어서는 안 된다는 것을 알 수 있다.일지를 하나하나 보는 것이 불친절하지 않은가.(특히 win 환경은...)
    그리고 물론 이것은 완전무결한 것이 아니기 때문에 나도 다른 수법을 잘 배우고 싶다.또한, 저도 PHP를 처음 접한 지 1년도 안 됐는데, "여기 맛없으니까 이렇게 하는 게 좋을 것 같아요"라는 말이 있으면 꼭 알려주세요.끝.

    좋은 웹페이지 즐겨찾기